C#でパックされた構造体のアンマネージバッファをマーシャリングする方法

StackOverflow https://stackoverflow.com/questions/506231

質問

次の 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);

アウトバッファ パラメータには、C で次のように定義される、任意の数の構造体 (次々にパックされる) が設定されます。

typedef struct _BAH_RECORD {

    int evt
    int len;
    WCHAR name[1];

} BAH_RECORD, *PBAH_RECORD;

名前 フィールドには、可変長の NULL で終わる Unicode 文字列が割り当てられます。の レン フィールドには、構造体の合計サイズ (名前文字列を含む) がバイト単位で示されます。アンマネージ側での構造体の処理方法には何の問題もないと確信しています。

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() への引数として使用します...文字列は正常に出力されるので、間違いなくそこにありますが、マーシャラーにそれを正しく処理させることができないようです(たとえそれがあったとしても)できる?)

助けていただければ幸いです

スティーブ

役に立ちましたか?

解決

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top