2014-12-05 49 views
1

我将不胜感激,帮助解决一个问题,我一直坚持了几天。C#pInvoke到一个C函数

我有一个本地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; 

这是init稍后通过此代码ialized:

#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()似乎顺利进行,但在回调函数应该点被调用,应用程序崩溃。正如你所看到的,在这个阶段,我甚至没有解开提供给回调函数的参数。

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

+0

与您的断言相反,C代码不声明任何函数。如果它是有效的C(这对我和CDECL来说似乎很怀疑),那么它将'T_TED_AcppBoxDYN_RegisterEventCallback'声明为一个*别名*,用于函数*类型*。也许它是有效的C++,但即使在这种情况下,它也必须声明一个类型别名,而不是该类型的实际函数或函数指针。 – 2014-12-05 16:29:11

+0

如何定义'STATUS'? – Dennis 2014-12-05 16:47:10

+0

您不能直接从C#调用非托管C++实例函数。因为你没有'this'指针。另外,你的'TDICallback'委托必须是Cdecl。你需要'[UnmanagedFunctionPointer(CallingConvention.Cdecl)]'属性。请参阅http://stackoverflow.com/questions/5155180/changing-a-c-sharp-delegates-calling-convention-to-cdecl – 2014-12-05 16:50:10

回答

2

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

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); 
} 

此修复该问题,现在我的回调被正确调用。