I am totally bollixed up on this one.
If I can marshal a delegate to a legacy DLL as a callback, why the hell can't I do something to a
delegate to assign it to a function pointer variable in a structure?!? It sure seems like the two
operations are very similar; why do I have to cross a DLL boundary to do it?
Does anyone have any suggestions about how to work around this situation? Or should I just check
myself into an asylum right now?
- Mark
Maybe this is what you are looking for?
// CS file sample program passing callback function pointers through a
structure
using System;
using System.Runtime.InteropServices;
public delegate void CalcDelegate(int arg1, int arg2);
[StructLayout(LayoutKind.Sequential)]
struct FunctionTable
{
public IntPtr fAdd; // function pointer pointing to AddMethod
public IntPtr fMult; // function ptr pointing to MultMethod
}
class Tester
{
[DllImport("native.dll")]
public static extern void NativeCaller(FunctionTable ft);
[DllImport("msvcrt")]
public static extern IntPtr strncpy(Delegate pd, IntPtr src, int size);
static CalcDelegate pd;
public static void Main()
{
FunctionTable ft = new FunctionTable();
pd = new CalcDelegate(AddMethod);
ft.fAdd = GetFunctionPtrFromDelegate(pd);
pd = new CalcDelegate(MultMethod);
ft.fMult = GetFunctionPtrFromDelegate(pd);
NativeCaller(ft);
}
// here is the trick, we use a msvcrt function to return a pointer from
the delegate
static IntPtr GetFunctionPtrFromDelegate(Delegate d)
{
// strncpy returns the buffer address (the marshaled delegate pointer).
We obviously don't copy anything
return strncpy(d, IntPtr.Zero, 0);
}
static void AddMethod(int arg1, int arg2)
{
Console.WriteLine(arg1 + arg2);
}
static void MultMethod(int arg1, int arg2)
{
Console.WriteLine(arg1 * arg2);
}
}
//C++ file native.cpp
// compile with: cl /LD native.cpp
struct FunctionTable
{
void* fAdd;
void* fMult;
};
typedef int (__stdcall *FPTRHELPER) (int, int);
extern "C" {
__declspec(dllexport) void NativeCaller (FunctionTable);
}
void NativeCaller(FunctionTable fptr)
{
(*(FPTRHELPER)fptr.fAdd)(5, 2);
(*(FPTRHELPER)fptr.fMult)(5, 2);
}
Willy.
>I am totally bollixed up on this one.
>
[quoted text clipped - 10 lines]
>
> - Mark
Girish Bharadwaj - 23 Sep 2004 22:20 GMT
brrr.... That is some code. :) love it.

Signature
Girish Bharadwaj
http://msmvps.com/gbvb
> Maybe this is what you are looking for?
>
[quoted text clipped - 86 lines]
> >
> > - Mark
Girish bharadwaj - 24 Sep 2004 03:03 GMT
BTW: If you want to get the IntPtr for a delegate, you can do that by
IntPtr funcPtr = d.Method.MethodBase.GetFunctionPointer(); //d= delegate, So
you dont have to resort to strncpy hack :)

Signature
Girish Bharadwaj
http://msmvps.com/gbvb
> brrr.... That is some code. :) love it.
>
[quoted text clipped - 90 lines]
> > >
> > > - Mark
Willy Denoyette [MVP] - 24 Sep 2004 10:12 GMT
Girish,
Unfortunately this doesn't work:
1. d.Method.MethodBase.GetFunctionPointer(); doesn't compile because
MethodBase is no property of MethodInfo, GetFunctionPointer is a method of
RuntimeMethodHandle. So you have to use - IntPtr f =
d.Method.MethodHandle.GetFunctionPointer(); but read on...
2. The MethodHandle (RuntimeMethodHandle) is only valid in the domain in
which he is obtained!
Normally, when unmanaged code (process wide) "calls back" into managed code
the PInvoke thunk (or IJW thunk) selects the target domain, based on flags
set in the VTFixup table entries when you first call into unmanaged code
(passing a delegate as arg), and adjusts the delegate callback method
pointer accordingly. That's the reason why you need to call into unmanaged
code passing a delegate to get a correctly adjusted method pointer back.
When using the function pointer returned from GetFunctionPointer() will most
probably call at the wrong address (corrupting the stack) or call into
read-only memory.
Willy.
> BTW: If you want to get the IntPtr for a delegate, you can do that by
>
[quoted text clipped - 102 lines]
>> > >
>> > > - Mark
Girish bharadwaj - 24 Sep 2004 11:26 GMT
Doh! for 1. Yeah. I meant MethodHandle.
So Doh! for 2. I did not realize that part. :)

Signature
Girish Bharadwaj
http://msmvps.com/gbvb
> Girish,
>
[quoted text clipped - 124 lines]
> >> > >
> >> > > - Mark
Willy Denoyette [MVP] - 24 Sep 2004 11:28 GMT
> Girish,
> probably call at the wrong address (corrupting the stack) or call into
> read-only memory.
Woops... should read:
.... or call into protected memory.
Willy.
Girish bharadwaj - 24 Sep 2004 11:39 GMT
There is a Marshal.GetFunctionPointerForDelegate() in 2.0. Is that similar
to what you are describing?

Signature
Girish Bharadwaj
http://msmvps.com/gbvb
>
> > Girish,
[quoted text clipped - 7 lines]
>
> Willy.
Willy Denoyette [MVP] - 24 Sep 2004 16:05 GMT
> There is a Marshal.GetFunctionPointerForDelegate() in 2.0. Is that similar
> to what you are describing?
Girish,
Absolutely, GetFunctionPointerForDelegate() (internal)calls into the CLR 2.0
and returns a valid pointer to be used as callback pointer for the target
domain.
Willy.
Mark Olbert - 28 Sep 2004 04:43 GMT
Wow! Thanx for the solution/hack, and for the sidebar discussion.
- Mark