Click here to Skip to main content
Licence 
First Posted 8 Mar 2006
Views 26,034
Bookmarked 18 times

Using managed delegate types in the unmanaged world

By | 8 Mar 2006 | Article
An article on how to use managed delegate types in the unmanaged world.

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.

//Interface exposed to COM world 
[ComVisible(true), 
    GuidAttribute("2E9B141F-F876-4141-BCA3-F8B58DA0FE4F")]
public interface IDelegateHelper
{
    AsyncCallback 
      AsynCallbackDelegateWrapper(IntPtr funcPtr_in);
}

//Class exposed to COM world
[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 the TLBs
#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

//Add this to the library block in IDL 
//file for recognizing IAsyncResult* 
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
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

NidhiGupta

Web Developer

India India

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionAPi Problem Pinmembert4urean2:36 13 Aug '06  
I am doing a project to develop ”Software Defined Radio”. I have purchased a hardware radio receiver called WiNRADiO G303e. It connects to the computer via USB interface. It feeds the computer with down converted + demodulated RF signal (12kHz) to the computer. Which I have to process in some way.
 
The winradio company has provided an API to communicate with the radio receiver According to them
“The G303 receivers API is implemented as a single 32-bit library WRG303API.DLL. It provides functions for all communication with all types of G303 receivers. It can be used by any 32-bit application under Windows 98, ME as well as 2000 and XP.”
I am making my project in C#. I have written an API wrapper class. I used P/Invoke and defined all the method signatures in that class. I have used help from various different tools and web forums to write this class.
 

Now I particular problem is in the methods which use pointer to memory location, arrays or passing the reference of these arrays
 
METHOD 1
 
The method uses a callback mechanism which can be provided by Delegates in c # but I can’t figure out the syntax to it.
 
C/C++ declaration given in the API
BOOL __stdcall CodecStart (int hRadio, void __stdcall (*CallbackFunc) (void *), void *CallbackTarget);
I have been suggested to use the following code for this function but I have absolutely no clue how to do coding for this method.
 
There is an example usage of this function in C++
 
#include "stdafx.h"
#include
#include
 
// G3 API function type declarations
typedef int (__stdcall *FNCOpenRadioDevice)(int iDeviceNum);
typedef BOOL (__stdcall *FNCCloseRadioDevice)(int hRadio);
typedef BOOL (__stdcall *FNCSetAtten)(int hRadio, BOOL fAtten);
typedef BOOL (__stdcall *FNCSetPower)(int hRadio, BOOL fPower);
typedef BOOL (__stdcall *FNCSetAGC)(int hRadio, int iAGC);
typedef BOOL (__stdcall *FNCCodecStart)(int hRadio,void (__stdcall *CallbackFunc)(void *),
void *CallbackTarget);
typedef BOOL (__stdcall *FNCCodecStop)(int hRadio);
typedef unsigned int (__stdcall *FNCCodecRead)(int hRadio,void *Buf,unsigned int Size);
 
typedef struct {
int hRadio;
FILE *IFFile;
FNCCodecRead CodecRead;
} CallbackContext;
 
void __stdcall CodecCallback(void *Target)
{
unsigned int i;
char Buf[4096];
CallbackContext *Ctx=(CallbackContext *)Target;
 
while ((i=Ctx->CodecRead(Ctx->hRadio,Buf,sizeof(Buf)))!=0)
fwrite(Buf,i,1,Ctx->IFFile);
}
//int _tmain(int argc, _TCHAR* argv[])
int main(int argc, char* argv[])
{
// load the G3 API library
HMODULE dll=LoadLibraryA("wrg303api.dll");
if (!dll) {puts("WRG303API.DLL not found !"); return 0;}
 
// link G3 API functions
FNCOpenRadioDevice OpenRadioDevice=(FNCOpenRadioDevice)GetProcAddress(dll,"OpenRadioDevice");
FNCCloseRadioDevice CloseRadioDevice=(FNCCloseRadioDevice)GetProcAddress(dll,"CloseRadioDevice");
FNCSetAtten SetAtten=(FNCSetAtten)GetProcAddress(dll,"SetAtten");
FNCSetPower SetPower=(FNCSetPower)GetProcAddress(dll,"SetPower");
FNCSetAGC SetAGC=(FNCSetAGC)GetProcAddress(dll,"SetAGC");
FNCCodecStart CodecStart=(FNCCodecStart)GetProcAddress(dll,"CodecStart");
FNCCodecStop CodecStop=(FNCCodecStop)GetProcAddress(dll,"CodecStop");
FNCCodecRead CodecRead=(FNCCodecRead)GetProcAddress(dll,"CodecRead");
 
// open the first available radio
int hRadio=OpenRadioDevice(0);
if (!hRadio) {puts("No WR-G303 device could be opened !");FreeLibrary(dll); return 0;}
 
// set Power, AGC and Attenuator
if (SetPower(hRadio,TRUE)) puts("The device is turned ON"); else puts("The device failed to turn ON");
if (SetAtten(hRadio,FALSE)) puts("The attenuator is OFF"); else puts("The attenuator failed to turn OFF");
if (SetAGC(hRadio,3)) puts("The AGC is FAST"); else puts("The AGC failed to switch");
 
// open the IF samples destination file
FILE *f=fopen("IF2.pcm","wb");
 
// start the IF stream from the codec
CallbackContext Ctx;
 
Ctx.hRadio=hRadio;
Ctx.IFFile=f;
Ctx.CodecRead=CodecRead;
if (!CodecStart(hRadio,CodecCallback,&Ctx)) puts("Codec streaming couldn't be started!");
else {
puts("Codec streaming properly started!");
while (!ftell(f) )
{
}
CodecStop(hRadio);
fclose(f);
}
 
// close the device handle
if (CloseRadioDevice(hRadio)) puts("The device is closed properly"); else puts("The device failed to close");
 
// free the G3 API library
FreeLibrary(dll);
 
return 0;
}

o O º(`'•.,(`'•., ☆,.•''),.•'')º O o°
»•'"`»* *☆ t4ure4n ☆* *«•'"`«
°o O º(,.•''(,.•'' ☆`'•.,)`'•.,)º O o°
 

 

 


 
o O º(`'·.,(`'·., ☆,.·''),.·'')º O o°
»·'"`»* *☆ t4ure4n ☆* *«·'"`«
°o O º(,.·''(,.·'' ☆`'·.,)`'·.,)º O o°

GeneralAlternatively... PinmemberRichard Deeming7:44 15 Mar '06  
AnswerRe: Alternatively... Pinmembernidhig8320:16 15 Mar '06  
GeneralRe: Alternatively... PinmemberRichard Deeming23:53 15 Mar '06  
GeneralComments Pinmembermanish@siemens18:32 8 Mar '06  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 8 Mar 2006
Article Copyright 2006 by NidhiGupta
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid