I have a dll written in C that gets imported into a C# application. All I need from the dll is read out a few values from a hardware device, the actual read process is done by a function in the C dll.
Now I want to read out all the values with this single function and return them to C# in an fast and easy way.
It is a very "general" multi plattform C library that consists of a few functions to handle the communication with said hardware device. I'm looking for a general "C to C#" answer that doesn't have to be specific for my case.
I'm not very experienced in C and C# which makes the task rather complicated (I have no choice about the language).
What would be a smart way to do this in C and how do I declare it in C and how I do import it properly in C#?
Here some Pseudo code to make my question a bit clearer. Thats not valid code but should make clear what I'm after
C:
int [] read(){
int results [3];
results[0] = getPosition();
results[1] = getOrientation();
results[2] = getTouch();
return results;
}
C#
[DllImport("myDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int[] read();
int [] cReturn = new int[3];
cReturn = read();
I tried returning an int array and marshal it in C#, as all my values are int types but it seems returning arrays isn't something you would do in C.
I found quite a few examples for C++ but none of them worked with C as they used C++ specific functions.
You can have your C API set the values into pointers passed as arguments, ie:
void your_c_function(int* value1, int* value2)
{
*value1 = 42;
*value2 = 43;
}
You can then PInvoke this by ref:
[DllImport("your_dll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int your_c_function(ref int value1, ref int value2);
Note that you can also define a struct in C, and pass the entire struct by pointer, if there are many values to set. This will require recreating the struct definition on the managed side, however.
Related
I'm attempting to follow the answer at this question
My struct looks like this in C
typedef struct drive_info_t {
unsigned char drive_alias[32];
} drive_info_t;
My function looks like this in C
unsigned int get_drive_info_list(drive_info_t **list, unsigned int *item_count) {
//fill list in native C
//print out in native C
printf("list.alias - %s\r\n",list[i]->drive_alias);
}
My C# struct looks like this
[StructLayout(LayoutKind.Sequential)]
public struct drive_info_t
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] drive_alias;
}
My C# function declaration looks like this
[DllImport("mydll.dll", EntryPoint = "get_drive_info_list", CallingConvention = CallingConvention.Cdecl)]
public static extern uint GetDriveInfoList(out System.IntPtr ptr_list_info, out System.IntPtr ptr_count);
I'm calling C# function like this
IntPtr ptr_list_info = IntPtr.Zero;
IntPtr ptr_cnt = IntPtr.Zero;
ret = api.GetDriveInfoList(out ptr_list_info, out ptr_cnt);
I'm marshaling the returned pointers like this
nAlloc = ptr_cnt.ToInt32();
int szStruct = Marshal.SizeOf(typeof(api.drive_info_t));
api.drive_info_t[] localStructs = new api.drive_info_t[nAlloc];
for (int i = 0; i < nAlloc; i++)
{
localStructs[i] = (api.drive_info_t)Marshal.PtrToStructure(ptr_list_info, typeof(api.drive_info_t));
ptr_list_info = new IntPtr(ptr_list_info.ToInt32() + (szStruct));
}
Printing the struct alias like this
for (uint i = 0; i < localStructs.Length; i++)
{
Console.WriteLine("list.alias - {0}", System.Text.Encoding.Default.GetString(localStructs[i].drive_alias));
}
Thanks for staying with me..
This is what my output looks like on a console application in C#. You can see the native C dll printing to the console it's values, but my marshaling is messing up somewhere:
======================== C values ============================
list.alias - drv1
list.alias - drv2
list.alias - drv3
list.alias - drv4
======================== C# values ============================
list.alias - drv1
list.alias - o£Q95drv2
list.alias - o£Q95drv3
list.alias - o£Q95drv4
I have no clue where this garbage text and offset is coming from.
I'm responsible for the .Net side, other team members can change the native C as needed if required, but native C changes need to be cross-platform OSX/Windows/Linux.
Thanks in advance.
This is a perfect example of why the types of the arguments do not define the interface. Consider
drive_info_t **list
This could be a pointer to an array of structs. In which case presumably the array is allocated by the callee. Which is why a pointer to array is used as opposed to an array.
Or it could be an array of pointers to struct. Here the array would be allocated by caller and the structs could be allocated by either callee or caller. No way for us to tell.
We can discern that your interface accepts an array of pointers to struct. Look at this code:
list[i]->drive_alias
Quite clearly list is an array of pointers to struct.
This tells you that your code is wrong. You have followed the wrong template because you mis-identified the semantics. Your next step is to return to the documentation for the interface and any example calling code to learn precisely what the semantics are. Who allocates and deallocated what.
Almost certainly you will use IntPtr[] to marshal the array but beyond that it is impossible for us to say what happens. I would guess that the caller allocates the structs but don't rely on guesswork. Read the documentation and example calling code.
Beyond that the second argument should be ref uint or perhaps out uint depending on the semantics of the function. Again, that's something that we cannot work out.
I have the following c#/c code, where I am doing stuff in a C dll. Am using pinvoke/marshal as the black magic that enables me to dynamically allocate/free stuff in the dll, without c# code knowing anything untoward is going on.
In this snippet, you will see that I am using 2 different ways to alloc/use/free an array of doubles. My question is, what does the "MarshalAs(UnmanagedType..." line do, because both incantations (ie, using or not using the MarshalAs statement) work fine? I should add that I have a poor understanding of C, even less understanding of C#, and I understand the whole pinvoke/marshal about as well as I understand supersymmetric quantum mechanics.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class row
{
public int a;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
IntPtr[] b;
IntPtr [] c;
}
// c code
struct row
{
int a;
double *b;
double *c;
}
void fooe(void)
{
row.b[4] = (double *) malloc(54000);
row.c[4] = (double *) malloc(54000);
free(row.b[4]);
free(row.c[4]);
}
This particular use of ByValArray changes everything.
First, let's consider the without ByValArray case. Here the array is marshalled as a pointer to the first element. The matching C struct is
struct row
{
int a;
void* *b; // more likely you would use a typed pointer
void* *c;
}
No for the case where you use ByValArray. Here the array is marshalled inline and the equivalent C struct is:
struct row
{
int a;
void* b[12];
void* *c;
}
These two versions are very different.
I also wonder if you really meant to use IntPtr[] in the C# code. Did you perhaps really mean to write double[]? So, perhaps you actually meant:
[StructLayout(LayoutKind.Sequential)]
public class row
{
public int a;
double[] b;
double[] c;
}
In which case the matching C struct would be:
struct row
{
int a;
double *b;
double *c;
}
I've no idea what is meant by the fooe function, but it makes no sense at all and does not compile. It looks like you are trying to assign a pointer to a double which is quite meaningless.
I am very new to c++ so I might have some mistakes on this side.
So I started with writing simple C++ function that will contain struct as return type:
my c++ struct:
struct a {
int i;
};
my c++ function declaration in library.h file:
extern "C" __declspec(dllexport) struct a retNumber();
my c++ function description in library.cpp file:
struct a retNumber()
{
struct a r = a();
r.i = 22;
return r;
}
So I just want to compile it and then use it in c# code, I am getting following compile errors:
error C2371: 'retNumber' : redefinition; different basic types
error C2526: 'retNumber' : C linkage function cannot return C++ class
error C2556: 'a retNumber(void)' : overloaded function differs only by return type from 'void retNumber(void)'
That's the first part of my question and if you guys will help me to solve it, I will really appreciate it, once it's solved, I am going to declare the same struct in my c# code:
struct a1
{
int i;
}
Then I am going to import my c++ function:
[DllImport("library.dll")]
public static extern a1 retNumber();
Once it's done, I will create GCHandle:
a1 test = retNumber();
GCHandle handle = GCHandle.Alloc(test, GCHandleType.Pinned);
and then I will try to convert my actual result and release memory:
Object temp = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(a1));
handle.Free();
So by this time I should have object that is of type a1 and contains variable i with value 22.
If anyone can please delagate through this process I will greatly appreciate it!
Thank you very much in advance!!!
On the C++ side, you need to wrap everything in extern "C", including the struct:
extern "C" {
struct a {
int i;
};
};
On the C# side, you'll need to specify the calling convention properly:
[DllImport("library.dll", CallingConvention=CallingConvention.Cdecl))]
public static extern a1 retNumber();
Once you do that, there is no need for the Marshal.PtrToStructure call. Just do:
a1 test = retNumber();
Console.WriteLine(a1.i); // Should print 22
I have some problems working with boolean types and marshalling this in a struct back and forth between C# and C. I am very rusty in C but hopefully there's nothing crucially wrong in that part.
As far as I've read/seen, .NET Boolean and C# bool type is 4 bytes long whilst the C type bool is only 1 byte. For memory footprint reasons, I do not which to use the defined BOOL 4 bytes version in the C code.
Here is some simple test code that hopefully will make my questions clear:
C code:
typedef struct
{
double SomeDouble1;
double SomeDouble2;
int SomeInteger;
bool SomeBool1;
bool SomeBool2;
} TestStruct;
extern "C" __declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs);
__declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs)
{
return structs;
}
I call this code in C# using the following definitions:
[StructLayout(LayoutKind.Explicit)]
public struct TestStruct
{
[FieldOffset(0)]
public double SomeDouble1;
[FieldOffset(8)]
public double SomeDouble2;
[FieldOffset(16)]
public int SomeInteger;
[FieldOffset(17), MarshalAs(UnmanagedType.I1)]
public bool SomeBool1;
[FieldOffset(18), MarshalAs(UnmanagedType.I1)]
public bool SomeBool2;
};
[DllImport("Front.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr TestGetBackStruct([MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] TestStruct[] structs);
and here is the actual test function in C#:
[Test]
public void Test_CheckStructParsing()
{
var theStruct = new TestStruct();
theStruct.SomeDouble1 = 1.1;
theStruct.SomeDouble2 = 1.2;
theStruct.SomeInteger = 1;
theStruct.SomeBool1 = true;
theStruct.SomeBool2 = false;
var structs = new TestStruct[] { theStruct };
IntPtr ptr = TestGetBackStruct(structs);
var resultStruct = (TestStruct)Marshal.PtrToStructure(ptr, typeof(TestStruct));
}
This works in the sense that I do get a struct back (using the debugger to inspect it), but with totally wrong values. I.e. the marshalling does not work at all. I've tried different version of the C# struct without success. So here are my questions (1 & 2 most important):
Is the C function correct for this purpose?
How is the struct to be written correctly in order to get me the correct values in the struct back to C#? (Is it even necessary to define the struct with the StructLayout(LayoutKind.Explicit) attribute using the FieldOffset values or can I use StructLayout(LayoutKind.Sequential) instead)?
Since I am returning a pointer to the TestStruct in C, I guess it should be possible to get back an array of TestStructs in C#. But this does not seem to be possible using the Marshal.PtrToStructure function. Would it be possible in some other way?
Apparantly it is possible to use something called unions in C by having multiple struct fields point to the same memory allocation using the same FieldOffset attribute value. I understand this, but I still don't get yet when such scenario would be useful. Please enlighten me.
Can someone recommend a good book on C# P/Invoke to C/C++? I am getting a bit tired of getting pieces of information here and there on the web.
Much obliged for help with these questions. I hope they were not too many.
Stop using LayoutKind.Explicit and get rid of the FieldOffset attributes and your code will work. Your offsets were not correctly aligning the fields.
public struct TestStruct
{
public double SomeDouble1;
public double SomeDouble2;
public int SomeInteger;
[MarshalAs(UnmanagedType.I1)]
public bool SomeBool1;
[MarshalAs(UnmanagedType.I1)]
public bool SomeBool2;
};
Declare the function in C# like this:
public static extern void TestGetBackStruct(TestStruct[] structs);
The default marshalling will match your C++ declaration (your code is C++ rather than C in fact) but you must make sure that your allocate the TestStruct[] parameter in the C# code before calling the function. Normally you would also pass the length of the array as a parameter so that the C++ code knows how many structs there are.
Please don't try to return the array of structures from the function. Use the structs parameter as an in/out parameter.
I know of no book with an emphasis on P/Invoke. It appears to be something of a black art!
My question has to do with trying to call a function written in C from C#. I've looked in a header file that came with the C library to understand the functions as they exist in the C dll. Here's what I see:
C code (for a function called "LocGetLocations"):
typedef enum {
eLocNoError,
eLocInvalidCriteria,
eLocNoMatch,
eLocNoMoreLocations,
eLocConnectionError,
eLocContextError,
eLocMemoryError
} tLocGetStatus;
typedef void *tLocFindCtx;
typedef void *tLocation;
PREFIX unsigned int POSTFIX LocGetLocations
(
tLocFindCtx pCtx,
tLocation *pLoc,
unsigned int pNumLocations,
tLocGetStatus *pStatus
);
In C#, I have this:
[DllImport(#"VertexNative\Location.dll")]
public static extern uint LocGetLocations(IntPtr findContext, out byte[] locations, uint numberLocations, out int status);
The problem is that I don't quite know how to handle the pLoc parameter in C#. I'm bringing it over as a byte array, although I'm not sure if that is correct. The C library's documentation says that that parameter is a pointer to an array of handles.
How can I get an array back on the C# side and access its data?
The example I was given in C, looks like this:
tLocation lLocation[20];
// other stuff
LocGetLocations(lCtx, lLocation, 20, &lStatus)
Any help would be much appreciated!
Generally, the only thing that matters is the size of the parameters. As I recall enums are integers in C, so you can simply use that. Or better, recreate the same enum in C#, I think it would work. One thing to remember is that when dealing with complex structs, one needs to use attributes to tell the framework about the desired alignment of members.
In the end, this signature works:
[DllImport(#"VertexNative\Location.dll")]
public static extern uint LocGetLocations(IntPtr findContext, [Out] IntPtr[] locations, uint numberLocations, out int status);
And I can call it like this (some refactoring needed):
IntPtr[] locations = new IntPtr[20];
int status;
// findContext is gotten from another method invocation
uint result = GeoCodesNative.LocGetLocations(findContext, locations, 20, out status);
Thanks for the help!