Reputation:
Summary:
I have a bunch of C functions I have to call from C#. My current working solution is based on function overloading and I'm wondering if there is a more elegant solution.
The C stuff:
somewhere in a header file
typedef struct _unknown_stuff * handle; // a opaque pointer
an example of the function
func( uint num_entries,
handle * objects,
uint * n)
{ ... }
in C the function should be used similar to this:
// warning: i bet that the syntax is not correct but you should get the idea...
uint n;
func(0, null, &n);
handle * objects = malloc(n * sizeof(handle));
func(n, objects, null);
The C# stuff:
right now I'm doing the following in C#:
public struct handle
{
public IntPtr Pointer;
}
// version to get number of objects
[DllImport(dll, ...]
private static extern void
func( uint must_be_zero,
object must_be_null,
out uint n);
// version to get the actual data
[DllImport(dll, ...]
private static extern void
func( uint num_entries,
[Out] handle[] objects,
int must_be_zero);
and then:
handle[] objects;
uint n = 42;
func(0, null, out n);
objects = new handle[n];
func(n, objects, 0);
The Question
Since I'm a C# noob, I was wondering if this is the best way to do this. Especially I would like to know if there is a way around overloading the function.
Upvotes: 0
Views: 628
Reputation: 13964
Wouldn't the C dll look at 0, and process that as null?
It only has one function, correct? That is, the C function is defined once, and not separately for a null case, and would have an
if( objects == NULL )
check somewhere in there. On most systems (check the stdio.h of the target system) this is 0.
So calling from pinvoke with a 0 value in this place should do what you wanted overloading to do.
Upvotes: 0
Reputation: 101645
First of all, your code as is is wrong, because in the second C# signature your third argument is int
, while the corresponding C argument is still int*
. It will work when targetting 32-bit Windows, because sizeof(int)==sizeof(int*)
there - so when you pass a 0 int you end up passing a null pointer - but it is not 64-bit safe. If you still want to do it that way, you need to use IntPtr
there.
Aside from that, you could try:
[DllImport(dll, ...]
private static extern void func(
uint num_entries,
[Out] handle[] objects,
[Out] int[] num_devices);
making the third argument an array so that you could pass null there.
Or just use pointers. There's nothing bad about it, and don't be afraid of unsafe
keyword - any kind of P/Invoke is inherently unsafe anyway, so you might as well be explicit about it.
Upvotes: 1