Sto cercando di creare un involucro a una DLL C e sto provando a chiamare una funzione che ha prende una funzione di callback, riceve un oggetto come un puntatore che viene passato indietro.Come chiamare una funzione in un ++ Dll C da C# che ha void * richiamata e oggetto parametro
file h delares
extern int SetErrorHandler(void (*handler) (int, const char*, void*),
void *data_ptr);
Il gestore è una funzione di callback che viene chiamata quando si verifica un errore e il data_ptr è un qualsiasi oggetto (stato) che viene passato di nuovo a voi, nel caso del mio app che sarà solo questo (oggetto corrente).
Sono in grado di chiamare le funzioni in una DLL che utilizza tipi costanti di tipo marshalling come semplici stringhe, int, ecc. Ma non riesco a capire come eseguire il marshalling di un puntatore su un oggetto C# che è lo stato.
Per passare il riferimento all'oggetto alla funzione C da quello che ho trovato cercando qui e altrimenti mi sembra di aver bisogno di un tipo di struttura per poter eseguire il marshalling alla funzione, così ho creato una struttura per contenere il mio oggetto :
[StructLayout(LayoutKind.Sequential)]
struct MyObjectState
{
public object state;
}
EDIT: ho provato a mettere un attributo: [MarshalAs(UnmanagedType.Struct, SizeConst = 4)]
sulla proprietà public object state
, ma questo produce lo stesso errore, quindi rimosso, doesnt sembra che funzionerebbe comunque.
La struct contiene una proprietà oggetto singolo per contenere qualsiasi oggetto per la funzione di richiamata.
ho dichiarato il delegato in C# come segue:
delegate void ErrorHandler(int errorCode, IntPtr name, IntPtr data);
Poi ho dichiarato la funzione di importazione in C# come segue:
[DllImport("somedll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int SetErrorHandler handler, IntPtr data);
Poi ho creato una funzione di callback nel mio codice C#:
Sono in grado di chiamare la funzione di libreria come indicato di seguito:
var state = new MyObjectState()
{
state = this
};
IntPtr pStruct = Marshal.AllocHGlobal(Marshal.SizeOf(state));
Marshal.StructureToPtr(state, pStruct, true);
int ret = SetErrorHandler(MyErrorHandler, pStruct);
Le opere di chiamata e la funzione di callback viene chiamata, ma non sono in grado di accedere ai dati nella funzione di callback e quando provo Marshal.PtrToStructure
ottengo un errore:
The structure must not be a value class.
ho fatto un sacco di ricerca qui e abbiamo trovato diverse cose su Marshall e void *, ma niente mi ha aiutato a farlo funzionare
Grazie.
In questo caso è vero, infatti non ho davvero bisogno di passare questo ai dati come sarà disponibile nel mio callback dell'oggetto, ma volevo fornire la chiamata corretta alla funzione per quando l'utente vuole fornire un contesto. Immagino che la gestione dei dati possa essere gestita dall'oggetto C# per mantenere lo stato/contesto. Quindi immagino che questo risolva il mio problema, ma suppongo che la domanda originale su come o sia possibile passare l'oggetto rimanga senza risposta – Andre
Non si vuole davvero passare un riferimento a un oggetto C# nella mia vista. Ricorda che gli oggetti gestiti possono essere spostati da GC. Hai intenzione di forzare tali oggetti a essere appuntati? E cosa può fare il codice nativo con una cosa del genere? È completamente opaco. Si potrebbe usare 'ObjectIDGenerator' per ottenere un ID univoco per ciascun oggetto, ma personalmente penso che la tua domanda sia affrontata meglio spostandola lateralmente! –
Quello che dici ha senso, e credo che la risposta sia: non farlo/evitalo, potrebbe non essere impossibile ma non dovresti, grazie – Andre