Domanda

Quindi ho una base di codice C ++ nativa di terze parti con cui sto lavorando (file .lib e .hpp) che ho usato per creare un wrapper in C ++ / CLI per un eventuale utilizzo in C #.

Ho riscontrato un problema particolare durante il passaggio dalla modalità Debug alla modalità di rilascio, in quanto ottengo un'eccezione di violazione di accesso quando viene restituito un codice di callback.

Il codice dai file hpp originali per il formato della funzione di callback:

typedef int (*CallbackFunction) (void *inst, const void *data);

Codice dal wrapper C ++ / CLI per il formato della funzione di callback: (Spiegherò perché ne ho dichiarati due in un momento)

public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);

- Rapidamente, il motivo per cui ho dichiarato un secondo " UnManagedCallbackFunction " è che ho provato a creare un "intermediario" callback nel wrapper, quindi la catena è cambiata da Native C ++ > C # a una versione di C ++ nativo > C ++ / CLI Wrapper > C # ... Divulgazione completa, il problema persiste, è stato appena inviato al wrapper C ++ / CLI ora sulla stessa riga (il ritorno).

E infine, il codice che si blocca da C #:

public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData)
    {
        Console.WriteLine("in hReceiveLogEvent...");
        Console.WriteLine("pInstance: {0}", pInstance);
        Console.WriteLine("pData: {0}", pData);

        // provide object context for static member function
        helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target;
        if (hw == null || pData == null)
        {
            Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n");
            return 0;
        }

        // typecast data to DataLogger object ptr
        IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
        DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;

        //Do Logging Stuff

        Console.WriteLine("exiting hReceiveLogEvent...");
        Console.WriteLine("pInstance: {0}", pInstance);
        Console.WriteLine("pData: {0}", pData);
        Console.WriteLine("Setting pData to zero...");
        pData = IntPtr.Zero;
        pInstance = IntPtr.Zero;
        Console.WriteLine("pData: {0}", pData);
        Console.WriteLine("pInstance: {0}", pInstance);

        return 1;
    }

Tutte le scritture sulla console sono terminate e al ritorno vediamo il temuto crash:

  

Eccezione non gestita a 0x04d1004c in   helloworld.exe: 0xC0000005: accesso   posizione di lettura della violazione 0x04d1004c.

Se entro nel debugger da qui, tutto ciò che vedo è che l'ultima voce nello stack di chiamate è: > & Quot; 04d1004c () " che valuta un valore decimale di: 80805964

Il che è interessante solo se guardi la console che mostra:

entering registerDataLogger
pointer to callback handle: 790848
fp for callback: 2631370
pointer to inst: 790844
in hReceiveLogEvent...
pInstance: 790844
pData: 80805964
exiting hReceiveLogEvent...
pInstance: 790844
pData: 80805964
Setting pData to zero...
pData: 0
pInstance: 0

Ora, so che tra il debug e il rilascio alcune cose sono piuttosto diverse nel mondo Microsoft. Sono ovviamente preoccupato per il riempimento dei byte e l'inizializzazione delle variabili, quindi se c'è qualcosa che non sto fornendo qui, fammelo sapere e lo aggiungerò al post (già lungo). Penso anche che il codice gestito NON stia rilasciando tutta la proprietà e quindi il materiale nativo C ++ (per il quale non ho il codice) potrebbe tentare di eliminare o eliminare l'oggetto pData, causando il crash dell'app.

Ulteriori informazioni complete, tutto funziona bene (apparentemente) in modalità Debug!

Un vero problema di graffio alla testa che apprezzerebbe qualsiasi aiuto!

È stato utile?

Soluzione

Penso che lo stack sia stato schiacciato a causa di convenzioni di chiamata non corrispondenti: prova a mettere l'attributo

 [UnmanagedFunctionPointer(CallingConvention.Cdecl)]

sulla dichiarazione del delegato di callback.

Altri suggerimenti

Questo non risponde direttamente alla tua domanda , ma può portarti nella giusta direzione per quanto riguarda la modalità di debug va bene contro la modalità di rilascio non va bene:

  

Dato che il debugger aggiunge molte informazioni di conservazione dei registri allo stack, generalmente completando le dimensioni e il layout del mio programma in memoria, sono stato & # 8220; a essere fortunato & # 8221; in modalità debug scarabocchiando oltre 912 byte di memoria che non erano molto importanti. Senza il debugger, tuttavia, stavo scarabocchiando su cose piuttosto importanti, alla fine uscendo dal mio spazio di memoria, facendo sì che Interop cancellasse la memoria che non possedeva.

Qual è la definizione di DataLoggerWrap? Un campo char potrebbe essere troppo piccolo per i dati che stai ricevendo.

Non sono sicuro di ciò che stai cercando di ottenere.

Alcuni punti:

1) Il garbage collector è più aggressivo in modalità di rilascio, quindi con cattiva proprietà il comportamento che descrivi non è insolito.

2) Non capisco cosa stia cercando di fare il codice seguente?

IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;

Usi GCHandle.Alloc per bloccare un'istanza di DataLoggerWrap in memoria, ma poi non la passi mai a non gestita, quindi perché la blocchi? Inoltre non lo hai mai liberato?

La seconda riga riprende quindi un riferimento: perché il percorso circolare? perché il riferimento - non lo usi mai?

3) Hai impostato IntPtrs su null - perché? - questo non avrà alcun effetto al di fuori dell'ambito della funzione.

4) È necessario sapere qual è il contratto di callback. Chi possiede pData il callback o la funzione di chiamata?

Sono con @jdehaan, tranne CallingConvetion.StdCall potrebbe essere la risposta, specialmente quando la lib di terze parti è scritta in BC ++, per esempio.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top