Click here to Skip to main content
Click here to Skip to main content

Convert a Delegate to a Function pointer to Implement Callback function

, 2 Feb 2003
Rate this:
Please Sign up or sign in to vote.
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

Share

About the Author

kero
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 PinmemberA.Gokulakannan25-Aug-09 17:42 
QuestionMarshal.GetFunctionPointerForDelegate? Pinmemberblue2v10-Apr-09 9:29 
AnswerRe: Marshal.GetFunctionPointerForDelegate? PinmemberZhixiang Zhu15-May-12 22:16 
General!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Don´t use this code !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PinmemberElmue22-Apr-08 16:52 
Questionhello world ! Pinmemberbibiboule2-Jan-07 21:33 
QuestionWhat about an ArrayList instead an Int???? Pinmemberfranjie27-May-05 3:45 
Generalmanaged class as member variable in unmanaged class Pinmemberbaiju.km17-Aug-04 3:30 
GeneralSuccessive invocations fail Pinsusshnipak16-Sep-03 3:14 
GeneralRe: Successive invocations fail Pinmembernutty11-Jul-04 20:55 
GeneralRe: Declaring Managed class as Member variable in an unmanaged class Pinmemberbaiju.km24-Aug-04 1:52 
GeneralRe: Successive invocations fail Pinmemberthe-unforgiven13-Sep-05 3:18 
GeneralJust something to note Pinmemberleppie2-Apr-03 14:46 
GeneralMore than one deleagte PinmemberRonnyPutz12-Feb-03 4:48 
QuestionHow about a VC++ 6.0 sample? PinmemberWREY5-Feb-03 1:45 
AnswerRe: How about a VC++ 6.0 sample? Pinmemberkero5-Feb-03 14:06 
GeneralRe: How about a VC++ 6.0 sample? PinmemberWREY4-Mar-03 3:20 
GeneralRe: How about a VC++ 6.0 sample? PinstaffChristian Graus7-Sep-06 0:40 
GeneralRe: How about a VC++ 6.0 sample? PinmemberWREY7-Sep-06 4:47 
GeneralRe: How about a VC++ 6.0 sample? PinstaffChristian Graus9-Sep-06 15:28 
GeneralUnable to download source files. PinmemberWREY4-Feb-03 6:06 
GeneralRe: Unable to download source files. PinmemberJeremy Davis4-Feb-03 23:01 
GeneralRe: Unable to download source files. PinmemberWREY5-Feb-03 1:18 

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.

| Advertise | Privacy | Mobile
Web02 | 2.8.140814.1 | Last Updated 3 Feb 2003
Article Copyright 2003 by kero
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid