Introduction
Creating a delegate in .NET is extremely simple. However, in a rare case, you might have to create an object of the .NET delegate
type with an unmanaged function pointer (in unmanaged world). This article explains a simple way to do the same.
Background
The problem I faced was:
In an ATL COM environment, I had to create an object of the .NET delegate
type, AsyncCallback
. In .NET, to create an object of this kind and assign a method to it is simple, by using a parameterized constructor. But in unmanaged COM world, parameterized constructors are not available, and it would be very difficult to do the same.
I solved this problem by creating a helper class in .NET which wraps an unmanaged function pointer (sent from the unmanaged world) as an AsyncCallback
delegate. This delegate is then returned to the unmanaged world.
Using the code
Step 1. In .NET, create an interface IDelegateHelper
. This interface provides a method AsyncCallbackDelegateWrapper
that takes in a function pointer to an unmanaged function whose delegate is to be created. DelegateHelperCLass
implements this interface. The method definition involves using Marshal.GeDelegateForFunctionPointer
available in .NET to create a delegate out of the function pointer. The interface is provided for ease of use in the COM unmanaged world.
[ComVisible(true),
GuidAttribute("2E9B141F-F876-4141-BCA3-F8B58DA0FE4F")]
public interface IDelegateHelper
{
AsyncCallback
AsynCallbackDelegateWrapper(IntPtr funcPtr_in);
}
[ComVisible(true)]
public class DelegateHelperCLass : IDelegateHelper
{
public AsyncCallback
AsynCallbackDelegateWrapper(IntPtr funcPtr_in)
{
Delegate aAsyncCallbackDelegate =
Marshal.GetDelegateForFunctionPointer(funcPtr_in,
typeof(AsyncCallback));
return aAsyncCallbackDelegate as AsyncCallback;
}
}
Step 2. Export this .NET DLL into a TLB for use in COM. Use the tlbexp.exe utility to do the same. Register the .NET DLL using regasm.
tlbexp.exe DelegateHelper.dll
/out:F:\DelegateHelper.tlb
regasm.exe DelegateHelper.dll
Step 3. To use this in the unmanaged world (COM C++, here), create an instance of IDelegateHelper
using CoCreateInstance
. Then call the method AsynCallbackDelegateWrapper
, passing the function pointer of the method whose delegate is to be created. The result obtained is a .NET delegate
type.
#import "C:\WINDOWS\Microsoft.NET\Framework"
"\v2.0.50215\mscorlib.tlb"
raw_interfaces_only,
raw_native_types, no_namespace,
named_guids, rename("_Module", "ReflectionModule"),
rename("ReportEvent", "ReportEventModule")
#import "F:\DelegateHelper.tlb"
raw_interfaces_only named_guids, no_namespace
importlib("C:\WINDOWS\Microsoft.NET\"
"Framework\v2.0.50215\mscorlib.tlb");
//Create a function pointer FuncPtr that has
//a signature same as that of the delgate methods
typedef void(*FuncPtr)(IAsyncResult*);
//CClient code that calls the helper methods
STDMETHODIMP CClient::CreateAsyncCallbackDelegate(void)
{
//First create an instance of DelegateHelper class
CComPtr<IDelegateHelper> aHelper;
HRESULT hr =
aHelper.CoCreateInstance(CLSID_DelegateHelperCLass);
if(FAILED(hr))
{
return E_FAIL;
}
//AsyncCallback delegate instnace
//that is to be populated with
_AsyncCallback* aCallBack = NULL;
FuncPtr aPtr = TestMethod;
hr = aHelper->AsynCallbackDelegateWrapper((long)aPtr,
&aCallBack);
if(FAILED(hr))
{
return E_FAIL;
}
//*************************************
//Now aCallBack can be used like
//a regular AsyncCallback instance!!
//*************************************
return S_OK;
}
//Some static method whose delegate is to be created
void CClient::TestMethod(IAsyncResult* asyncResult_in)
{
//Your Callback code
}
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.