C#pInvoke到C函数

时间:2014-12-05 16:13:11

标签: c# pinvoke

我会感谢你帮我解决了一个问题,我已经坚持了几天。

我有一个声明的原生C ++函数类型:

typedef STATUS (T_TED_AcppBoxDYN_RegisterEventCallback) (
        PEventCallback function, // pointer to the customer callback 
        PVOID param              // custom data (returned in callback)
        );

其中PEventCallbackPEVENT的声明如下:

typedef int (*PEventCallback) (PEVENT event, PVOID param); 

typedef struct
{
  int nEventId;
  void* pParam;
} EVENT,*PEVENT;

C ++代码提供指向该类型函数的指针作为全局变量:

T_TED_AcppBoxDYN_RegisterEventCallback* TED_AcppBoxDYN_RegisterEventCallback
        = NULL;

稍后通过以下代码进行初始化:

#ifdef LOAD_PROC_ADDRESS
#undef LOAD_PROC_ADDRESS
#endif
#define LOAD_PROC_ADDRESS(handle,func) \
  if((func=(T_##func*)GetProcAddress(handle,#func))==NULL) \
  {\
      sMsg.Format( "Error occurs while loading entry point\n'%s'\n"\
                   "from detector DLL '%s'\n", GetName (), #func );\
      MessageBox(NULL, sMsg.GetBuffer(), "Load Proc Error", MB_OK | MB_ICONSTOP);\
      return (false);\
  }

bool P5100EDllManager::LoadProc ()
{
    CString sMsg;

    HMODULE hDllHandle = GetHandle();
    if (hDllHandle == NULL)
    {
        return false;   // cannot load the proc if the dll has not been loaded
    }

    LOAD_PROC_ADDRESS(hDllHandle, TED_AcppBoxDYN_RegisterEventCallback);
    return true;
}

我想从C#调用指向函数。为此,我定义了一个C#包装器:

public delegate void TDICallBack(IntPtr callbackEvent, IntPtr pParam);
[DllImport(DLL, EntryPoint = "TED_AcppBoxDYN_RegisterEventCallback", CallingConvention = CallingConvention.Cdecl)]
private static extern int TED_AcppBoxDYN_RegisterEventCallback(TDICallBack callBack, IntPtr param);
public void RegisterEventCallback(TDICallBack callBack, IntPtr param)
{
  TED_AcppBoxDYN_RegisterEventCallback(callBack, param);
}

我正在使用它:

TdiapiFacade.RegisterEventCallback(OnTdiCallBack, IntPtr.Zero);

public void OnTdiCallBack(IntPtr ptr, IntPtr param)
{
}

RegisterEventCallback()似乎成功运行,但在应该调用回调函数的时候,应用程序崩溃了。正如您所看到的,在这个阶段,我甚至没有打开提供给回调函数的参数。

我需要做些什么来完成这项工作?

2 个答案:

答案 0 :(得分:2)

P / invoke不允许访问导出的数据(变量),例如函数指针。你需要一个DLL内的帮助器,一个包装函数指针的导出函数,或一个返回它的函数(返回类型将被视为C#中的一个委托)。

答案 1 :(得分:0)

感谢您的输入

我已经通过修改我的回调注册解决了这个问题:

void RegisterCB()
{
    var ret = TdiapiFacade.RegisterEventCallback(OnTdiCallBack, new IntPtr());
    HandleError(ret);
}

到此:

private TDIAPI.TDICallBack callback;
void RegisterCB()
{
    callback = new TDIAPI.TDICallBack(OnTdiCallBack);
    var ret = TdiapiFacade.RegisterEventCallback(callback , new IntPtr());
    HandleError(ret);
}

这解决了这个问题,现在我的回调被正确调用了。