Ich habe zwei C++ - Strukturen wie unten gezeigt. Ich muss die Struktur beim Aufrufen einer DLL-Methode aus C# abrufen.Marshalling verschachtelte Strukturen
sie beispielsweise in C, wie unten ermöglicht definieren ++ Code:
struct A
{
int count;
struct B;
}
struct B
{
char* id;
char* name;
}
C++ Code kehrt die folgende Methode
A* GetData();
Verfahren, das ich brauche von C# nennen hat die folgende Signatur:
IntPtr GetData();
Diese Methode gibt den Zeiger auf Struktur A Füllung Anzahl in Struktur A, ID und Namen von struct B.
In C# definiere ich diese Strukturen als Klassen:
[StructLayout(LayoutKind.Sequential)]
class A
{
public int count;
public IntPtr B;
}
[StructLayout(LayoutKind.Sequential)]
class B
{
public string id;
public string name;
}
Ich habe ein C++ DLL erstellt von C# zu nennen. Wenn ich versuche, Daten aus der verschachtelten Struktur (A->B->id)
zu lesen, erhalte ich einen Leseverletzungsfehler (AccessViolationException)
.
Wie kann ich die verschachtelte Struktur zuordnen, damit ich sie in der C# -Methode lesen kann?
Mein C# -Code ist als unten
[DllImport("Win32Project.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern IntPtr GetData();
A setting = new A();
setting.B = new IntPtr();
IntPtr deviceSettingptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(A)));
IntPtr settingsInfoptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(B)));
Marshal.StructureToPtr(setting, deviceSettingptr, false);
Marshal.StructureToPtr(setting.B, settingsInfoptr, true);
setting.B= settingsInfoptr;
deviceSettingptr = GetData();
setting = (A)Marshal.PtrToStructure(deviceSettingptr, typeof(A));
B info = (B)Marshal.PtrToStructure(setting.B, typeof(B));
Console.WriteLine(string.Format("Setting count={0}", setting.count));
Console.WriteLine(string.Format("Setting id={0}, Setting name={1}", info.id, info.name));
Wie greife ich auf die Mitglieder der Struktur B id und Namen haben?
Warte, also ist 'A.b' ein Zeiger auf' B' oder nur 'B'? – Luaan
Das A.B Mitglied ist eine Struktur, kein Zeiger. Sie müssen es stattdessen als B deklarieren. Die Strings in B sind ein sehr bedeutendes Speicherverwaltungsproblem, jemand muss sie wieder freigeben. Der pinvoke-Marshaller kann das nicht, Sie müssen sie daher als IntPtr deklarieren und Marshal.PtrToStringAnsi() verwenden. Wie wirst du die Erinnerung loslassen, nun, viel Glück. Ähnliches gilt für den Rückgabewert von GetData(), auch hohe Chancen, dass dies ein dangling pointer ist. Verbessern Sie den C++ - Code zuerst, es ist nicht verwendbar wie es ist. –
Ich deklarierte Zeichenfolgen in Struktur B als IntPtr und verwendet unten, um die Daten zurück zu erhalten. Zeichenfolgen-ID = Marshal.PtrToStringAnsi (info.id); Aber das ist eine leere Zeichenfolge. –