Приветствую.
Пытаюсь получить текст элемента дерева другого приложения (например, из "Windows Explorer") пишу вот так:
#include <atlbase.h>
#include <atlapp.h>
#include <atlctrls.h>
#include <iostream>
int main()
{
CTreeViewCtrlEx tvc;
tvc = (HWND)0x000806D8; //Значение получено при помощи Spy++
CTreeItem tiCur = tvc.GetSelectedItem(); //Значение получаю, т.е. тут не NULL
WCHAR szBuf[1024] = { 0 };
if (!tiCur.GetText(szBuf, sizeof(szBuf) / sizeof(WCHAR)))
// if (!tiCur.SortChildren(TRUE))
std::wcout << L"Error" << std::endl;
else
std::wcout << szBuf << std::endl;
return 0;
}
Так вот всегда вываливается на ошибку и буфер не заполняет. С начало закралась мысль, что сообщения пришедшие из другого приложения не попадают к окну (понимаю, что мысль шальная, но черт его знает), заменил строку получения текста на сортировку. В результате все сработало и дочерние элементы отсортировались, это доказывает, что сообщения к окну приходят (хотя может быть ни все, но все же ходят). Может кто объяснит, что я не так делаю?
Здравствуйте, DmitryChernov, Вы писали:
[]
См. в сторону ReadProcessMemory.
Кстати, у Рихтера есть схожий пример.
Здравствуйте, DmitryChernov, Вы писали:
DC>Пытаюсь получить текст элемента дерева другого приложения (например, из "Windows Explorer") пишу вот так:
DC>Так вот всегда вываливается на ошибку и буфер не заполняет. С начало закралась мысль, что сообщения пришедшие из другого приложения не попадают к окну (понимаю, что мысль шальная, но черт его знает), заменил строку получения текста на сортировку. В результате все сработало и дочерние элементы отсортировались, это доказывает, что сообщения к окну приходят (хотя может быть ни все, но все же ходят). Может кто объяснит, что я не так делаю?
Есть вот такой код для копирования дерева из другого процесса. Требует доработки напильником в MemAllocate/MemRelease (см. закомментированную строку), но в принципе работает:
// TreeViewFPDE.h: interface for the CTreeViewFPDE class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_TREEVIEWFPDE_H__9A632F5A_BA1D_4597_AFED_774A7EE00EC8__INCLUDED_)
#define AFX_TREEVIEWFPDE_H__9A632F5A_BA1D_4597_AFED_774A7EE00EC8__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// information about target ListView
struct dmTreeView
{
HWND hWnd;
CString Class;
long ItemCount;
RECT rect;
};
class CTreeViewFPDE
{
public:
CTreeViewFPDE();
virtual ~CTreeViewFPDE();
BOOL GetTreeviewInfo(dmTreeView& tvInfo);
CString WindowClass(HWND hWindow);
void TreeViewScan(dmTreeView& tvInfo, CTreeViewCtrl& tree);
protected:
LPVOID MemAllocate(DWORD nBytes, DWORD fpID);
BOOL MemRelease(LPVOID mPointer);
void SubTreeScan(DWORD hItem, HTREEITEM hTreeItem, CTreeViewCtrl& tree);
CString TreeviewItem(DWORD hItem);
BOOL TreeviewItemExpanded(DWORD hItem);
void ReadProcessData(LPVOID pBuffer, LPVOID pData, DWORD nBytes);
void WriteProcessData(LPVOID pBuffer, LPVOID pData, DWORD nBytes);
BOOL m_bWindowsNT;
HWND tvWindow;
HANDLE fpHandle;
TVITEM TVitem;
LPVOID tvItemPointer, tvDataPointer;
};
#endif // !defined(AFX_TREEVIEWFPDE_H__9A632F5A_BA1D_4597_AFED_774A7EE00EC8__INCLUDED_)
// TreeViewFPDE.cpp: implementation of the CTreeViewFPDE class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "TreeViewFPDE.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CTreeViewFPDE::CTreeViewFPDE()
{
OSVERSIONINFO verinfo;
verinfo.dwOSVersionInfoSize = sizeof(verinfo);
if (GetVersionEx(&verinfo))
{
m_bWindowsNT = (verinfo.dwPlatformId == 2);
}
tvWindow = NULL;
}
CTreeViewFPDE::~CTreeViewFPDE()
{
}
CString CTreeViewFPDE::WindowClass(HWND hWindow)
{
long cLen;
char className[64] = {0};
cLen = GetClassName(hWindow, className, 63);
if (cLen)
className[cLen] = 0;
return className;
}
// Fills in info about target window (passed via tvInfo.hWnd)
// Returns TRUE if hWindow is a handle to a TreeView control
BOOL CTreeViewFPDE::GetTreeviewInfo(dmTreeView& tvInfo)
{
tvWindow = tvInfo.hWnd;
if (IsWindow(tvWindow) == 0)
{
tvWindow = NULL;
return FALSE;
}
tvInfo.Class = WindowClass(tvWindow);
if (tvInfo.Class.CompareNoCase("SysTreeView32"))
{
tvWindow = NULL;
tvInfo.ItemCount = 0;
return FALSE;
}
tvInfo.ItemCount = SendMessage(tvWindow, TVM_GETCOUNT, NULL, NULL);
GetWindowRect(tvWindow, &tvInfo.rect);
return TRUE;
}
void CTreeViewFPDE::TreeViewScan(dmTreeView& tvInfo, CTreeViewCtrl& tree)
{
DWORD tvProcessId;
GetWindowThreadProcessId(tvWindow, &tvProcessId);
tvItemPointer = MemAllocate(sizeof(TVitem), tvProcessId);
tvDataPointer = MemAllocate(255, tvProcessId);
tvInfo.ItemCount = SendMessage(tvWindow, TVM_GETCOUNT, 0, 0);
long tvCount = tvInfo.ItemCount;
if (tvCount == 0) return;
long tvIndex = 1;
long hItem = SendMessage(tvWindow, TVM_GETNEXTITEM, TVGN_ROOT, 0);
while (hItem)
{
HTREEITEM hRootItem = tree.InsertItem(TreeviewItem(hItem), TVI_ROOT, TVI_LAST);
if (TreeviewItemExpanded(hItem))
tree.SetItemState(hRootItem, TVIS_EXPANDED, TVIS_EXPANDED);
SubTreeScan(hItem, hRootItem, tree);
hItem = SendMessage(tvWindow, TVM_GETNEXTITEM, TVGN_NEXT, hItem);
}
MemRelease(tvItemPointer);
MemRelease(tvDataPointer);
}
void CTreeViewFPDE::SubTreeScan(DWORD hItem, HTREEITEM hParentItem, CTreeViewCtrl& tree)
{
if (tvWindow == NULL)
return;
hItem = SendMessage(tvWindow, TVM_GETNEXTITEM, TVGN_CHILD, hItem);
if (hItem == 0)
return;
while (hItem)
{
HTREEITEM hTreeItem = tree.InsertItem(TreeviewItem(hItem), hParentItem, TVI_LAST);
if (TreeviewItemExpanded(hItem))
tree.SetItemState(hTreeItem, TVIS_EXPANDED, TVIS_EXPANDED);
SubTreeScan(hItem, hTreeItem, tree);
hItem = SendMessage(tvWindow, TVM_GETNEXTITEM, TVGN_NEXT, hItem);
}
}
CString CTreeViewFPDE::TreeviewItem(DWORD hItem)
{
if (tvWindow == NULL)
return "";
// 1. Fill in TVITEM in the normal fashion, with just one difference
TVitem.mask = TVIF_TEXT;
TVitem.hItem = (HTREEITEM)hItem;
TVitem.pszText = (char*)tvDataPointer; // ItemData address is our shared buffer!
TVitem.cchTextMax = 255;
// 2. Copy the TVITEM to the shared buffer, and send the GETITEM request
WriteProcessData(tvItemPointer, &TVitem, sizeof(TVitem));
LRESULT apiResult = SendMessage(tvWindow, TVM_GETITEMA, 0, (LPARAM)tvItemPointer);
// 3. Get the return data from the shared buffer (and convert to VB string)
// TVM_GETITEM doesn't return the item's text length
if (apiResult)
{
char myBuffer[256];
ReadProcessData(tvDataPointer, myBuffer, 255);
return myBuffer;
}
return "";
}
BOOL CTreeViewFPDE::TreeviewItemExpanded(DWORD hItem)
{
if (tvWindow == NULL)
return NULL;
// 1. Fill in TVITEM in the normal fashion, with just one difference
TVitem.mask = TVIF_STATE;
TVitem.hItem = (HTREEITEM)hItem;
TVitem.stateMask = TVIS_EXPANDED;
// 2. Copy the TVITEM to the shared buffer, and send the GETITEM request
WriteProcessData(tvItemPointer, &TVitem, sizeof(TVitem));
LRESULT apiResult = SendMessage(tvWindow, TVM_GETITEMA, 0, (LPARAM)tvItemPointer);
ReadProcessData(tvItemPointer, &TVitem, sizeof(TVitem));
// 3. Check my mask state bit
return (TVitem.state & TVIS_EXPANDED);
}
LPVOID CTreeViewFPDE::MemAllocate(DWORD nBytes, DWORD fpID)
{
// Returns pointer to a share-able buffer (size nBytes) in target process
// fpID is the foreign process id - we only need it on NT platforms, actually
if (m_bWindowsNT)
{
fpHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, fpID);
return VirtualAllocEx(fpHandle, 0, nBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
}
else
{
fpHandle = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, nBytes, NULL);
return MapViewOfFile(fpHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
}
}
BOOL CTreeViewFPDE::MemRelease(LPVOID mPointer)
{
if (m_bWindowsNT)
{
VirtualFreeEx(fpHandle, mPointer, 0, MEM_RELEASE);
}
else
{
UnmapViewOfFile(mPointer);
}
// return CloseHandle(fpHandle);
return TRUE;
}
void CTreeViewFPDE::ReadProcessData(LPVOID pBuffer, LPVOID pData, DWORD nBytes)
{
if (m_bWindowsNT)
ReadProcessMemory(fpHandle, pBuffer, pData, nBytes, 0);
else
CopyMemory(pData, pBuffer, nBytes);
}
void CTreeViewFPDE::WriteProcessData(LPVOID pBuffer, LPVOID pData, DWORD nBytes)
{
if (m_bWindowsNT)
WriteProcessMemory(fpHandle, pBuffer, pData, nBytes, 0);
else
CopyMemory(pBuffer, pData, nBytes);
}