C# p - вызов функции C

Я был бы признателен за помощь в решении проблемы, на которой я застрял пару дней.

У меня есть родной тип функции C++, объявленный так:

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

где PEventCallback а также PEVENT объявлены так:

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 ответа

P/invoke не разрешает доступ к экспортируемым данным (переменным), таким как указатель вашей функции. Вам понадобится помощник внутри DLL, либо экспортируемая функция, которая оборачивает указатель функции, либо функция, которая ее возвращает (возвращаемый тип будет рассматриваться как делегат внутри C#).

Спасибо за ваш вклад

Я решил проблему, изменив регистрацию моего обратного вызова из:

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

Это решает проблему, теперь мой обратный вызов правильно вызывается.

Другие вопросы по тегам