2

C文字配列のマーシャリングに問題があります。私は次のC#構造を持っています:

[StructLayout(LayoutKind.Explicit, Size = 16, CharSet = CharSet.Ansi), Serializable]
internal struct Header
{
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 4)]
    [FieldOffset(0)]
    public string header;

    [FieldOffset(4)]
    public int version;

    [FieldOffset(8)]
    public int diroffset;

    [FieldOffset(12)]
    public int direntries;
}

ストリームからこの構造を読み取るための次のコード:

public static T ReadStruct<T>(this Stream stream) where T : struct
{
    var sz = Marshal.SizeOf(typeof(T));
    var buffer = new byte[sz];
    stream.Read(buffer, 0, sz);

    var pinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned);

    var structure = (T) Marshal.PtrToStructure(
        pinnedBuffer.AddrOfPinnedObject(), typeof(T));

    pinnedBuffer.Free();
    return structure;
}

今私の問題はheader、構造体が読み取られた後、フィールドが文字を見逃していることです。構造体が読み取られるファイルには4バイトが含まれていますが、構造体がヘッダー文字列VPVPによって読み取られた後は、のみが含まれます。デバッガーの読み取り関数のバイト配列を見ると、その配列には値86、80、86、80が含まれています。これはです。私も使ってみましたが、何も変わりませんでした。ReadStructVPVVPVPLayoutKind.SequentialStructLayout

何か間違ったことをしているのですか、それとも文字列に文字がないのですか?

4

1 に答える 1

4

あなたが抱えている問題は、バイトを書き込むことではなく、構造体の定義にあります。

問題はここにあります:

[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 4)]

あなたが言ったように、あなたVPVPは4文字の長さのテキストを書いていると思います。ただし、これは当てはまりません。Cでは、文字列を次のように宣言できます。

char mystring[] = { 'V', 'P', 'V', 'P', '\0' };

\0文字列の終わりをマークするには、最後にヌル文字()が必要です。マーシャリング時にこれを考慮する必要があります。これは、その「ヌルターミネータバイト」用のスペースを予約する必要があるためです。予約しない場合、C#文字列によって使用可能なメモリに追加され、最後の文字が失われます。 。したがって、nullで終了する文字列を使用する場合は、長さ5にする必要があります。


編集:これは、ヌルターミネータについて心配する必要がなく、char[](そして魔法の16バイトサイズも維持する)より良い解決策です:

[StructLayout(LayoutKind.Explicit, Size = 16, CharSet = CharSet.Ansi), Serializable]
internal struct Header
{
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 4)]
    [FieldOffset(0)]
    private char[] headerCharArray;

    public string header
    {
        get { return new string(headerCharArray); }
        set
        {
            if (value.Length == 4)
            {
                headerCharArray = value.ToArray();
            }
            else
            {
                throw new InvalidOperationException("String length was not 4.");
            }
        }
    }

    [FieldOffset(4)]
    public int version;

    [FieldOffset(8)]
    public int diroffset;

    [FieldOffset(12)]
    public int direntries;
}

そうchar[]すれば、はメモリに保存され、構造体自体のメモリを使用しないプロパティを介して文字列としてアクセスできます。

于 2013-01-31T18:16:59.747 に答える