Questo funziona:Come eseguire il marshalling sulla stringa ANSI tramite l'attributo?
[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetError")]
private static extern IntPtr SDL_GetError();
public static string GetError()
{
return Marshal.PtrToStringAnsi(SDL_GetError());
}
Questo crash:
[DllImport("SDL2.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetError")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetError();
This article suggerisce che l'attributo di ritorno è essenzialmente come chiamare Marshal.PtrToStringAnsi
, quindi qual è il problema?
Come Daniel pointed out, è probabilmente perché il crash marshaller sta tentando di liberare la memoria. L'articolo afferma anche,
N.B. Nota: il lato non gestito non deve utilizzare la parola chiave "new" o la funzione "malloc()" C per allocare memoria. L'Interop Marshaler non sarà in grado di liberare la memoria in queste situazioni. Questo perché la "nuova" parola chiave dipende dal compilatore e la funzione "malloc" dipende dalla libreria C.
Ho provato liberare il puntatore char con Marshal.FreeHGlobal
, Marshal.FreeCoTaskMem
e Marshal.FreeBSTR
- tutti crash. Non ci sono altri modi per liberare la memoria AFAIK, quindi suppongo che la memoria sia stata allocata tramite new
o malloc()
. Quindi, adesso, sono intrappolato? Ho una perdita di memoria permanente nel mio programma?
Ho controllato la fonte. La stringa viene creata tramite static char errmsg[SDL_ERRBUFIZE]
. La mia C è arrugginita, ma suppongo che sia dichiarata come static
in modo che non venga liberata quando esce dall'ambito della funzione. Non ricordo dove gli array statici vivono in memoria-terra però; c'è un modo per liberarli?
Modifica: Attendi ... è statico. Ciò significa che ogni volta che c'è un nuovo errore sovrascriverà il vecchio messaggio di errore, quindi perché SDL_GetError()
restituisce solo il messaggio di errore più recente. Ergo, non devo preoccuparmi di liberarlo.
In questo modo, se tutte le opzioni return: MarshalAs...
tentano di liberare la memoria, l'unica soluzione è la mia attuale. Questo è ottimale dopo tutto.
Sì, se è statico, la memoria non deve essere liberata. Quindi l'unico modo è quello di effettuare il marshalling manuale, altrimenti il marshaller CLR libererà la memoria. –