Question

Je suis (avec succès) appeler la fonction Windows FilterSendMessage en C # en utilisant la signature PInvoke suivante:

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

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

typedef struct _BAH_RECORD {

    int evt
    int len;
    WCHAR name[1];

} BAH_RECORD, *PBAH_RECORD;

Nom est affectée une longueur variable, chaîne de caractères unicode zéro terminal. len champ 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 avec la façon dont les struct sont traité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 je tente de bah.name voir / imprimer / écran, je reçois des ordures ...

Pour confirmer que outBuffer ne contient effectivement des données valides, je l'ai fait un peu de pointeur brut carriole en c # à l'étape si elle, appelant Marshal.ReadInt32 deux fois (pour couvrir les 2 premiers struct champs), puis Marshal.ReadByte quelques fois à un octet remplir [] que je puis utiliser comme argument pour Encoding.Unicode.GetString () ... la chaîne sort bien, il est donc sans aucun doute là-dedans, je ne peux pas sembler obtenir le placier pour gérer correctement ( si elle peut même?)

Toute aide appréciée

Steve

Était-ce utile?

La solution

Le problème est que la chaîne « nom » dans votre struct C # BAH_RECORD est marshalé comme pointeur sur une chaîne (WCHAR *), mais sur le côté C est un tampon de WCHAR en ligne. Alors, quand vous, maréchal votre struct l'exécution lit les quatre premiers octets du tampon comme un pointeur, puis tente de lire la chaîne qu'il pointe.

Malheureusement, il n'y a aucun moyen pour le moteur d'exécution marshaler automatiquement des tampons de taille variable à l'intérieur struct de sorte que vous devrez utiliser marshaling manuel (ou comme vous le dites « pointeur hack »). Mais quand vous avancez le pointeur pour pointer vers la mémoire tampon vous n'avez pas besoin de lire dans les octets individuellement, puis les convertir en une chaîne -. Il suffit d'appeler Marshal.PtrToStringUni

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top