2009-06-28 7 views
8

Ho bisogno del tuo aiuto con il seguente scenario:Come posso passare i dati MemoryStream a non gestito C++ DLL utilizzando P/Invoke

Sto leggendo alcuni dati da hardware in un MemoryStream (C#) e ho bisogno di passare questi dati in memoria di una dll implementata in C++ non gestito (usando il puntatore ??). I dati letti (nello stream) sono molto grandi (megabyte). Capisco che posso P/Richiamare questa DLL ma quello che non sono sicuro è come passare il puntatore/riferimento dei dati del flusso all'API C++?

Devo ammettere che sono confuso perché sono nuovo di C# - devo usare non sicuro/fisso poiché i dati sono grandi o non sono rilevanti in quanto l'oggetto MemoryStream è gestito da GC? Alcuni esempi di codice/descrizione dettagliata sarebbero molto utili. Grazie

Firma di API non gestito:

BOOL doSomething (void * rawData, int dataLength)

+0

Quale tipo di dati richiede la DLL C++? – scottm

+0

Richiede dati non elaborati - byte/void *. Posso modificare l'API dll come richiesto. –

risposta

12

se è solo in attesa di byte è possibile leggere il MemoryStream in un array di byte e poi passare un puntatore a che il metodo.

si deve dichiarare il metodo esterno:

[DllImport("mylibrary.dll", CharSet = CharSet.Auto)] 
public static extern bool doSomething(IntPtr rawData, int dataLength); 

Poi, leggere i byte dalla MemoryStream in una matrice di byte. Allocare un GCHandle cui:

Una volta assegnato, è possibile utilizzare un GCHandle per impedire l'oggetto gestito da essendo raccolto mediante la spazzatura collettore quando un client non gestito contiene il solo riferimento. Senza tale un handle, l'oggetto può essere ritirato dal garbage collector prima del che completa il suo lavoro per conto del client non gestito .

Infine, utilizzare il metodo AddrOfPinnedObject per ottenere un IntPtr da passare alla DLL C++.

private void CallTheMethod(MemoryStream memStream) 
{ 
    byte[] rawData = new byte[memStream.Length]; 
    memStream.Read(rawData, 0, memStream.Length); 

    GCHandle rawDataHandle = GCHandle.Alloc(rawData, GCHandleType.Pinned); 
    IntPtr address = handle.AddrOfPinnedObject(); 

    doSomething(address, rawData.Length); 
    rawDataHandle.Free(); 
} 
+0

Grazie. Sì, questo metodo è fondamentalmente per la compressione, quindi richiederà/opererà su dati grezzi passati ad esso. Anche i curiosi dati etichettati non sicuri sono posizionati su heap o stack in C#? –

+0

È lo stesso del codice non contrassegnato come non sicuro. – scottm

+0

Giusto per chiarire, questo codice non è considerato pericoloso. – scottm

Problemi correlati