2013-04-07 5 views
5

Sto cercando di creare una DLL Win32 espone alcune funzioni che sono chiamati in C# come seguePassaggio array di byte tra C++ e C# ByRef solleva AccessViolationException

__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; 
    } 
} 

E su C# lato

[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()); 
    } 
} 

Quando Eseguo il codice C#, AccessViolationException avviene sulla funzione GetData che è un segno di eccezione nel codice C++, tuttavia, seguendo lo snippet di codice C++ funziona bene senza errori.

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; 
} 

Se si confrontano C# main funzione e C++ _tmain, sono quasi analoga aperta in modo da dove mi possono fare un errore?

+0

Spero che questo ti possa aiutare. http://stackoverflow.com/questions/8199874/c-sharp-and-void-pointers –

risposta

9

Si sta restituendo un array assegnato da una chiamata a C++ nuovo e si spera che il gestore di marshalling lo trasformi in un byte C# []. Non succederà.

È necessario passare un puntatore per riferimento e quindi effettuare il marshalling a mano. Il tuo P/Invoke dovrebbe assomigliare a questa:

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

Quando i dati funzione ritorna punterà alla matrice e si può leggere il contenuto utilizzando la classe Marshal. Immagino che tu voglia copy it to a new byte array.

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

Alcuni altri punti:

  1. Le convenzioni di chiamata non corrispondono. Il lato nativo è cdecl e il managed è stdcall.
  2. È necessario esportare un deallocator per eliminare la memoria restituita dalla funzione nativa. Considera una riprogettazione in cui il chiamante assegna il buffer.
+0

Grazie per avermi salvato molto – anonim

+0

... o assegnarlo con CoTaskMemAlloc/g_malloc in NAtive e utilizzare Marshal.FreeCoTaskMem su IntPtr restituito in gestione –