Click here to Skip to main content
15,860,972 members
Articles / Programming Languages / C++/CLI
Article

Convert a Delegate to a Function pointer to Implement Callback function

Rate me:
Please Sign up or sign in to vote.
4.71/5 (14 votes)
2 Feb 20032 min read 151.5K   974   29   22
Convert a delegate to a function pointer to implement callback function, for mixed Managed C++ and unmanaged C++ coding, and for DLL call.

Introduction

These days, I've read the article Implementing Callback functions using IJW (avoiding DllImport), by Nishant S. From which I benefited much. And I wonder if there is some way to convert a delegate to a function pointer, I've got it at last.

When you are calling a function which is in a DLL, and that function requires a callback function pointer. First you can use DllImport (if you like to do so), which is a simple solution. But I don’t like DllImport. What's more, some times the function I want to call is not in a DLL. That is if I am coding mixed Managed C++ and Unmanaged C++. Even DllImport will not work. There are several ways to call a Managed C++ function in unmanaged C++ code.

  1. Use static function
     //managed class
    __gc class classA1 {
        public: static void func1(int nArg)    {
                     Console::WriteLine(nArg.ToString());
                }
    };
    //unmanaged class
    class classB1 {
        public: classB1(int nArg)    {
            m_nCount = nArg;
        }
        public: void func1()  {
            classA1::func1(m_nCount);
        }
        protected: int m_nCount;
    };

    When I need a non-static function to be called, there is the second solution.

  2. Use a managed object as a parameter.
     //managed class
    __gc class classA1 {
        public : void func2(int nArg)  {
                     Console::WriteLine(nArg.ToString());
                 }
    };
    //unmanaged class
    class classB1 {
        public: classB1(int nArg) {
            m_nCount = nArg;
        }
        public : void func2(classA1* pClassA1)     {
             pClassA1->func2(m_nCount);
         }
        protected: int m_nCount;
    };

    It seems to work well, but when the one which call pClassA1->func2(…) is not the function classB1:: func2(…)]. Maybe classB1:: func2(…) calls other object’s member function, and the function calls others, at last pClassA1->func2(…) is called sadly. You must hold pClassA1 as a parameter to run for a long way, blessing there is no virtual function. Virtual functions can’t have managed object as parameter. And an unmanaged object can’t have a member variable to hold managed object.

  3. Make a function pointer which points to an instance member function.

    I have not found any method in .NET framework SDK to convert a delegate to a function pointer straightly yet, but I noticed Marshal::StructToPtr() which announced to be able to convert a managed struct to unmanaged memory block. What it does is to wrap the delegate in the managed struct, then convert the struct to an unmanaged block. At the beginning I used an unmanaged struct that has a field of a function pointer act as the unmanaged memory block, like this:

    typedef void (*PFUNC)(int)
    
    Struct PFUNC_Wrapper
    {
        PFUNC thepfunc;
    };

    Use the managed struct like this:

    __delegate void MyDelegate(int nArg);
    [StructLayoutAttribute( LayoutKind::Sequential, 
                           CharSet = CharSet::Ansi )]
    __gc struct Delegate_Wrapper
    {
        [MarshalAsAttribute(UnmanagedType::FunctionPtr)]
        MyDelegate*  _theDelegate;
    };

    Then I convert the managed struct to an unmanaged struct. At the field of PFUNC thepfunc I got the function pointer. Ooh I got it! But soon I found I could also convert the unmanaged struct to a function pointer instead of accessing the member field of PFUNC thepfunc. Like this: *(PFUNC*)(&theUnmanagedStruct). Here you must have seen that the unmanaged struct is useless. So I just use a PFUNC to receive the data as an unmanaged memory block.

The source code

 __gc class classA1 {    
    public : void func2(int nArg) {
                 Console::WriteLine(nArg.ToString());
             }
};
typedef void (*PFUNC)(int);

class classB1 {
    public: classB1(int nArg) {
        m_nCount = nArg;
    }
    public: virtual void func3(PFUNC pCallback){
        if(pCallback != NULL)    {
            pCallback(m_nCount);
        }
    }
    protected: int m_nCount;
};
__delegate void MyDelegate(int nArg);

[StructLayoutAttribute( LayoutKind::Sequential, CharSet = CharSet::Ansi )]
__gc struct Delegate_Wrapper
{
    [MarshalAsAttribute(UnmanagedType::FunctionPtr)]
    MyDelegate*  _theDelegate;
};

