Search code examples
c++c++-clifunction-pointers

ERROR: 'a pointer to member is not valid for a managed class'


I'm getting this error and I don't know how to solve it. This is my code (more details below):

CP1626.h

#pragma once

#include <Windows.h>
namespace CP1626{

...

//DLL functions
void setCallbackDataWriteFunc(PNIO_CBF_DATA_WRITE _ptrDataWriteFunc);

...

}

cp1626.cpp

#include "cp1626lib.h"

...

typedef void (* ptr_setCallbackDataWriteFunc)(PNIO_CBF_DATA_WRITE);
ptr_setCallbackDataWriteFunc setCallbackDataWriteFuncFunction;

...

void CP1626::setCallbackDataWriteFunc(PNIO_CBF_DATA_WRITE _ptrDataWriteFunc){
    (setCallbackDataWriteFuncFunction)(_ptrDataWriteFunc);
}

And with PNIO_IOXS defined as

typedef PNIO_IOXS    (*PNIO_CBF_DATA_WRITE) /* write data to IO stack (local ==> remote) */
       (PNIO_UINT32          DevHndl,       /* Handle for Multidevice */
        PNIO_DEV_ADDR      * pAddr,         /* geographical address */
        PNIO_UINT32          BufLen,        /* length of the submodule input data */
        PNIO_UINT8         * pBuffer,       /* Ptr to data buffer to write to */
        PNIO_IOXS            Iocs);         /* remote (io controller) consumer status */

And then, I've, coded using C++/CLI and .NET, my main user interface class, who does next:

UI_Main.h

#include "cp1626lib.h"

...


public ref class UI_Main : public System::Windows::Forms::Form{

    //Local function definition, which is assigned to callback
    PNIO_IOXS dataWriteFunc(PNIO_UINT32 DevHndl, PNIO_DEV_ADDR * pAddr, PNIO_UINT32 BufLen, PNIO_UINT8 * pBuffer, PNIO_IOXS Iocs);

    ...

    void InitCP1626(){
                ...

                CP1626::setCallbackDataWriteFunc(dataWriteFunc);

                ...
            }

}

The error is at line CP1626::setCallbackDataWriteFunc(dataWriteFunc);, and it says that a pointer to member is not valid for a managed class. What's the correct form to do this callback assignation when I'm on a managed class? I think that I should find a way to convert delegates into function pointers, but also I'm not sure about this.

Thank you in advance.

EDIT: I've tried to change line CP1626::setCallbackDataWriteFunc(dataWriteFunc); with CP1626::setCallbackDataWriteFunc(Marshal::GetFunctionPointerForDelegate(del));, with dataWriteFunc^ del; a delegate with format delegate PNIO_IOXS dataWriteFunc(PNIO_UINT32 DevHndl, PNIO_DEV_ADDR * pAddr, PNIO_UINT32 BufLen, PNIO_UINT8 * pBuffer, PNIO_IOXS Iocs);

But it also fails. At this time, the error says 'CP1626::setCallbackDataWriteFunc : cannot convert parameter 1 from 'System::IntPtr' to 'PNIO_CBF_DATA_WRITE''


Solution

  • you might think about rereading part of the documentation from Microsoft. Even if it's old (like from 2006) it is not outdated.

    Example. Microsoft documented the use of callbacks. https://msdn.microsoft.com/en-us/library/367eeye0.aspx

    In your case, you didn't look, what GetFunctionPointerForDelegate() is returning. It is a IntPtr. This is a structure Microsoft uses to wrap all sort of pointers into one structure for .NET. It has the method void* ToPointer()

    PNIO_CBF_DATA_WRITE cb = static_cast<PNIO_CBF_DATA_WRITE>(IntPtr.ToPointer());  
    CP1626::setCallbackDataWriteFunc(cb);
    

    Be aware that you should use __stdcall for the callback. It is mentioned to be needed for compatibility.

    typedef PNIO_IOXS (__stdcall *PNIO_CBF_DATA_WRITE)
    

    If you are not able to recompile the sources to use __stdcall, just reroute it over another function you have defined.

    I tried to use your code within a test project but i didn't want to setup to call the callback somewhere independent.

    Kind Regards

    p.s. I wanted to mark your question with low quality. Because there is documentation to read/google and learn from. You should take your time and be so kind to mark some of the answers for your four questions lately as the right answer.