我花了几个小时在微软的开发中心倾注;但是,我似乎无法弄清楚如何做以下两件事:
在“导航器”子窗口的“EA交易”部分循环查看每个程序的名称(例如下面屏幕截图中的“MACD Sample”)
选择并双击该程序(例如'MACD Sample')。
Winspector(Left) | Application(Right)
我的主要问题似乎是我不知道如何正确使用HTREEITEM来访问信息。我注意到有一个函数ListView_GetItemText,但我一直无法找到TreeView_GetItemText或等效函数。
非常感谢任何帮助。
以下是我的计划的主要功能:
int _tmain(int argc, _TCHAR* argv[])
{
wcout << TEXT("Enumerating Windows...") << endl;
HWND handle = NULL;
//--- Success: gets application handle
bool success1 = getHandle(L"MetaTrader", L"20", handle);
cout << "Success1: " << success1 << endl;
cout << "Result1: " << handle << endl;
//--- Success: gets navigator window
bool success2 = getChildHandle(handle, L"", L"Navigator", handle);
cout << "Success2: " << success2 << endl;
cout << "Result2: " << handle << endl;
//--- Success: gets "SysTreeView32" handle
handle = FindWindowEx(handle, 0, L"SysTreeView32", L"");
cout << "Result3: " << handle << endl;
//--- Success: get "SysTreeView32" root nod
HTREEITEM root = TreeView_GetNextItem(handle, NULL, TVGN_ROOT);
cout << "root: " << root << endl;
return 0;
}
运行代码的结果似乎正常工作
完整性的完整代码:
// MT4Terminal-test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#pragma once
#include "targetver.h"
#include <iostream>
#include <map>
#include <string>
namespace std {
#if defined _UNICODE || defined UNICODE
typedef wstring tstring;
#else
typedef string tstring;
#endif
}
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <psapi.h>
#include <Windows.h>
#include <Commctrl.h>
#include <windows.system.h>
using namespace std;
HWND glb_handle;
tstring glb_searchWindowTitle;
tstring glb_seachClassName;
BOOL CALLBACK enumWindowsChildProc(
__in HWND hWnd,
__in LPARAM lParam
) {
return TRUE;
}
BOOL CALLBACK enumWindowsProc(
__in HWND hWnd,
__in LPARAM lParam
) {
int length = ::GetWindowTextLength(hWnd);
if (0 == length) return TRUE;
TCHAR* bufferA;
bufferA = new TCHAR[length + 1];
memset(bufferA, 0, (length + 1) * sizeof(TCHAR));
TCHAR* bufferB;
bufferB = new TCHAR[100];
memset(bufferB, 0, 100 * sizeof(TCHAR));
GetWindowText(hWnd, bufferA, length + 1);
GetClassName(hWnd, bufferB, 100);
tstring windowTitle = tstring(bufferA);
tstring className = tstring(bufferB);
delete bufferA;
delete bufferB;
if (windowTitle.find(glb_searchWindowTitle) < string::npos &&
className.find(glb_seachClassName) < string::npos)
glb_handle = hWnd;
wcout.clear();
return TRUE;
}
bool getHandle(wstring searchClassName, wstring searchWindowTitle, HWND &handle)
{
handle = NULL;
glb_handle = NULL;
glb_searchWindowTitle = searchWindowTitle;
glb_seachClassName = searchClassName;
BOOL enumeratingWindowsSucceeded = EnumWindows(enumWindowsProc, NULL);
if (enumeratingWindowsSucceeded)
{
if (glb_handle != NULL)
{
handle = glb_handle;
return true;
}
}
glb_handle = NULL;
glb_searchWindowTitle = L"";
glb_seachClassName = L"";
return false;
}
bool getChildHandle(HWND parent_handle, wstring searchClassName, wstring searchWindowTitle, HWND &handle)
{
handle = NULL;
glb_handle = NULL;
glb_searchWindowTitle = searchWindowTitle;
glb_seachClassName = searchClassName;
BOOL enumeratingWindowsSucceeded = EnumChildWindows(parent_handle, enumWindowsProc, NULL);
if (enumeratingWindowsSucceeded)
{
if (glb_handle != NULL)
{
handle = glb_handle;
return true;
}
}
glb_handle = NULL;
glb_searchWindowTitle = L"";
glb_seachClassName = L"";
return false;
}
int _tmain(int argc, _TCHAR* argv[])
{
wcout << TEXT("Enumerating Windows...") << endl;
HWND handle = NULL;
//--- Success: gets application handle
bool success1 = getHandle(L"MetaTrader", L"20", handle);
cout << "Success1: " << success1 << endl;
cout << "Result1: " << handle << endl;
//--- Success: gets navigator window
bool success2 = getChildHandle(handle, L"", L"Navigator", handle);
cout << "Success2: " << success2 << endl;
cout << "Result2: " << handle << endl;
//--- Success: gets "SysTreeView32" handle
handle = FindWindowEx(handle, 0, L"SysTreeView32", L"");
cout << "Result3: " << handle << endl;
//--- Success: get "SysTreeView32" root nod
HTREEITEM root = TreeView_GetNextItem(handle, NULL, TVGN_ROOT);
cout << "root: " << root << endl;
return 0;
}
选择SysTreeView32项目
(为了澄清,当我说选择SysTreeView32项时,我指的是在树节点上模拟双击操作 - 类似于双击桌面上的图标以打开程序的方式)< / p>
在查看文档后,我确信:
不存在显式消息,该消息将模拟使用树视图项的句柄双击树上的节点
可能的解决方法是发送TVM_GETITEMRECT消息以获取树节点的坐标,然后使用SendInput()发送单击
上述两个陈述是否正确?
在实施Barmak Shemirani的代码之后,我尝试使用与Barmak Shemirani修复相同的方法实现上面的#2。具体来说,我尝试使用VirtualAllocEx()在其他Application程序的内存中分配一个Rect结构,使用指向矩形的指针调用程序中的TreeView_GetItemRect宏,并使用ReadProcessMemory()读取结果。
但是,当我调用TreeView_GetItemRect()时,我的程序崩溃,同时将指针传递给其他Apps内存中的Rect。很可能是因为TreeView_GetItemRect()试图将Rect坐标写入无效的内存地址。这让我意识到我并不真正理解宏在做什么:
因此,检查来源,我发现:
#define HELLO
#define TV_FIRST 0x1100 // TreeView messages
#define TVM_GETITEMRECT (TV_FIRST + 4)
#define TreeView_GetItemRect(hwnd, hitem, prc, code) \
(*(HTREEITEM *)(prc) = (hitem), (BOOL)SNDMSG((hwnd), TVM_GETITEMRECT, (WPARAM)(code), (LPARAM)(RECT *)(prc)))
我主要了解除SNDMSG功能之前的部分以外的所有内容:
(*(HTREEITEM *)(prc) = (hitem),
以上陈述究竟是什么意思?这是否是我传递给HTREEITEM指针的矩形指针,这会导致程序崩溃?
Screenshot of console freezing
新代码
int _tmain(int argc, _TCHAR* argv[])
{
wcout << TEXT("Enumerating Windows...") << endl;
HWND handle = NULL;
//--- Success: gets application handle
bool success1 = getHandle(L"MetaTrader", L"20", handle);
//--- Success: gets navigator window
bool success2 = getChildHandle(handle, L"", L"Navigator", handle);
//--- Success: gets "SysTreeView32" handle
handle = FindWindowEx(handle, 0, L"SysTreeView32", L"");
//--- Success: get "SysTreeView32" root nod
HTREEITEM root = TreeView_GetNextItem(handle, NULL, TVGN_ROOT);
unsigned long pid;
GetWindowThreadProcessId(handle, &pid);
HANDLE process = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE |
PROCESS_QUERY_INFORMATION, FALSE, pid);
TVITEM item, *_item;
wchar_t buf[CHAR_BUF_LEN];
wchar_t *_buf;
memset(buf, 0, sizeof(buf) / sizeof(buf[0]));
_item = (TVITEM*)VirtualAllocEx(process, NULL, sizeof(TVITEM), MEM_COMMIT, PAGE_READWRITE);
_buf = (wchar_t*)VirtualAllocEx(process, NULL, CHAR_BUF_LEN, MEM_COMMIT, PAGE_READWRITE);
item.cchTextMax = CHAR_BUF_LEN;
item.pszText = _buf;
item.mask = TVIF_TEXT;
//--- find Experts Advisors branch in tree
HTREEITEM node = TreeView_GetNextItem(handle, root, TVGN_CHILD);
node = TreeView_GetNextItem(handle, node, TVGN_NEXT);
node = TreeView_GetNextItem(handle, node, TVGN_NEXT);
RECT rect, *_rect;
_rect = (RECT*)VirtualAllocEx(process, NULL, sizeof(RECT), MEM_COMMIT, PAGE_READWRITE);
rect = { 0 };
WriteProcessMemory(process, _rect, &rect, sizeof(RECT), NULL);
//--- step into Expert Advisors
node = TreeView_GetNextItem(handle, node, TVGN_CHILD);
//--- target program to open
wchar_t ea_name[] = L"MACD Sample";
while (node != NULL)
{
ZeroMemory(buf, CHAR_BUF_LEN);
item.hItem = node;
//Binds item and _item
WriteProcessMemory(process, _item, &item, sizeof(TVITEM), NULL);
TreeView_GetItem(handle, _item);
//Read buffer back to this program's process memory
ReadProcessMemory(process, _buf, buf, CHAR_BUF_LEN, NULL);
//Print program name
wcout << buf << endl;
if (wcscmp(ea_name, buf) == 0)
{
cout << "Found target program: " << ea_name << endl;
cout << "get rectangle coordinates: " << TreeView_GetItemRect(handle, node, _rect, TRUE) << endl;
}
node = TreeView_GetNextItem(handle, node, TVGN_NEXT);
}
VirtualFreeEx(process, _item, 0, MEM_RELEASE);
VirtualFreeEx(process, _buf, 0, MEM_RELEASE);
VirtualFreeEx(process, _rect, 0, MEM_RELEASE);
return 0;
}
答案 0 :(得分:2)
这是您通常用于读取TreeView项目文本的方法:
wchar_t buf[100];
memset(buf, 0, sizeof(buf));
TVITEM item = { 0 };
item.hItem = hitem;
item.cchTextMax = 100;
item.pszText = buf;
item.mask = TVIF_TEXT;
TreeView_GetItem(hwnd, &item);
程序中 这不起作用。 TreeView_GetItem
是基于SendMessage
的宏,它通过LPARAM
参数复制数据。但是不同流程之间不允许这种交换。
你可能花费数小时,甚至几天,试图破解它 (See this example)
或者您可能想要研究并查看目标计划是否支持UI Automation
编辑,这是获取HTREEITEM
文字的示例。除非:
如果目标程序是ANSI,则将此功能更改为ANSI。
HTREEITEM hitem = TreeView_GetSelection(hwndTree);
if (!hitem)
debug << "!hitem\n";
const int buflen = 512;
DWORD pid;
GetWindowThreadProcessId(hwndTree, &pid);
HANDLE process = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
| PROCESS_QUERY_INFORMATION, FALSE, pid);
TVITEMEX* ptv = (TVITEMEX*)VirtualAllocEx(process, NULL, sizeof(TVITEMEX),
MEM_COMMIT, PAGE_READWRITE);
wchar_t* pbuf = (wchar_t*)VirtualAllocEx(process, NULL, buflen,
MEM_COMMIT, PAGE_READWRITE);
TVITEMEX tv = { 0 };
tv.hItem = hitem;
tv.cchTextMax = buflen / 2;
tv.pszText = pbuf;
tv.mask = TVIF_TEXT | TVIF_HANDLE;
WriteProcessMemory(process, ptv, &tv, sizeof(TVITEMEX), NULL);
if (SendMessageW(hwndTree, TVM_GETITEM, 0, (LPARAM)(TVITEMEX*)(ptv)))
{
wchar_t buf[buflen / 2];
ReadProcessMemory(process, pbuf, buf, buflen, 0);
debug << "Result:" << buf << "\n";
}
else
debug << "!SendMessageW\n";
VirtualFreeEx(process, ptv, 0, MEM_RELEASE);
VirtualFreeEx(process, pbuf, 0, MEM_RELEASE);
CloseHandle(process); //*** I forgot this line before
答案 1 :(得分:0)
投票最多的答案已经解决了您的问题,但我想在声明中添加一些评论:
(*(HTREEITEM *)(prc) = (hitem),
TVM_GETITEMRECT解释说:
发送此消息时,lParam参数包含要为其获取矩形的项目的句柄。
在宏TreeView_GetItemRect
中,prc
将被_rect
替换,而TreeView_GetItemRect(handle, node, _rect, TRUE)
是在其他进程中分配的。因此程序崩溃了。
根据您的情况,您可以替换代码:
RECT rect, *_rect;
_rect = (RECT*)VirtualAllocEx(process, NULL, sizeof(RECT), MEM_COMMIT, PAGE_READWRITE);
*(HTREEITEM*)&rect = node;
WriteProcessMemory(process, _rect, &rect, sizeof(RECT), NULL);
SendMessage(handle, TVM_GETITEMRECT, true, (LPARAM)_rect);
作者:
customer._id