在 x64 中从指针编组结构
Marshalling a struct from pointer in x64
我有三个结构:
[StructLayout(LayoutKind.Sequential)]
internal struct COPYDATASTRUCT
{
public IntPtr dwData; // Specifies data to be passed
public int cbData; // Specifies the data size in bytes
public IntPtr lpData; // Pointer to data to be passed
}
public struct SHELLTRAYDATA
{
public UInt32 dwUnknown;
public UInt32 dwMessage;
public NID_XX nid;
}
public struct NID_XX
{
public UInt32 cbSize;
public IntPtr hWnd;
public uint uID;
public uint uFlags;
public uint uCallbackMessage;
public IntPtr hIcon;
}
在我的 WndProc 中,我执行以下操作:
case WM_COPYDATA:
{
COPYDATASTRUCT cp = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
if(cp.dwData == SH_TRAY_DATA)
{
var shellTrayData = (SHELLTRAYDATA)Marshal.PtrToStructure(cp.lpData,typeof(SHELLTRAYDATA));
HandleNotification(shellTrayData);
}
}
当我的应用程序在 x86 上 运行ning 时它工作正常。当我在 x64 上 运行 它时,我没有得到 hIcon,而且 hWnd 无效。当我将应用程序定位到 x86 和 x64 上的 运行 时,它工作正常。我知道问题出在编组上。我必须手动编组结构吗?在这方面需要帮助。我更愿意为 x64 和 x86
使用相同的结构
编辑:
非托管结构如下:
typedef struct tagCOPYDATASTRUCT
{
ULONG_PTR dwData;
DWORD cbData;
_Field_size_bytes_(cbData) PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
// data sent by shell via Shell_NotifyIcon
typedef struct _SHELLTRAYDATA
{
DWORD dwUnknown;
DWORD dwMessage;
NID_XX nid;
} *PSHELLTRAYDATA;
// sub structure common to all others
typedef struct
{
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
} NID_XX, *PNID_XX;
typedef const NID_XX * PCNID_XX;
编辑:
结构的大小如下:
非托管:
- 复制数据结构:12(X86) 和 24(x64)
- 外壳托盘数据:32(X86) 和 48(X64)
- NID_XX: 24(X86) 和 40(X64)
托管:
- 复制数据结构:12(X86) 和 24(x64)
- 外壳托盘数据:32(X86) 和 48(X64)
- NID_XX: 24(X86) 和 40(X64)
两边都一样
这些结构因不同的架构而异。 IntPtr
值是 32 位宽或 64 位宽,具体取决于体系结构。这对成员的规模有明显的影响,对对齐的影响可能不太明显。
无论体系结构如何,您都无法使用相同的结构。您需要了解这两个流程的架构。每当发送方和接收方的架构不同时,你就有麻烦了。
您可以选择固定布局,使用 C# long
而不是 IntPtr
。 HWND
和 HICON
等类型将始终适合 C# long
。尽管要提防仅在特定过程中有意义的句柄类型。例如,HICON
值在您将它们发送到不同进程后将没有意义。
我想我会序列化而不是使用固定的布局结构。例如,序列化您希望发送到 JSON 的数据。这可以很容易地打包成一个字符串并通过 WM_COPYDATA
.
发送
因为句柄在 64 位版本上是 64 位的,而我们收到的结构仍然包含 32 位。将 hIcon 和 hWnd 的 IntPtr 更改为 Uint32 就可以了。现在这个结构适用于 x64 和 x86 架构。我一直都知道序列化到 JSON 肯定偏离了我的要求。感谢大家的帮助。
我有三个结构:
[StructLayout(LayoutKind.Sequential)]
internal struct COPYDATASTRUCT
{
public IntPtr dwData; // Specifies data to be passed
public int cbData; // Specifies the data size in bytes
public IntPtr lpData; // Pointer to data to be passed
}
public struct SHELLTRAYDATA
{
public UInt32 dwUnknown;
public UInt32 dwMessage;
public NID_XX nid;
}
public struct NID_XX
{
public UInt32 cbSize;
public IntPtr hWnd;
public uint uID;
public uint uFlags;
public uint uCallbackMessage;
public IntPtr hIcon;
}
在我的 WndProc 中,我执行以下操作:
case WM_COPYDATA:
{
COPYDATASTRUCT cp = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
if(cp.dwData == SH_TRAY_DATA)
{
var shellTrayData = (SHELLTRAYDATA)Marshal.PtrToStructure(cp.lpData,typeof(SHELLTRAYDATA));
HandleNotification(shellTrayData);
}
}
当我的应用程序在 x86 上 运行ning 时它工作正常。当我在 x64 上 运行 它时,我没有得到 hIcon,而且 hWnd 无效。当我将应用程序定位到 x86 和 x64 上的 运行 时,它工作正常。我知道问题出在编组上。我必须手动编组结构吗?在这方面需要帮助。我更愿意为 x64 和 x86
使用相同的结构编辑:
非托管结构如下:
typedef struct tagCOPYDATASTRUCT
{
ULONG_PTR dwData;
DWORD cbData;
_Field_size_bytes_(cbData) PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
// data sent by shell via Shell_NotifyIcon
typedef struct _SHELLTRAYDATA
{
DWORD dwUnknown;
DWORD dwMessage;
NID_XX nid;
} *PSHELLTRAYDATA;
// sub structure common to all others
typedef struct
{
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
} NID_XX, *PNID_XX;
typedef const NID_XX * PCNID_XX;
编辑: 结构的大小如下:
非托管:
- 复制数据结构:12(X86) 和 24(x64)
- 外壳托盘数据:32(X86) 和 48(X64)
- NID_XX: 24(X86) 和 40(X64)
托管:
- 复制数据结构:12(X86) 和 24(x64)
- 外壳托盘数据:32(X86) 和 48(X64)
- NID_XX: 24(X86) 和 40(X64)
两边都一样
这些结构因不同的架构而异。 IntPtr
值是 32 位宽或 64 位宽,具体取决于体系结构。这对成员的规模有明显的影响,对对齐的影响可能不太明显。
无论体系结构如何,您都无法使用相同的结构。您需要了解这两个流程的架构。每当发送方和接收方的架构不同时,你就有麻烦了。
您可以选择固定布局,使用 C# long
而不是 IntPtr
。 HWND
和 HICON
等类型将始终适合 C# long
。尽管要提防仅在特定过程中有意义的句柄类型。例如,HICON
值在您将它们发送到不同进程后将没有意义。
我想我会序列化而不是使用固定的布局结构。例如,序列化您希望发送到 JSON 的数据。这可以很容易地打包成一个字符串并通过 WM_COPYDATA
.
因为句柄在 64 位版本上是 64 位的,而我们收到的结构仍然包含 32 位。将 hIcon 和 hWnd 的 IntPtr 更改为 Uint32 就可以了。现在这个结构适用于 x64 和 x86 架构。我一直都知道序列化到 JSON 肯定偏离了我的要求。感谢大家的帮助。