在 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;

编辑: 结构的大小如下:

非托管:

  1. 复制数据结构:12(X86) 和 24(x64)
  2. 外壳托盘数据:32(X86) 和 48(X64)
  3. NID_XX: 24(X86) 和 40(X64)

托管:

  1. 复制数据结构:12(X86) 和 24(x64)
  2. 外壳托盘数据:32(X86) 和 48(X64)
  3. NID_XX: 24(X86) 和 40(X64)

两边都一样

这些结构因不同的架构而异。 IntPtr 值是 32 位宽或 64 位宽,具体取决于体系结构。这对成员的规模有明显的影响,对对齐的影响可能不太明显。

无论体系结构如何,您都无法使用相同的结构。您需要了解这两个流程的架构。每当发送方和接收方的架构不同时,你就有麻烦了。

您可以选择固定布局,使用 C# long 而不是 IntPtrHWNDHICON 等类型将始终适合 C# long。尽管要提防仅在特定过程中有意义的句柄类型。例如,HICON 值在您将它们发送到不同进程后将没有意义。

我想我会序列化而不是使用固定的布局结构。例如,序列化您希望发送到 JSON 的数据。这可以很容易地打包成一个字符串并通过 WM_COPYDATA.

发送

因为句柄在 64 位版本上是 64 位的,而我们收到的结构仍然包含 32 位。将 hIcon 和 hWnd 的 IntPtr 更改为 Uint32 就可以了。现在这个结构适用于 x64 和 x86 架构。我一直都知道序列化到 JSON 肯定偏离了我的要求。感谢大家的帮助。