// This is the entry point for this application
int _tmain(void)
{
    // TODO: Please replace the sample code below with your own.
    Console::WriteLine(S"Hello World");

    //create instance of managed classA1
    classA1* theA1 = new classA1();

    //create instance of Delegate_Wrapper
    Delegate_Wrapper* theWrapper = new Delegate_Wrapper();
    theWrapper->_theDelegate = new MyDelegate(theA1,&classA1::func2);
    
    //Convert the Delegate to Function Pointer.
    PFUNC pFnc;
    Marshal::StructureToPtr(theWrapper,&pFnc,false);
    
    //create instance of unmaged classB1
    classB1 theB1(3);

    //use the function pointer as a callback function
    theB1.func3(pFnc);
    
    Console::ReadLine();
    return 0;
}

Ensure that the garbage collector does not reclaim the delegate before the callback function completes its work.

Conclusion

A managed class’s member function can be used through a function pointer. Even if it is a non-static function!!

E-mail:peiweny@hotmail.com

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


Written By
Web Developer
United States United States
A programer
Born in China
work in Japan
25 years old
Male

Comments and Discussions

 
QuestionMarshal directive exception was unhandled Pin
A.Machan Kachan25-Aug-09 17:42
A.Machan Kachan25-Aug-09 17:42 
QuestionMarshal.GetFunctionPointerForDelegate? Pin
blue2v10-Apr-09 9:29
blue2v10-Apr-09 9:29 
AnswerRe: Marshal.GetFunctionPointerForDelegate? Pin
Zhixiang Zhu15-May-12 22:16
Zhixiang Zhu15-May-12 22:16 
General!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Don´t use this code !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Pin
Elmue22-Apr-08 16:52
Elmue22-Apr-08 16:52 
Questionhello world ! Pin
bibiboule2-Jan-07 21:33
bibiboule2-Jan-07 21:33 
QuestionWhat about an ArrayList instead an Int???? Pin
franjie27-May-05 3:45
franjie27-May-05 3:45 
Generalmanaged class as member variable in unmanaged class Pin
BAIJUMAX17-Aug-04 3:30
professionalBAIJUMAX17-Aug-04 3:30 
GeneralSuccessive invocations fail Pin
Member 767218516-Sep-03 3:14
Member 767218516-Sep-03 3:14 
GeneralRe: Successive invocations fail Pin
nutty11-Jul-04 20:55
nutty11-Jul-04 20:55 
GeneralRe: Declaring Managed class as Member variable in an unmanaged class Pin
BAIJUMAX24-Aug-04 1:52
professionalBAIJUMAX24-Aug-04 1:52 
GeneralRe: Successive invocations fail Pin
the-unforgiven13-Sep-05 3:18
the-unforgiven13-Sep-05 3:18 
GeneralJust something to note Pin
leppie2-Apr-03 14:46
leppie2-Apr-03 14:46 
GeneralMore than one deleagte Pin
RonnyPutz12-Feb-03 4:48
RonnyPutz12-Feb-03 4:48 
QuestionHow about a VC++ 6.0 sample? Pin
WREY5-Feb-03 1:45
WREY5-Feb-03 1:45 
AnswerRe: How about a VC++ 6.0 sample? Pin
kero5-Feb-03 14:06
kero5-Feb-03 14:06 
GeneralRe: How about a VC++ 6.0 sample? Pin
WREY4-Mar-03 3:20
WREY4-Mar-03 3:20 
VC++ 6.0 does not use "#using <<mscorlib.dll>" as a preprocessor statement. It might be acceptable in VC++ 7.0, but I am getting a fatal error from my VC++ 6.0 compiler for it. (This is in the "createpfnc.cpp" file.)

When I substituted "#include <<mscorlib.dll>" for it, I still get a fatal error because it cannot find the file to open it. Where is the file located?

NOTE: I had to use double angle brackets in front of "mscorlib" in order to get it shown in this message.

Thanks.

Cool | :cool:

William
GeneralRe: How about a VC++ 6.0 sample? Pin
Christian Graus7-Sep-06 0:40
protectorChristian Graus7-Sep-06 0:40 
GeneralRe: How about a VC++ 6.0 sample? Pin
WREY7-Sep-06 4:47
WREY7-Sep-06 4:47 
GeneralRe: How about a VC++ 6.0 sample? Pin
Christian Graus9-Sep-06 15:28
protectorChristian Graus9-Sep-06 15:28 
GeneralUnable to download source files. Pin
WREY4-Feb-03 6:06
WREY4-Feb-03 6:06 
GeneralRe: Unable to download source files. Pin
jerry0davis4-Feb-03 23:01
jerry0davis4-Feb-03 23:01 
GeneralRe: Unable to download source files. Pin
WREY5-Feb-03 1:18
WREY5-Feb-03 1:18 

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

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