2010-11-17 9 views
1

J'essaye de marshal une structure d'un byte []. Chaque partie fonctionne sauf marshaling une chaîne. Il me ressemble comme un BSTR:Marshal.PtrToStructure chaîne marshaled est vide

06 00 00 00 48 00 65 00 6c 00 6c 00 6f 00 21 00 00 00 

Donc, c'est une longueur de 4 octets puis "Bonjour!" en unicode avec un double terminateur null. Voici le code de marshaling avec lequel j'ai joué:

string auto = Marshal.PtrToStringAuto(nextSchedulePtr); // returns "Hello!" 
string ansi = Marshal.PtrToStringAnsi(nextSchedulePtr); // returns "H" 
string uni = Marshal.PtrToStringUni(nextSchedulePtr); // returns "Hello!" 
string bstr = Marshal.PtrToStringBSTR(nextSchedulePtr); // returns "Hel" 
Schedule schedule = (Schedule)Marshal.PtrToStructure(nextSchedulePtr, typeof(Schedule)); // returns "" with UnmanagedType.BStr and UnmanagedType.LPWStr 

La méthode 1 appelle de toute façon la méthode 3, donc c'est logique. Cependant, je ne peux spécifier aucun type dans l'attribut [MarshalAs (UnmanagedType.X)] qui permettra à la structure de renvoyer quoi que ce soit de significatif.

J'épuré la structure à ceci:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct Schedule 
{ 
    [MarshalAs(UnmanagedType.BStr)] 
    public string Name; 
} 

J'ai littéralement essayé toutes les valeurs valides pour UnmanagedType.X et soit ils jette AccessViolationExceptions ou retourner une chaîne vide ou le retour indésirable. Aucun renvoie "Bonjour!". Suis-je incapable de charger ces données dans une structure?

Remarque: Je ne peux pas modifier les données, elles sont gravées dans la pierre. Je peux, cependant, changer mon code. J'ai également épinglé l'octet [] afin qu'il ne soit pas GC'ed.

Répondre

2

Le problème est que la struct Schedule vous définissez matchs ce genre de struct C:

struct Schedule { 
    BSTR *Name; 
}; 

Bien que la structure qui existe en mémoire au IntPtr vous bricolez avec a la mise en page:

struct Schedule { 
    BSTR Name; 
}; 

Si vous utilisez Marshal.StructureToPtr() sur une instance de Schedule puis d'inspecter la mémoire, vous verrez que seuls les quatre premiers octets sont définis, car il s'agit d'un pointeur.

Malheureusement, il n'existe pas de solution de contournement élégante dans .NET. Vous ne pouvez pas utiliser une chaîne sans pointeur dans une structure car la structure sera alors de longueur variable.

Si c'est une option, renoncez complètement à la structure et restez avec Marshal.PtrToStringAuto().

+0

Cela prend tout son sens maintenant que j'y pense. Je vous remercie. C'est énervant, mais au moins il y a une solution de contournement que je peux abstraire du code client. – Gary

+0

Yeh, interop avec le code non managé peut sucer. Au moins, vous avez affaire à P/Invoke et non à JNI ... – cdhowie

+0

Comment cela peut-il fonctionner avec une chaîne de taille fixe? – Tsury