2009-02-03 7 views
2

J'appelle (avec succès) la fonction Windows FilterSendMessage en C# en utilisant la signature PInvoke suivante:Comment le maréchal tampon non géré de struct emballés dans C#

[DllImport("fltlib.dll")] 
    public static extern IntPtr FilterSendMessage(
     IntPtr hPort, 
     IntPtr inBuffer, 
     UInt32 inBufferSize, 
     IntPtr outBuffer, 
     UInt32 outBufferSize, 
     out UInt32 bytesReturned); 

Le paramètre outBuffer est rempli avec un nombre arbitraire de structs (emballés l'un après l'autre), comme définis dans C:

typedef struct _BAH_RECORD { 

    int evt 
    int len; 
    WCHAR name[1]; 

} BAH_RECORD, *PBAH_RECORD; 

le champ de nom se voit attribuer une longueur variable, unicode nul à terminaison str ing. Le champ len décrit la taille totale de la structure en octets (y compris la chaîne de nom). Je suis convaincu qu'il n'y a rien de mal à la façon dont les structures sont manipulées dans le côté non géré des choses.

Mon problème se pose quand je tente de maréchal outBuffer à une instance de la struct BAH_RECORD, défini dans C# comme:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
public struct BAH_RECORD 
{ 
    public UInt32 evt; 
    public UInt32 len; 
    public string name; 
} 

IntPtr outBuffer = Marshal.AllocHGlobal(OUT_BUFFER_SIZE); 

hResult = Win32.FilterSendMessage(hPortHandle, inBuffer, IN_BUFFER_SIZE, outBuffer, OUT_BUFFER_SIZE, out bytesReturned); 

BAH_RECORD bah = (BAH_RECORD)Marshal.PtrToStructure(outBuffer, typeof(BAH_RECORD)); 

<snip> 

Si j'essayer et voir/imprimer/affichage bah.name, je reçois des ordures

Pour confirmer que outBuffer contient réellement des données valides, j'ai fait un peu de hackery de pointeur brut dans C# pour l'appeler, en appelant Marshal.ReadInt32 deux fois (pour couvrir les 2 premiers champs struct), puis Marshal.ReadByte quelques fois pour remplir un octet [] que j'utilise ensuite comme argument de Encoding.Unicode.GetString() ... la chaîne sort bien, donc c'est définitivement là , Je juste ne peux pas obtenir le placier pour gérer correctement (si elle peut même?)

Toute aide appréciée

Steve

Répondre

1

Le problème est que la chaîne « nom » dans votre C# La structure BAH_RECORD est marshalée comme un pointeur sur une chaîne (WCHAR *) mais sur le côté C c'est un tampon WCHAR en ligne. Ainsi, quand vous marshalez votre structure, le moteur d'exécution lit les quatre premiers octets du tampon comme un pointeur, puis tente de lire la chaîne vers laquelle il pointe.

Malheureusement, il n'y a aucun moyen pour l'exécution de marshaler automatiquement les tampons de taille variable à l'intérieur des structs, vous devrez donc utiliser le marshaling manuel (ou comme vous le dites "hackery de pointeur"). Mais lorsque vous avancez le pointeur pour pointer sur le tampon, vous n'avez pas besoin de lire individuellement les octets, puis de les convertir en une chaîne - appelez Marshal.PtrToStringUni.

+0

PtrToStringUni fonctionne très bien. Merci pour la suggestion :) – TheLearningCurve

Questions connexes