Marshalling un personnage ** en C #

J’interface avec le code qui prend un caractère char** (c’est-à-dire un pointeur sur une chaîne):

 int DoSomething(Whatever* handle, char** error); 

Fondamentalement, il prend une poignée à son état, et si quelque chose ne va pas, il renvoie un code d’erreur et éventuellement un message d’erreur (la mémoire est allouée en externe et libérée avec une deuxième fonction. Cette partie que j’ai trouvée :)).

Cependant, je ne suis pas sûr de savoir comment gérer en C #. Ce que j’ai actuellement:

 [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] private static unsafe extern int DoSomething(IntPtr handle, byte** error); public static unsafe int DoSomething(IntPtr handle, out ssortingng error) { byte* buff; int ret = DoSomething(handle, &buff); if(buff != 0) { // ??? } else { error = ""; } return ret; } 

J’ai fouillé, mais je ne vois pas comment transformer cela en byte[] , convenant à l’alimentation UTF8Encoding.UTF8.GetSsortingng()

Suis-je sur la bonne voie?

EDIT: pour rendre plus explicite, la fonction de bibliothèque alloue de la mémoire , qui doit être libérée en appelant une autre fonction de bibliothèque . Si une solution ne me laisse pas avec un pointeur que je peux libérer, la solution est inacceptable.

Question bonus: Comme implicite ci-dessus, cette bibliothèque utilise UTF-8 pour ses chaînes. Dois-je faire quelque chose de spécial dans mon P / Invokes, ou simplement utiliser ssortingng pour les parameters const char* normaux?

Vous devriez juste pouvoir utiliser une ref ssortingng et laisser le marshaller par défaut de l’exécution s’occuper de cette conversion pour vous. Vous pouvez indiquer la largeur de caractère sur le paramètre avec [MarshalAs(UnmanagedType.LPStr)] pour vous assurer que vous utilisez des caractères 8 bits.

Comme vous avez une méthode de désallocation spéciale à appeler, vous devez conserver le pointeur, comme vous l’avez déjà montré dans l’exemple de votre question.

Voici comment je l’écrirais:

 [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] private static unsafe extern int DoSomething( MySafeHandle handle, void** error); // byte** should work, too, I'm just lazy 

Ensuite, vous pouvez obtenir une chaîne:

 var errorMsg = Marshal.PtrToSsortingngAnsi(new IntPtr(*error)); 

Et le nettoyage:

 [DllImport("mydll.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int FreeMyMemory(IntPtr h); // ... FreeMyMemory(new IntPtr(error)); 

Et maintenant nous avons l’erreur marshalled, donc retournez-la.

 return errorMsg; 

Notez également le type MySafeHandle , qui hériterait de System.Runtime.InteropServices.SafeHandle . Bien que cela ne soit pas ssortingctement nécessaire (vous pouvez utiliser IntPtr), il vous donne une meilleure gestion des poignées lors de l’interopérabilité avec du code natif. Vous en saurez plus à ce sujet ici: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.aspx .

Pour référence, voici le code qui comstack ( mais, pas encore testé, le travail sur celui testé ensuite fonctionne à 100%) qui fait ce dont j’ai besoin. Si quelqu’un peut faire mieux, c’est ce que je recherche: D

 public static unsafe int DoSomething(IntPtr handle, out ssortingng error) { byte* buff; int ret = DoSomething(handle, &buff); if(buff != null) { int i = 0; //count the number of bytes in the error message while (buff[++i] != 0) ; //allocate a managed array to store the data byte[] tmp = new byte[i]; //(Marshal only works with IntPtrs) IntPtr errPtr = new IntPtr(buff); //copy the unmanaged array over Marshal.Copy(buff, tmp, 0, i); //get the ssortingng from the managed array error = UTF8Encoding.UTF8.GetSsortingng(buff); //free the unmanaged array //omitted, since it's not important //take a shot of whiskey } else { error = ""; } return ret; } 

Edit: correction de la logique dans la boucle while, il y avait une erreur par erreur.