我编写了一个函数,即使树视图位于远程过程中,也可以产生树视图项目的文本。该函数在远程过程中分配了两个内存的块,将TVITEM结构(已复制到远程过程中),发送TVM_GetItem消息,并最终将第二个远程内存块的内容发送回本地缓冲区。这是代码:

std::string getTreeViewItemText( HWND treeView, HTREEITEM item )
{
    DWORD pid;
    ::GetWindowThreadProcessId( treeView, &pid );

    HANDLE proc = ::OpenProcess( PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, pid );
    if ( !proc )
        // handle error

    TVITEM tvi;
    ZeroMemory( &tvi, sizeof(tvi) );

    LPVOID tvi_ = ::VirtualAllocEx( proc, NULL, sizeof(tvi), MEM_COMMIT, PAGE_READWRITE);
    if ( !tvi_ )
        // handle error

    TCHAR buffer[100] = { 'X' };

    LPVOID txt_ = ::VirtualAllocEx( proc, NULL, sizeof(buffer), MEM_COMMIT, PAGE_READWRITE );
    if ( !txt_ )
        // handle error

    tvi.mask = TVIF_TEXT | TVIF_HANDLE;
    tvi.pszText =  (LPTSTR)txt_;
    tvi.cchTextMax = sizeof(buffer) / sizeof(buffer[0] );
    tvi.hItem = item;

    if ( !::WriteProcessMemory( proc, tvi_, &tvi, sizeof(tvi), NULL ) )
        // handle error

    if ( !::SendMessage( treeView, TVM_GETITEM, 0, (LPARAM)tvi_ ) )
        // handle error

    if ( !::ReadProcessMemory( proc, (LPCVOID)txt_, buffer, sizeof( buffer ), NULL ) )
        // handle error

    ::VirtualFreeEx( proc, tvi_, 0, MEM_RELEASE );

    ::VirtualFreeEx( proc, txt_, 0, MEM_RELEASE );

    ::CloseHandle( proc );

    return buffer;
}

此代码与您在传递时获得的普通树视图非常好 WC_TREEVIEW 班级名称为 CreateWindow. 。但是,我注意到它与MS Common Controls V5(Comctl32.ocx)或MS Common Controls V6(MSCOMCTL.OCX)提供的新树不起作用。在这种情况下,返回的文本始终为空(缓冲区全部为零)。我还注意到sendmessage呼叫返回零(因此 // handle error 上面的评论启动)。我尚不清楚我是否真的表明错误,无论如何,缓冲区都填充了所有零。

所有其他树视图消息(例如TVM_GETITEMRECT)似乎很好地工作。

有人知道为什么那是吗?我尝试使用Unicode标志玩(我注意到 TVM_GETITEM 定义为 TVM_GETITEMA 或者 TVM_GETITEMW)但这似乎没有帮助。

有帮助吗?

解决方案

好的,让我们再给它。

较新的树视图期望 TVITEMEX 代替 TVITEM, ,而且由于没有平常 cbSize 字段,控件无法分辨它收到的版本并假设 TVITEMEX. 。也许TreeView无法访问的最后成员存在问题 TVITEMEX 因为没有内存分配。尝试使用 TVITEMEX 或分配更多的内存 TVITEM 比实际要求的。

也要考虑这一点

返回的文本不一定存储在应用程序传递的原始缓冲区中。 PSZTEXT可能会指向新的缓冲区文本,而不是将其放置在旧的缓冲区中。

因此,您可能需要从不同的过程内存中读取。

而且,由于VirtualAlloCex重置内存,因此缓冲区被归零。

作为最后一个可能是无用的度假胜地,请尝试使用 MEM_RESERVE|MEM_COMMIT 而不是只是 MEM_COMMIT.

其他提示

如果代码已与Unicode定义进行编译,则该代码无法正常工作,但是远程进程不是(或相反的回合)。你应该打电话 iswindowunicode 首先 treeView 处理以检查远程侧是否期望Unicode消息。

这是需要的,因为在这种情况下,SendMessage所做的标准双向编组是不够的:您必须根据远程侧是Unicode窗口发送两个完全不同的窗口消息。如果是Unicode,请将SendMessageW与TVM_GetItemw一起使用。如果是ANSI,请与TVM_GetItema一起使用SendMessagea。

这适用于所有通用控件,但不适用于基本的控件集(使用窗口消息<1024)。

我还认为,如果代码被编译为64位二进制,则该代码将破坏,但是远程过程为32位(或相反的回合)。这是因为代码将其本地(例如:64位)TVITEM副本副本副本副本副本副本录制到远程进程中,然后期望远程进程在处理TVM_GetItem(A | W)消息时如预期的那样对其进行预期。但是,结构的大小可能不同(由于指针尺寸不同)。

使用SPY ++查看是否使用NM_CUSTOMDRAW NOTIFIEFIAD标志处理TreeView是否处理WM_NOTIFY消息。如果确实如此,那就不幸。实际数据是在内部存储的,您几乎没有机会将其撤出。

这同样适用于Windows BTW的先前版本。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top