2013-01-16 6 views
6

supponga che v'è una funzione nativa con un'interfaccia puro-C come il seguente, esportata da una DLL nativa:Gli attributi P/Invoke [In, Out] sono facoltativi per gli array di marshalling?

// NativeDll.cpp 

extern "C" void __stdcall FillArray(
    int fillValue, 
    int count, 
    int* data) 
{ 
    // Assume parameters are OK... 

    // Fill the array 
    for (int i = 0; i < count; i++) 
    { 
     data[i] = fillValue; 
    } 
} 

Il seguente P/Invoke funziona bene (testato con VS2010 SP1):

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)] 
public static extern void FillArray(
    int fillValue, 
    int count, 
    [In, Out] int[] data 
); 

così come questo P/Invoke, come sopra, ma senza il [In, Out] attributi:

[DllImport("NativeDll.dll", CallingConvention=CallingConvention.StdCall)] 
public static extern void FillArray(
    int fillValue, 
    int count, 
    int[] data 
); 

Quindi, sono quelli [In, Out] attributi facoltativo per gli array di marshalling? Qual è il loro scopo, se esiste? E 'OK ometterli nelle nostre dichiarazioni P/Invoke?

risposta

16

No, non sono esattamente opzionale. Succede semplicemente di lavorare per caso. È comunque un incidente molto comune. Funziona perché l'array non viene effettivamente eseguito il marshalling. Il marshaller di pinvoke vede che l'array C# è già compatibile con l'array nativo, quindi ignora il passaggio per crearne una copia. Si limita semplicemente l'array e passa il puntatore al codice nativo.

Questo è ovviamente molto efficiente e si otterranno inevitabilmente i risultati perché il codice nativo sta scrivendo direttamente gli elementi dell'array. Quindi, né gli attributi [In] né [Out] sono importanti.

Diventa molto più oscuro se il tipo di elemento dell'array non è così semplice. Non è così facile identificare un tipo di elemento che è una struct o un tipo di classe che non è blittable o il cui layout non corrisponde dopo il marshalling, quindi il marshaller pinvoke ha per creare una copia dell'array. Soprattutto l'incompatibilità del layout può essere molto difficile da identificare perché il layout gestito non è rintracciabile. E può cambiare a seconda del jitter che viene utilizzato. Può funzionare in x86 ma non in x64, ad esempio, piuttosto brutto quando viene selezionato AnyCPU. Per fare in modo che copia la copia modificata di nuovo nell'array C# , è necessario che richieda [Out].

Non so cosa dire, a parte il fatto che nessuno è mai stato licenziato per essere esplicito nelle loro dichiarazioni. Forse dovresti essere sempre esplicito quando il tipo di elemento dell'array non è semplice, quindi non avrai mai un incidente.

+1

Ugh ... Ho passato così tante ore della mia vita a risolvere problemi di marshalling effup tra x86/x64/'Any CPU' ... – JerKimball