我很难理解缓冲区中的某些值来自何处以及为什么会出现 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;
}
当我从本机应用程序发送数据时,我要做的第一件事是将缓冲区读入通用结构:
[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
. 一个作为类型参数的获取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++ 中使用 which 将成员初始化为默认值并且不影响对齐填充结构,但事实并非如此,因为即使使用memset(..., 0, ...)
也不是影响接收到的字节。
另外,仅当我尝试解码结构的其余部分时,仅对标头进行了完美解码,该字符串具有我得到 System.ExecutionEngineException 的字符串。
通过查看我的结构,托管缓冲区也不包含我期望它在那里拥有的东西 - 。
为什么?
更令人费解的是,Visual Studio 报告抛出的是 ExecutionEngineException,而 MSDN 说这个异常不再是运行时抛出的,它已经过时了。
反序列化该字符串时我做错了什么?