C3374: no se puede tomar la dirección de 'function' a menos que se cree una instancia delegada
Pregunta
Tengo dificultades para utilizar una función de registro de biblioteca de terceros para registrar una devolución de llamada. Estoy escribiendo en C ++ CLI y accediendo a una biblioteca escrita en C o C ++.
¿Qué significa el error del compilador anterior?
esta es la función de registro definida por el proveedor:
MYCO int WINAPI MyCo_Device_Register_CallbackFunc(LPVOID func, LPVOID lpParam, DWORD mask);
esta es la devolución de llamada definida por el proveedor:
typedef void (CALLBACK* MyCo_Device_CallbackProc)(DWORD ddStatus, LPVOID lpParam);
Mi función de devolución de llamada:
public ref class Device
{
void CallBackFunc(DWORD ddStatus, LPVOID lpParam) {};
}
Mi llamada (que falla):
MyCo_Device_Register_CallbackFunc((LPVOID) Device::CallBackFunc, nullptr, 0xFFFF);
Solución
Si tuviera que apostar una conjetura, está intentando tomar la dirección de una función ADMINISTRADA y pasarla como un indicador de función NATIVO. Eso no funcionará en absoluto. Escriba un puente nativo (más difícil y probablemente sin ventaja) o (y este es el enfoque más fácil), cree un delegado y use Marshal.GetFunctionPointerForDelegate . No olvide que el delegado tiene que permanecer vivo durante el tiempo que el código nativo espera volver a llamar, por lo que lo más probable es que deba almacenarlo en algún lugar.
Ah, y todas las funciones dentro de una clase de referencia o clase de valor son funciones administradas, en caso de que eso no esté claro.
[EDITAR] Ampliando respuesta para cubrir preguntas en comentarios. El primer paso es crear un delegado correspondiente. Para la función que proporcionó, se verá así:
public delegate void CallbackFuncDelegate(DWORD ddStatus, LPVOID lpParam);
Luego, deberás crear una:
CallbackFuncDelegate del = gcnew CallbackFuncDelegate(CallbackFunc);
Y como se mencionó anteriormente, debes guardar eso EN tu clase como miembro para asegurarte de que no desaparezca. Por último, debe obtener el puntero de la función y pasarlo:
MyCo_Device_Register_CallbackFunc((MyCo_Device_CallbackProc) Marshal::GetFunctionPointerForDelegate(del).ToPointer(), 0, 0);
Creo que eso cubre todo. Todo lo que necesitas es usar el sistema de espacio de nombres; y deberías estar bien.
Otros consejos
su función de devolución de llamada es un miembro: el puntero a los miembros y los punteros a las funciones son cosas diferentes.
Incluso en la solución de Promit:
CallbackFuncDelegate(CallbackFunc)
CallbackFunc no debe ser miembro de la clase
Puedes escribir simplemente
public ref class Device
{
static void CallBackFunc(DWORD ddStatus, LPVOID lpParam) {};
}
y luego use
Device::CallBackFunc