2

次の pinvoke シグネチャを使用して、C# で Windows FilterSendMessage 関数を (正常に) 呼び出しています。

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

outBufferパラメーターには、C で次のように定義された任意の数の構造体 (次々にパック) が取り込まれます。

typedef struct _BAH_RECORD {

    int evt
    int len;
    WCHAR name[1];

} BAH_RECORD, *PBAH_RECORD;

nameフィールドには、可変長のヌル終了 Unicode 文字列が割り当てられます。lenフィールドは、構造体の合計サイズ (名前文字列を含む) をバイト単位で示します。管理されていない側で構造体がどのように処理されているかについては、何も問題はないと確信しています。

c# で次のように定義されている BAH_RECORD 構造体のインスタンスに outBuffer をマーシャリングしようとすると、私の問題が発生します。

[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>

bah.name を印刷/表示/表示しようとすると、ゴミが表示されます...

outBuffer に実際に有効なデータが含まれていることを確認するために、C# で大雑把なポインター ハッカーを実行して、Marshal.ReadInt32 を 2 回呼び出し (最初の 2 つの構造体フィールドをカバーするため)、次に Marshal.ReadByte を数回呼び出してバイトを入力しました。 [] を Encoding.Unicode.GetString() の引数として使用します...文字列は正常に出力されるので、間違いなくそこにあるので、マーシャラーに正しく処理させることができないようです (できる?)

どんな助けでも大歓迎

スティーブ

4

1 に答える 1

1

問題は、C# の BAH_RECORD 構造体の 'name' 文字列が文字列 (WCHAR*) へのポインターとしてマーシャリングされますが、C 側ではインライン WCHAR バッファーであることです。したがって、構造体をマーシャリングすると、ランタイムはバッファーの最初の 4 バイトをポインターとして読み取り、それが指す文字列を読み取ろうとします。

残念ながら、ランタイムが構造体内の可変サイズのバッファーを自動的にマーシャリングする方法がないため、手動でマーシャリングする必要があります (または、「ポインター ハッカリー」と言います)。ただし、ポインターを進めてバッファーを指す場合、バイトを個別に読み取ってから文字列に変換する必要はありません。Marshal.PtrToStringUni を呼び出すだけです。

于 2009-02-03T10:29:12.680 に答える