我有一段C ++代码,它使用Common Controls Tree View窗口消息读出树项的文本(包含在普通TVM_GETITEM中)。接收消息的树视图处于不同的进程中,因此我使用一点共享内存作为窗口消息的一个参数所指向的结构。我必须做这项工作,因为远程进程不在我的控制之下(我正在编写一个类似于Spy ++的应用程序)。
原则上这很有效,但如果目标流程有很大不同,则会失败:
如果目标进程的代码是使用UNICODE定义但我自己的代码没有构建的,那么这两个进程将对TVITEM structure中字符串成员的结构有不同的看法。我已经使用IsWindowUnicode调用解决了这个问题,然后明确地发送TVM_GETITEMA
或TVM_GETITEMW
(必要时重新编码结果)。
如果调用进程是以32位模式构建的,并且目标进程是64位(或反过来),则TVITEM structure结构的布局(和大小)是不同的,因为指针有不同的大小
我目前正在努力寻找解决第二个问题的好方法。这个特定的用例(获取树项文本)只是一个例子,我的代码发送的其他窗口消息也存在同样的问题。现在,我正在考虑两种方法:
还有其他人必须解决类似的问题吗?有更简单的解决方案吗?
答案 0 :(得分:1)
我最终在运行时检查远程进程是32位还是64位,然后在发送消息之前将正确的结构写入共享内存。
例如,即使存在32位< - >,也可以使用TVM_GETITEM
消息。呼叫者和接收者之间的64位混音:
/* 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位远程进程也可以访问它)。
答案 1 :(得分:0)
恕我直言,有一个设计问题。我不知道你为什么这样做,也许你不能完全控制所有部分。但是在基本的MVC视角中,您正在从视图中查看值,而不是将其提交给模型。
答案 2 :(得分:0)
我不熟悉这个特定的消息,但是如果Windows TVM_GETITEM消息应该在进程间正常运行,那么Windows应该在调用者的地址空间中填写TVITEM结构并为您处理任何所需的转换,而不需要你提供共享内存。如果不是,那么我怀疑你在这里看到的问题很容易解决,没有一些不舒服的扭曲。
共享内存位让我困惑;通常你必须让两个进程明确地知道共享内存段,并且你没有提到DLL注入或类似的东西。被调用者究竟如何知道其地址空间中的共享内存部分,以及如何使用它?你确定这个API需要吗?