2008
06.11

More Fun with Interop

Now let’s say we have a “C” exported function that looks something like this:

void MyFunction(void* myData);

This, of course, is inherently unsafe, because the void* could represent anything. In the wonderful world of “C”, however, such a construct is frequently used.
We must assume that the caller knows exactly what the called function is expecting the void* to point to. Knowing that, then, how would we call this function from C#? Good question.
I puzzled over it a bit before realizing that a void* is allowed in C#. No way, you say. That’s what I thought.

Using P/Invoke for this example, in your DllImport declaration, just put the “unsafe” keyword like so:

        [DllImport("MyDLL.dll")]
        public static unsafe extern void MyFunction(void* myData);

Using “unsafe” allows the code to compile and the compiler to be happy with a void* in C#. Cool. So how do you call it from C#?
This is one of those instances where you need to create a “pinned” address so the garbage collector doesn’t move the memory around during the call. For the sake of simplicity in this example we are just going to use an array of bytes for the void*. Put everything in an “unsafe” block so the C# compiler is happy with a void* :

public void AMethod()
{
  unsafe
  {
    void* vaddr = null;
    Array arr = Array.CreateInstance(typeof(byte), 10);
    GCHandle handle = GCHandle.Alloc(arr, GCHandleType.Pinned);
    vaddr = (void*)handle.AddrOfPinnedObject();
    //Call the DllImport function
    MyFunction(vaddr);

    if (handle.IsAllocated)
      handle.Free();
  }
}

Assuming that MyFunction “knows” that it is going to get an array of 10 bytes (in this case), the call will work and both the C++ and C# sides will be happy. Of course, you probably should put something interesting in the array before sending it across. I’ll leave that to you.

midniteblogger