【问题标题】:C# pInvoke to a C functionC# pInvoke 到 C 函数
【发布时间】:2023-04-05 04:37:01
【问题描述】:

如果我解决了几天的问题,我将不胜感激。

我有一个这样声明的原生 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() 似乎工作成功,但在应该调用回调函数的地方,应用程序崩溃了。如您所见,在这个阶段我什至没有解开提供给回调函数的参数。

我需要做什么才能完成这项工作?

【问题讨论】:

  • 与您的断言相反,C 代码没有声明任何函数。如果它完全是有效的 C(这对我和 CDECL 来说似乎很可疑),那么它将 T_TED_AcppBoxDYN_RegisterEventCallback 声明为函数 typealias。也许它是有效的 C++,但即使在这种情况下,它也必须声明一个类型别名,而不是该类型的实际函数或函数指针。
  • STATUS 是如何定义的?
  • 您不能直接从 C# 调用非托管 C++ 实例函数。因为您没有 this 指针。此外,您的TDICallback 代表必须是 Cdecl。您将需要 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] 属性。见stackoverflow.com/questions/5155180/…
  • typedef int STATUS; //!
  • @Jim:他试图调用的函数似乎不是成员函数。

标签: c# pinvoke


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    感谢您的意见

    我已经解决了这个问题,方法是修改我的回调注册:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      • 2010-10-26
      • 1970-01-01
      • 2021-02-19
      • 1970-01-01
      相关资源
      最近更新 更多