Я провел пару часов, просачиваясь через Dev Center от Microsoft; Однако, я не могу показаться, чтобы выяснить, как сделать следующие две вещи:Как правильно выполнить цикл/получить текст/выбрать элемент окна SysTreeView32
Цикл через и просмотреть названия каждой программы в разделе «Советники» подпункта окна «Навигатор» (для пример «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, я имею в виду имитацию операции двойного щелчка на узле дерева - подобно тому, как можно дважды щелкнуть значок на своем рабочем столе, чтобы открыть программу)
После просмотра документации, я убежден:
Там не существует явное сообщение, которое будет имитировать дважды щелкнув узел на дереве, используя дескриптор элемента древовидной
Возможной работой было бы отправить сообщение TVM_GETITEMRECT, чтобы получить координаты дерева no de, а затем использовать SendInput() для отправки щелчка
Правильно ли указаны эти два утверждения?
После реализации кода Barmak Shemirani я попытался реализовать № 2 выше, используя ту же методологию, что и в исправлении Barmak Shemirani. В частности, я попытался выделить структуру Rect в другой памяти прикладной программы с помощью VirtualAllocEx(), вызвать макрос TreeView_GetItemRect в моей программе с указателем на прямоугольник и прочитать результаты с помощью ReadProcessMemory().
Однако моя программа вылетает, когда я вызываю TreeView_GetItemRect(), передавая указатель на 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;
}
Это * может быть сделано между различными процессами, это просто не тривиально. Я помню [письмо] (http://stackoverflow.com/questions/4857602/get-listview-items-from-other-windows/4857746#4857746) о том, как это сделать для ListView давным-давно. ListViews и TreeViews достаточно похожи, чтобы кто-то со знанием Win32 мог адаптировать код, чтобы делать то, что он хочет. Разумеется, классы-помощники .NET CLR намного проще. –
Большое спасибо за ваши сообщения; Я бы никогда не думал, что SendMessage() не может использоваться в разных процессах. Я заглянул в UI Automation, но это довольно старое приложение и, похоже, не поддерживает его. Я внедрил предложенное предложение без особых проблем; однако я столкнулся с трудностями при попытке сделать небольшое расширение. – user2079438
Я перепечатывал свое оригинальное сообщение, чтобы включить: Выбор элемента SysTreeView32 – user2079438