2012-04-20 10 views
2

私のバッファ内のいくつかの値がどこから来ているのか、そしてなぜSystem.ExecutionEngineExceptionが得られているのか分かりません。マネージマーシャリングのネイティブはランダムな値を持っています

ここに私の場合です: 私のシステムでは、名前付きパイプを通じて管理対象のサービスと通信するネイティブアプリケーションがあります。ネイティブアプリケーションは、以下の構造体によって保持されたデータを送信するためにWriteFile(pipehandle, &msg, sizeof(msg), &cbBytes, NULL)を使用しています。

struct NotificationMessageHeader 
{ 
    __int32 A; 
    __int64 B; 
    __int32 MessageType; 
    __int32 D; 
}; 

struct NotificationMessageA 
{ 
    NotificationMessageHeader Header; 
    unsigned char X; 
    wchar_t Y[MAX_PATH]; 
}; 

マネージドサービスは、次のようになり、これらの構造の管理バージョンを、持っている:

[StructLayout(LayoutKind.Sequential)] 
public struct NotificationMessageHeader 
{ 
    public UInt32 A; 
    public UInt64 B; 
    public UInt32 MessageType; 
    public UInt32 D; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct NotificationMessageA 
{ 
    public NotificationMessageHeader Header; 
    [MarshalAs(UnmanagedType.I1)] 
    public byte X; 
    [MarshalAs(UnmanagedType.LPWStr)] 
    public string Y; 
} 

Iからデータを送信していますネイティブアプリケーション、私が最初にすることは、一般的な構造にバッファを読み込まれます。メッセージの種類が何であるかを判断し、私は確信している番目の後にする

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
public struct GenericNotificationMessage 
{ 
    public NotificationMessageHeader Header; 
} 

メッセージタイプがサポートされている時、私はこの機能を使用して適切な構造としてそのバッファの残りをデコード:

T GetMessageAsStructure<T>(object data) 
     where T : struct 
    { 
     T output = default(T); 
     GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); 
     try 
     { 
      IntPtr dataPtr = handle.AddrOfPinnedObject(); 
      output = (T)Marshal.PtrToStructure(dataPtr, typeof(T)); 
     } 
     finally 
     { 
      handle.Free(); 
     } 
     return output; 
    } 

を再び - GetMessageAsStructureへの2つのコールがあります。 1つは型引数としてGenericNotificationMessageは、ヘッダーのみをデコードし、正しく動作 - 私は期待どおりのヘッダーフィールドに値を取得しています。次に、メッセージが私がサポートしているタイプであることが分かった場合は、GetMessageAsStructureとtypeパラメータ(この場合はNotificationMessageA)を呼び出します。

...ここでは状況が悪くなり始めます。 CLRはアクセス違反の例外で失敗します。

NotificationMessageA msg = { }; 
    memset(&msg, 0, sizeof(msg)); 

    msg.Header.A = 2; 
      msg.Header.B = 999; 
    msg.Header.MessageType = 1; 
    msg.Header.D = 3; 
    msg.X = 64; 
    wcscpy(msg.Y, L"somexec.exe"); 

    DWORD written = 0; 
    WriteFile(_hPipe, &msg, sizeof(msg), &written, NULL); 

管理バッファは、次の値があります:

[0] 2 <---- This shouldn't be at index 3? 
[1] 0 
[2] 0 
[3] 0 
[4] 0 
[5] 0 
[6] 0 
[7] 0 
[8] 231 <--- WTF is this? should't it start at index 11? 
[9] 3 
[10] 0 
[11] 0 
[12] 0 
[13] 0 
[14] 0 
[15] 0 
[16] 1 
[17] 0 
[18] 0 
[19] 0 
[20] 3 
[21] 0 
[22] 0 
[23] 0 
[24] 64 
[25] 0 
[26] 115 
[27] 0 
[28] 111 
[29] 0 
[30] 109 
[31] 0 
[32] 101 
[33] 0 
[34] 101 
[35] 0 
[36] 120 
[37] 0 
[38] 101 
[39] 0 
[40] 99 
[41] 0 
[42] 46 
[43] 0 
[44] 101 
[45] 0 
[46] 120 
[47] 0 
[48] 101 
[49] 0 
[50] 0 

私はしかし、私はのようなものを送るとき、私は、私は、管理側で持っているバッファ内の値であり、例えば見てみました私が= { }を使用しているので、C++でメンバーワイズ初期化をデフォルト値にして、整列された構造体に影響を与えないので、おそらく私はそこにゴミを入れているかもしれませんが、memset(..., 0, ...)を使ってもそうではないからです受信バイトに影響を与えます。

さらに、ヘッダーだけが完全に復号化されます。構造体の残りの部分をデコードしようとしているときにのみ、文字列がSystem.ExecutionEngineExceptionになります。

また、管理されたバッファは、自分の構造を見て、そこにあることが予想されるものを保持しません。

なぜですか?

困ったことは、スローされたものがExecutionEngineExceptionであることをVisual Studioが報告していることです。MSDNでは、この例外はランタイムによってもうスローされず、廃止されていると言います。

この文字列をデシリアライズするときに間違っているのは何ですか?ポインタではなく、あなたがポインタとしてNotificationMessageA.Yをマーシャリングしているが、ネイティブコードで、それは構造内部のバッファである

答えて

4

、あなたは、MIMOの答えに加えてUnmanagedType.ByValTStr

+0

が働い完全に!ありがとうございました。 –

2

を使用する必要があります。

Index 0 to 3: MessageHeader.A, little endian 
Index 4 to 7: padding, since B must be 8 byte aligned 
Index 8 to 15: B, little endian 
... 
Index 24: X 
Index 25: padding 
Index 26: start of the wchar_t array Y, but will be incorrectly interpreted as a pointer 
+0

それは今意味がある...ありがとう! –

関連する問題