Entwickler-Ecke

Sonstiges (.NET) - C# --> Zugriff auf unmanaged Speicher (C++)


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 00:02

Ok danke, werde ich morgen gleich ausprobieren.

Ja das stimmt. uint8_t ist ein unsigned char. Da hab ich was falsch verstanden. Werde mich wieder melden sobald alles funktioniert.

Mit freundlichen Grüssen


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) {
                //StreamQueueObj.DataChunk.Enqueue(data);
            }
        }


Jetzt muss ich nur noch die Daten richtig interpretieren.

Mit freundlichen Grüssen