meisse - Mi 06.07.11 17:58
Titel: C# --> Zugriff auf unmanaged Speicher (C++)
Hallo zusammen
Folgendes ist gegeben: Aus dem C# Code wird eine Methode aus einer C++ DLL aufgerufen, um Daten anzufordern. Mit den Attributen der Methode definiere ich welche Daten ich gerne haben möchte. Zusätzlich gebe ich ein callback delegate mit. In der C++ DLL werden dann die Daten aufbereitet und in ein array abgespeichert, welches folgendermassen deklariert ist:
C#-Quelltext
1:
| uint8_t* m_dataBlock = new uint8_t[1024]; |
Das callback delegate sieht folgendermassen aus:
C#-Quelltext
1:
| typedef void (TPC_CC *TPC_DataStreamCallback)(void *DataPtr, int DataLength); |
Wenn das Datenarray 'm_dataBlock' gefüllt wurde, wird die callback methode aufgerufen:
C#-Quelltext
1: 2: 3:
| if(m_StreamBufferSize > 0) { m_callback(m_dataPtr, 1024); } |
In meiner C# Applikation wird danach die callback methode aufgerufen, mit welcher ich dann gerne auf das Array zugreifen möchte:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| public static void DispatchRawDataStream(IntPtr DataPtr, int DataLength) { Int32[] data = new Int32[DataLength]; GCHandle gcHandleData = GCHandle.FromIntPtr(DataPtr); data = (Int32[])gcHandleData.Target;
lock (StreamQueueObj.lockObj) { StreamQueueObj.DataChunk.Enqueue(data); } } |
Nur mit dieser Variante bekomme ich folgende Exception: ArgumentException überschreitet eine systemeigene/verwaltete Grenze. GCHandle kann nicht zwischen AppDomains übergeben werden.
Kann mir da jemand weiterhelfen?
Mit freundlichen Grüssen
Ralf Jansen - Mi 06.07.11 19:59
Ich vermute das C++ Array liegt auf dem unmanaged Heap und ist damit für C# nicht direkt erreichbar. Du musst den Speicherinhalt des Array erst auf den managed Heap kopieren um ihn verwenden zu können. Da hilft z.B. eine der
Marshal.Copy [
http://msdn.microsoft.com/de-de/library/ms146635.aspx] Überladungen.
Ist uint8_t nicht einfach ein Byte? Wie passt das zu Int32? Wäre da auf .Net Seite nicht auch ein Byte Array sinnvoller?
meisse - Do 07.07.11 08:34
Das ganze hat funktioniert mit dem Marshal.Copy Befehl:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| public static void DispatchRawDataStream(IntPtr DataPtr, int DataLength) { byte[] data = new byte[DataLength]; Marshal.Copy(DataPtr, data, 0, DataLength);
lock (StreamQueueObj.lockObj) { } } |
Jetzt muss ich nur noch die Daten richtig interpretieren.
Mit freundlichen Grüssen