2013-04-07 9 views
5

Ich versuche, eine Win32-DLL macht einige Funktionen zu erstellen, die in C# genannt werden alsPassing Byte-Array zwischen C++ und C# ByRef wirft Access

__declspec(dllexport) int GetData(unsigned char* *data, int* size) 
{ 
    try 
    { 
     int tlen = 3; 
     unsigned char* tchr = new unsigned char[5]; 
     tchr[0] = 'a'; 
     tchr[1] = 'b'; 
     tchr[2] = 'c'; 

     *size = tlen; 
     *data = tchr; 

     return 1; 
    } 
    catch (char *p) 
    { 
     return 0; 
    } 
} 

folgt und auf C# Seite

[DllImport("MyDll.dll")] 
static extern int GetData(ref byte[] data, ref int size); 

static void Main() 
{ 
    try 
    { 
     int hr = 0; 
     byte[] gData = null; 
     int gSize = 0; 
     hr = GetData(ref gData, ref gSize); 
     Console.WriteLine(gSize); 
     for (int i = 0; i < gSize; i++) 
      Console.WriteLine((char)gData[i]); 
    } 
    catch (Exception p) 
    { 
     Console.WriteLine(p.ToString()); 
    } 
} 

Wenn Ich laufe C# -Code, AccessViolationException geschieht auf GetData Funktion, die ein Zeichen der Ausnahme in C++ - Code ist, jedoch nach C++ Code-Snippet funktioniert ohne Fehler.

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    unsigned char* data = NULL; 
    int size = NULL; 
    GetData(&data, &size); 
    printf("%d", size); 
    for (int i = 0; i < size; i++) 
     printf("%c,", data[i]); 
    return 0; 
} 

Wenn Sie C# main Funktion vergleichen und C++ _tmain, sind sie fast so analoger wo kann ich einen Fehler machen?

+0

Hoffe, das wird Ihnen helfen. http://StackOverflow.com/Questions/8199874/c-sharp-and-void-pointers –

Antwort

9

Sie geben ein Array zurück, das durch einen Aufruf von C++ neu zugeordnet wurde, und hoffen, dass der Marshaler es in ein C# -Byte [] umwandelt. Das wird nicht passieren.

Sie müssen einen Zeiger als Referenz übergeben und dann von Hand zuordnen. Ihre p/invoke sollte wie folgt aussehen:

[DllImport("MyDll.dll")] 
static extern int GetData(out IntPtr data, out int size); 

Wenn die Funktion zurückgibt Daten an das Array zeigen und Sie können den Inhalt mit der Marshal-Klasse lesen. Ich nehme an, Sie würden copy it to a new byte array.

var arr = new byte[size]; 
Marshal.Copy(data, arr, 0, size); 

Einige andere Punkte:

  1. Die Aufrufkonventionen nicht übereinstimmen. Die native Seite ist cdecl und die verwaltete ist stdcall.
  2. Sie müssen einen Deallocator exportieren, um den von der nativen Funktion zurückgegebenen Speicher zu löschen. Stellen Sie sich ein Re-Design vor, bei dem der Anrufer den Puffer zuweist.
+0

Dank Sie haben mich viel gespeichert – anonim

+0

... oder mit CoTaskMemAlloc/g_malloc in NAtive zuweisen und Marshal.FreeCoTaskMem auf zurückgegebenen IntPtr in verwaltet –