Note that there are some explanatory texts on larger screens.

plurals
  1. POC# P/Invoke: Marshalling structures containing function pointers
    primarykey
    data
    text
    <p>Sorry for the verbose introduction that follows. I need insight from someone knowing P/Invoke internals better than I do.</p> <p>Here is how I'm marshalling structures containing function pointers from C to C#. I would like to know whether it's the cleanest and/or most efficient way of doing it.</p> <p>I'm interfacing with a native DLL coded in C that provides the following entry point:</p> <pre><code>void* getInterface(int id); </code></pre> <p>You have to pass <code>getInterface(int)</code> one of the following enum values:</p> <pre><code>enum INTERFACES { FOO, BAR }; </code></pre> <p>Which returns a pointer to a structure containing function pointers like:</p> <pre><code>typedef struct IFOO { void (*method1)(void* self, int a, float b); void (*method2)(void* self, int a, float b, int c); } IFoo; </code></pre> <p>And here is how you use it in C:</p> <pre><code>IFoo* interface = (IFoo*)getInterface(FOO); interface-&gt;method1(obj, 0, 1.0f); // where obj is an instance of an object // implementing the IFoo interface. </code></pre> <p>In C# I have a <code>Library</code> class that maps the <code>getInterface(int)</code> entry point using P/Invoke.</p> <pre><code>class Library { [DllImport("MyDLL"), EntryPoint="getInterface", CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr GetInterface(int id); }; </code></pre> <p>Then I defined:</p> <pre><code>struct IFoo { public M1 method1; public M2 method2; [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void M1(IntPtr self, int a, float b); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void M2(IntPtr self, int a, float b, int c); } </code></pre> <p>And I'm using it this way:</p> <pre><code>IntPtr address = Library.GetInterface((int)Interfaces.FOO); IFoo i = (IFoo)Marshal.PtrToStructure(address, typeof(IFoo)); i.method1(obj, 0, 1.0f): // where obj is an instance of an object // implementing the IFoo interface. </code></pre> <p>I have the following questions:</p> <ol> <li><p>Is mapping the whole structure less efficient than mapping a single pointer inside the structure using <code>Marshal.GetDelegateForFunctionPointer()</code>?</p> <p>Since I mostly don't need all the methods exposed by an interface, I can do (tested and works): </p> <pre><code>unsafe { IntPtr address = Library.GetInterface(id); IntPtr m2address = new IntPtr(((void**)address.toPointer())[1]); M2 method2 = (M2)Marshal.GetDelegateForFunctionPointer(m2address, typeof(M2)); method2(obj, 0, 1.0f, 1); } </code></pre></li> <li><p>When mapping the whole structure at once using <code>Marshal.PtrToStructure()</code>, is there a less verbose way than what I described? I mean less verbose than having to define the delegate types for every methods etc?</p></li> </ol> <hr> <p>EDIT: For the sake of clarity and completeness, in the code snippets above, <code>obj</code> is an instance obtained with the <code>void* createObject(int type)</code> entry point.</p> <hr> <p>EDIT2: One advantage of method 1) is that <code>Marshal.GetDelegateForFunctionPointer()</code> is only available starting from .NET Framework 2.0. However, <code>Marshal.PrtToStructure()</code> has always been available. That said, I'm not sure it's worth ensuring 1.0 compatibility nowadays.</p> <hr> <p>EDIT3: I tried to inspect the generated code using <a href="http://www.red-gate.com/products/reflector/" rel="noreferrer">Reflector</a> but it doesn't give much information since all the interesting details are done in helper functions like <code>PtrToStructureHelper</code> and are not exposed. Then, even if I could see what's done in the framework internals, then the runtime has the opportunity to optimize things away and I don't know exactly what, why and when :)</p> <p>However, I benchmarked the two approaches described in my question. The <code>Marshal.PtrToStructure()</code> approach was slower by a factor around 10% compared to the <code>Marshal.GetDelegateForFunctionPointer()</code> approach; that whith a structure containing <code>IntPtr</code>s for all the functions that are not of interest.</p> <p>I also compared the <code>Marshal.GetDelegateForFunctionPointer()</code> with my own rolled marshaller: I align a <code>struct</code> representing the call stack, pin it in memory, pass its address to the native side where I use a trampoline coded in asm so that the call function uses the memory area as its parameter stack (this is possible since the <code>cdecl</code> x86 calling convention passes all the function parameters on the stack). Timings were equivalent.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload