2016-07-28 33 views
4

Ich versuche, die Antwort auf this questionPInvoke - ein Array von Strukturen von Zeiger Marschall

Meine Struktur sieht wie folgt aus in C

typedef struct drive_info_t { 
    unsigned char drive_alias[32]; 
} drive_info_t; 

Meine Funktion sieht wie folgt in C

zu folgen
unsigned int get_drive_info_list(drive_info_t **list, unsigned int *item_count) { 
    //fill list in native C 

    //print out in native C 
    printf("list.alias - %s\r\n",list[i]->drive_alias); 
} 

Mein C# struct sieht aus wie dieses

[StructLayout(LayoutKind.Sequential)] 
public struct drive_info_t 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
    public byte[] drive_alias; 
} 

Meine C-Deklaration # Funktion sieht wie folgt aus

[DllImport("mydll.dll", EntryPoint = "get_drive_info_list", CallingConvention = CallingConvention.Cdecl)] 
public static extern uint GetDriveInfoList(out System.IntPtr ptr_list_info, out System.IntPtr ptr_count); 

ich C# Funktion wie diese

IntPtr ptr_list_info = IntPtr.Zero; 
IntPtr ptr_cnt = IntPtr.Zero; 

ret = api.GetDriveInfoList(out ptr_list_info, out ptr_cnt); 

Aufruf ich die zurückgegebenen Zeiger wie diese

nAlloc = ptr_cnt.ToInt32(); 

int szStruct = Marshal.SizeOf(typeof(api.drive_info_t)); 
api.drive_info_t[] localStructs = new api.drive_info_t[nAlloc]; 

for (int i = 0; i < nAlloc; i++) 
{ 
    localStructs[i] = (api.drive_info_t)Marshal.PtrToStructure(ptr_list_info, typeof(api.drive_info_t)); 
    ptr_list_info = new IntPtr(ptr_list_info.ToInt32() + (szStruct)); 
} 

Marshalling das Drucken struct alias wie dieser

for (uint i = 0; i < localStructs.Length; i++) 
{  
    Console.WriteLine("list.alias - {0}", System.Text.Encoding.Default.GetString(localStructs[i].drive_alias)); 
} 

Danke für den Aufenthalt bei mir ..

So sieht meine Ausgabe auf einer Konsolenanwendung in C# aus. Sie können die native C dll Druck auf die Konsole sehen es Werte gibt, aber meine Serialisieren ist vermasselt irgendwo:

======================== C values ============================ 
list.alias - drv1 
list.alias - drv2 
list.alias - drv3 
list.alias - drv4 
======================== C# values ============================ 
list.alias - drv1 
list.alias - o£Q95drv2 
list.alias -   o£Q95drv3 
list.alias -     o£Q95drv4 

Ich habe keine Ahnung, wo dieser Müll Text und Offset herkommt.

Ich bin für die .Net-Seite verantwortlich, andere Teammitglieder können bei Bedarf das native C ändern, aber native C-Änderungen müssen plattformübergreifend OSX/Windows/Linux sein.

Vielen Dank im Voraus.

+0

Aus Neugier, was passiert, wenn Sie '[StructLayout (LayoutKind.Sequential)]' zu '[StructLayout (LayoutKind.Sequential, Pack = 5)]' '? – itsme86

+0

Pack = 5 ist kein gültiger Wert, ich habe auch versucht, 1, 2, 4, 8 Werte ohne Änderung zu durchlaufen. – ScottN

+0

Ich frage mich ... Wenn Sie die IntPtr zu UIntPtr und alle Referenzen von ToInt32 zu UInt32 ändern. Ich weiß, manchmal kann es unwichtig erscheinen, aber ... –

Antwort

1

Dies ist ein perfektes Beispiel dafür, warum die Typen der Argumente die Schnittstelle nicht definieren. Betrachten

drive_info_t **list 

Dies könnte ein Zeiger auf ein Array von Strukturen sein. In diesem Fall wird das Array vermutlich vom Angerufenen zugewiesen. Deshalb wird ein Zeiger auf ein Array im Gegensatz zu einem Array verwendet.

Oder es könnte ein Array von Zeigern zu struct sein. Hier würde das Array vom Aufrufer zugewiesen werden und die Strukturen könnten entweder von Angerufenem oder Anrufer zugewiesen werden. Keine Möglichkeit für uns zu erzählen.

Wir können erkennen, dass Ihre Schnittstelle ein Array von Zeigern zu struct akzeptiert. Schauen Sie sich diesen Code:

list[i]->drive_alias 

Ganz klar list ist ein Array von Zeigern auf struct.

Das sagt Ihnen, dass Ihr Code falsch ist. Sie sind der falschen Vorlage gefolgt, weil Sie die Semantik falsch identifiziert haben. Ihr nächster Schritt besteht darin, zu der Dokumentation für die Schnittstelle und zu jedem Beispielaufrufcode zurückzukehren, um genau zu erfahren, was die Semantik ist. Wer hat was zugewiesen und was freigegeben?

Mit ziemlicher Sicherheit verwenden Sie IntPtr[], um das Array zu marshalieren, aber darüber hinaus ist es für uns unmöglich zu sagen, was passiert. Ich würde vermuten, dass der Anrufer die Strukturen zuweist, aber nicht auf Raten angewiesen ist. Lesen Sie die Dokumentation und den Beispiel-Aufrufcode.

Darüber hinaus sollte das zweite Argument ref uint oder vielleicht out uint abhängig von der Semantik der Funktion sein. Auch das können wir nicht herausfinden.

+0

'Mit Sicherheit verwenden Sie IntPtr [], um das Array zu marshallen, ja, ich habe am Ende die Deklaration in' [In, Out] System.IntPtr [] ptr_list_info' und auch den 2. Parameter für uint geändert. Vielen Dank! – ScottN