2010-10-15 4 views
13

Ich verwende API in C++ geschrieben in meinem Code (Schreiben in C#). API benötigt einen Parameter als Zeiger auf Struktur. Die Struktur besteht aus „Int“ s und Char Arrays: beispielÜbergabe einer Struktur an C++ API mit Marshal.StructureToPtr in C#

unsafe public struct ToBePassed 
    { 
     Int32 Num1; 
     Int32 Num2; 
     Char[] Data; // or fixed Char Data[255]; 
    } 

I kann nicht direkt mit der Struktur Zeiger auf API übergeben, da in diesem Fall I Störung erhalten als „Pointers nicht gemarshallt Strukturen verweisen kann“ . Code wird erfolgreich kompiliert, aber dieser Fehler kommt, wenn ich den Code ausführe (Debug).

Jetzt habe ich zwei Optionen: 1st: - Passing Struktur von Ref: Ich möchte fragen, eine API erfordert einen Struktur Pointer kann die Adresse erhalten, wenn ich die Struktur durch Ref übergeben. Beachten Sie, dass die API Daten in "Char [] Data" zurückgibt.

2.: - Verwendung von Marshal.StructureToPtr: Dies wird den Strukturzeiger in IntPtr konvertieren. Wieder ist der Zweifel gleich, Wird diese API korrekt empfangen?

Danke für Ihre Zeit!

Grüße, Swanand

Antwort

15

Wenn es Zeiger nur erfordert, können Sie einige nicht verwalteten Speicher, Marschall die Struktur in den Speicher zuweisen und diesen Zeiger auf Ihre Funktion übergeben. Danach können Sie sich zurück auf die Struktur begeben (wenn Sie möchten) und die Erinnerung freigeben. Bevor Sie etwas marshallen, müssen Sie die Struktur richtig definieren. Etwas wie folgt aus:

[StructLayout(
    LayoutKind.Sequential,  //must specify a layout 
    CharSet = CharSet.Ansi)] //if you intend to use char 
public struct ToBePassed 
{ 
    public Int32 Num1; 
    public Int32 Num2; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)] 
    public Char[] Data; //specify the size using MarshalAs 
} 

[DllImport("...")] 
public static extern void APICall(IntPtr argPtr); 


public static void CallFunction(ToBePassed managedObj) 
{ 
    IntPtr unmanagedAddr = Marshal.AllocHGlobal(Marshal.SizeOf(managedObj)); 

    Marshal.StructureToPtr(managedObj, unmanagedAddr, true); 

    APICall(unmanagedAddr); 

    Marshal.PtrToStructure(unmanagedAddr, managedObj); 

    Marshal.FreeHGlobal(unmanagedAddr); 
    unmanagedAddr = IntPtr.Zero; 
} 

[Bearbeiten]
variabler Länge Arrays zu simulieren, zuteilen nicht verwalteten Speicher innerhalb der Struktur und initialisieren wie gewohnt.

[StructLayout(LayoutKind.Sequential)] 
public struct SomeStruct 
{ 
    public Int32 X; 
    public Int32 Y; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct VLA 
{ 
    public Int32 intArrayLength; 
    public Int32 SomeStructArrayLength; 
    public IntPtr intArray; 
    public IntPtr SomeStructArray; 
} 

public static VLA CreateVLA(int[] intArray, SomeStruct[] SomeStructArray) 
{ 
    var vla = new VLA() 
    { 
     intArrayLength = intArray.Length, 
     SomeStructArrayLength = SomeStructArray.Length, 
     intArray = Marshal.AllocHGlobal(intArray.Length * Marshal.SizeOf(typeof(int))), 
     SomeStructArray = Marshal.AllocHGlobal(SomeStructArray.Length * Marshal.SizeOf(typeof(SomeStruct))), 
    }; 
    Marshal.Copy(intArray, 0, vla.intArray, intArray.Length); 
    //there's no overload to copy arbitrary arrays, do it manually 
    for (int i = 0; i < SomeStructArray.Length; i++) 
    { 
     Marshal.StructureToPtr(
      SomeStructArray[i], 
      vla.SomeStructArray + i * Marshal.SizeOf(typeof(SomeStruct)), 
      true); 
    } 
    return vla; 
} 
+0

Vielen Dank sehr sehr! Das war großartig!! Eine Frage, kann die API Daten im Char Array zurückgeben? – Swanand

+0

AFAIK, ja. Die nicht verwaltete API kann den Speicher wie jeden anderen Speicher verwenden, da sie nicht verwaltet wird. In diesem Fall würden Sie die Struktur zurückmelden, um das Ergebnis in den verwalteten Code zurückzuversetzen. –

+0

Das funktioniert gut .... Aber ich bin mit einem weiteren Problem konfrontiert, jetzt möchte ich Daten an die API übergeben (sagen WriteToAPI Version der oben genannten API) Ich werde jetzt Daten an API übergeben. Da diese Char-Daten jedoch nicht die Größe 255 haben (ich möchte Daten variabler Größe übergeben), wird der Fehler "Typ kann nicht Marshalled sein, da die Länge einer Embedded-Array-Instanz nicht mit der angegebenen Länge im Layout übereinstimmt" – Swanand