Я написал функцию, которая может выдавать текст элемента представления дерева, даже если представление дерева находится в удаленном процессе. Функция выделяет два фрагмента памяти в удаленном процессе, заполняет структуру 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
), но это, похоже, не помогло.