C3374: impossibile prendere l'indirizzo di 'funzione' a meno che non si crei un'istanza delegata
Domanda
Ho difficoltà a utilizzare una funzione di registrazione della libreria di terze parti per registrare un callback. Sto scrivendo in CLI C ++ e accedendo a una libreria scritta in C o C ++.
Cosa significa l'errore del compilatore sopra indicato?
questa è la funzione di registrazione definita dal venditore:
MYCO int WINAPI MyCo_Device_Register_CallbackFunc(LPVOID func, LPVOID lpParam, DWORD mask);
questo è il callback come definito dal fornitore:
typedef void (CALLBACK* MyCo_Device_CallbackProc)(DWORD ddStatus, LPVOID lpParam);
La mia funzione di richiamata:
public ref class Device
{
void CallBackFunc(DWORD ddStatus, LPVOID lpParam) {};
}
La mia chiamata (che non riesce):
MyCo_Device_Register_CallbackFunc((LPVOID) Device::CallBackFunc, nullptr, 0xFFFF);
Soluzione
Se dovessi scommettere un'ipotesi, stai provando a prendere l'indirizzo di una funzione GESTITA e passarlo come puntatore a funzione NATIVA. Non funzionerà affatto. Scrivi un bridge nativo (più difficile e probabilmente nessun vantaggio) oppure (e questo è l'approccio più semplice), crea un delegato e usa Marshal.GetFunctionPointerForDelegate . Non dimenticare che il delegato deve rimanere in vita per la durata che il codice nativo prevede di richiamare, quindi è molto probabile che sia necessario memorizzarlo da qualche parte.
Oh, e tutte le funzioni all'interno di una classe ref o di una classe di valore sono funzioni gestite, nel caso non fosse chiaro.
[MODIFICA] Risposta in espansione per coprire le domande nei commenti. Il primo passo è creare un delegato corrispondente. Per la funzione che hai fornito, sarà simile a questo:
public delegate void CallbackFuncDelegate(DWORD ddStatus, LPVOID lpParam);
Quindi, dovrai crearne uno:
CallbackFuncDelegate del = gcnew CallbackFuncDelegate(CallbackFunc);
E come notato in precedenza, dovresti archiviarlo nella tua classe come membro per assicurarti che non svanisca. Infine, è necessario ottenere il puntatore alla funzione e passarlo:
MyCo_Device_Register_CallbackFunc((MyCo_Device_CallbackProc) Marshal::GetFunctionPointerForDelegate(del).ToPointer(), 0, 0);
Penso che copra tutto. Tutto ciò che serve è usare il namespace System; e dovresti stare bene.
Altri suggerimenti
la funzione di callback è un membro - puntatore a membri e puntatori a funzioni sono cose diverse.
Anche nella soluzione di Promit:
CallbackFuncDelegate(CallbackFunc)
CallbackFunc non dovrebbe essere un membro di classe
Puoi scrivere semplicemente
public ref class Device
{
static void CallBackFunc(DWORD ddStatus, LPVOID lpParam) {};
}
e quindi utilizzare
Device::CallBackFunc