c++ - 通过 SendMessage 进行 IPC 时如何处理 32 位/64 位不匹配?

标签 c++ windows winapi sendmessage

我有一段 C++ 代码,它使用 Common Controls Tree View 窗口消息读出树项的文本(包含在普通 TVM_GETITEM 中)。接收消息的 TreeView 处于不同的进程中,因此我为窗口消息的一个参数指向的结构使用了一点共享内存。我必须做这项工作,因为远程进程不受我的控制(我正在编写一个类似于 Spy++ 的应用程序)。

这在原则上运作良好,但如果目标进程有很大不同,则会失败:

  1. 如果目标进程的代码是使用定义的 UNICODE 构建的,但我自己的代码没有定义,那么这两个进程将对 TVITEM structure 中字符串成员的结构有不同的想法。我已经使用 IsWindowUnicode 调用解决了这个问题,然后明确发送 TVM_GETITEMATVM_GETITEMW(必要时重新编码结果)。

  2. 如果调用进程是在 32 位模式下构建的,而目标进程是 64 位(或相反),则 TVITEM structure 结构的布局(和大小)是不同的,因为指针具有不同的大小。

我目前正在尝试找到解决第二个问题的好方法。这个特定的用例(获取树项目文本)只是一个例子,我的代码发送的其他窗口消息也存在同样的问题。现在,我正在考虑两种方法:

  1. 构建我的代码两次,然后根据目标进程执行的操作执行 32 位或 64 位代码。这需要对我们的构建和打包系统进行一些更改,并且需要将特定于体系结构的代码分解为专用进程(现在它在 DLL 中)。一旦完成,它应该会很好地工作。
  2. 在运行时检测目标进程的图像格式,然后使用自定义结构而不是明确使用 32 位或 64 位宽指针的 TVITEM structure 结构。这需要编写代码来检测远程进程的体系结构(我希望我可以通过在远程进程上调用 GetModuleFileName 然后使用 Image Help Library 分析 PE header 来做到这一点)并对两个结构进行硬编码(一个具有 32 位指针,一个具有 64 位) .此外,我必须确保共享内存地址在 32 位地址空间中(以便我自己的代码始终可以访问它,即使它是在 32 位模式下编译的)。

有其他人必须解决类似的问题吗?有更简单的解决方案吗?

最佳答案

我最终在运行时检查远程进程是 32 位还是 64 位,然后在发送消息之前将正确的结构写入共享内存。

例如,即使消息的调用者和接收者之间存在 32 位 <-> 64 位混合,您也可以使用 TVM_GETITEM 消息:

/* This template is basically a copy of the TVITEM struct except that
 * all fields which return a pointer have a variable type. This allows
 * creating different types for different pointer sizes.
 */
template <typename AddrType>
struct TVITEM_3264 {
  UINT      mask;
  AddrType  hItem;
  UINT      state;
  UINT      stateMask;
  AddrType  pszText;
  int       cchTextMax;
  int       iImage;
  int       iSelectedImage;
  int       cChildren;
  AddrType  lParam;
};
typedef TVITEM_3264<UINT32> TVITEM32;
typedef TVITEM_3264<UINT64> TVITEM64;

// .... later, I can then use the above template like this:
LPARAM _itemInfo;
DWORD pid;
::GetWindowThreadProcessId( treeViewWindow, &pid );
if ( is64BitProcess( pid ) ) {
    TVITEM64 itemInfo;
    ZeroMemory( &itemInfo, sizeof( itemInfo ) );

    itemInfo.mask = TVIF_HANDLE | TVIF_TEXT;
    itemInfo.hItem = (UINT64)m_item;
    itemInfo.pszText = (UINT64)(LPTSTR)sharedMem->getSharedMemory( sizeof(itemInfo) );
    itemInfo.cchTextMax = MaxTextLength;
    _itemInfo = (LPARAM)sharedMem->write( &itemInfo, sizeof(itemInfo) );
} else {
    TVITEM32 itemInfo;
    ZeroMemory( &itemInfo, sizeof( itemInfo ) );

    itemInfo.mask = TVIF_HANDLE | TVIF_TEXT;
    itemInfo.hItem = (UINT32)m_item;
    itemInfo.pszText = (UINT32)(LPTSTR)sharedMem->getSharedMemory( sizeof(itemInfo) );
    itemInfo.cchTextMax = MaxTextLength;
    _itemInfo = (LPARAM)sharedMem->write( &itemInfo, sizeof(itemInfo) );
}

sharedMem->getSharedMemory 函数是一个小辅助函数,用于获取指向共享内存区域的指针;可选的函数参数指定一个偏移值。重要的是共享内存区域应该始终在 32 位地址空间中(这样即使是 32 位远程进程也可以访问它)。

关于c++ - 通过 SendMessage 进行 IPC 时如何处理 32 位/64 位不匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4488053/

相关文章:

c++ - 将小部件从一个选项卡复制到另一个选项卡时的 QTabWidget

asp.net - 您实现/使用 WebDAV 有哪些经验?

c++ - 如何显示当前的IPv6连接?

perl - 如何在 Perl 中检查 .exe 或 .dll 的数字签名?

C++ 将 LARGE_INTEGER 转换为字符串

c++ - QtQuickControls,不适用于 Windows

c++ - 何时以及为什么使用#define 宏(x)而不是函数?

c++ - 子类化子窗口 C++

python - windows上新conda环境下无法打开jupyter笔记本

c - 我应该处理哪些错误?哪些是 "fatal"?