Ich schreibe einen C# -Wrapper für eine native Bibliothek. Es enthält dieses Callback-Funktion:C# nativer Rückruf mit Zeiger auf Strukturparameter
typedef application_event_result(*application_event_ptr)(application_request* request);
Der Parameter als solche definiert ist:
typedef struct {
uint32_t query;
const char* client;
bool isAuthenticated;
bool isGuest;
} application_request;
I die C# Rückruf definiert haben Delegierten wie folgt aus:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate application_event_result application_event([MarshalAs(UnmanagedType.Struct)]
ref application_request request);
Die Struktur in C#:
[StructLayout(LayoutKind.Sequential)]
public struct application_request
{
public UInt32 query;
[MarshalAs(UnmanagedType.LPStr)]
public string client;
[MarshalAs(UnmanagedType.I1)]
public bool isAuthenticated;
[MarshalAs(UnmanagedType.I1)]
public bool isGuest;
}
Das alles scheint zu funktionieren. Der Rückruf in C# wird ausgelöst, und die Mitglieder der Struktur haben die erwarteten Werte.
Bei der Rückkehr zu systemeigenem Code wird jedoch eine Heap-Korruptionsausnahme ausgelöst (0xc0000374).
Offensichtlich möchte ich das vermeiden.
Wenn ich die C# -Rückrufsignatur so ändern, dass IntPtr anstelle des Parameters "ref application_request" verwendet wird, und Marshal es manuell mit dem folgenden Code ausführen, funktioniert es.
var request = Marshal.PtrToStructure<application_request>(requestptr);
Aber ich möchte die Unterschrift so genau wie möglich haben und nicht den Marshaler selbst verwenden müssen.
Gibt es eine Möglichkeit für mich, die Unterschrift des Callback-Delegierten zu ändern, damit .net die Struktur automatisch konvertieren kann?
Der Fehler tritt auf, weil die Größe des Rückgabeparameters nicht konsistent ist. IntPtr ist vier Bytes, also müssen Sie in C# den Rückgabeparameter als vier Bytes deklarieren. Die Position des Zeigers muss auch im statischen Speicherbereich liegen, damit sowohl der c- als auch der C# -Code zusammenarbeiten können. Ein IntPtr funktioniert, da er sich in nicht verwaltetem statischem Speicher befindet. Ein C# -Objekt wird verwaltet, das einen Fehler verursacht, wenn es in nicht verwaltetem Speicherbereich platziert wird. – jdweng
Das Problem besteht nicht mit dem Rückgabewert, sondern mit dem Eingabeparameter pointer-to-struct. Gibt es eine Möglichkeit, das zu markieren, so dass es in nicht verwalteten Platz gebracht wird? – RasmusW
@jdweng der Rückgabewert sieht aus wie ein Enum Nein? –