Страницы

Поиск по вопросам

суббота, 27 октября 2018 г.

Получение содержимого ListView другого окна

Задача состоит в получении содержимого элемента ListView другого окна. Однако, данный код приводит к критическому завершению работы процесса - владельца окна. Как исправить это?
#include "stdafx.h" #include "windows.h" #include "Commctrl.h"
int main() {
HWND hWnd = FindWindow(NULL, L""); HWND hSysListView32 = FindWindowEx(hWnd, NULL, L"SysListView32", NULL);
unsigned long pid; GetWindowThreadProcessId(hSysListView32, &pid); HANDLE hProc = OpenProcess( PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, pid);
LVITEM* lvi = new LVITEM; lvi->iSubItem = 0; lvi->cchTextMax = 256;
LVITEM* lviAddr = (LVITEM*)VirtualAllocEx(hProc, NULL, sizeof LVITEM, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProc, lviAddr, lvi, sizeof LVITEM, NULL);
if (SendMessage(hSysListView32, LVM_GETITEMTEXT, 0, (LPARAM)lviAddr) > 0) printf("%s
", lvi->pszText); else printf("%d
", GetLastError());
system("pause"); return 0; }

Представляю рабочий код:
HWND hSysListView32 = FindWindowEx(hWnd, NULL, L"SysListView32", NULL); HWND hSysHeader32 = FindWindowEx(hSysListView32, NULL, L"SysHeader32", NULL);
int itemsCount = SendMessage(hSysListView32, LVM_GETITEMCOUNT, 0, 0); int colCount = SendMessage(hSysHeader32, HDM_GETITEMCOUNT, 0, 0);
DWORD dwProcessId; GetWindowThreadProcessId(hSysListView32, &dwProcessId); HANDLE hProcess = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwProcessId);
if (!hProcess) return -1;
LVITEM* lviAddress = (LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof LVITEM, MEM_COMMIT, PAGE_READWRITE); LPTSTR pItemText = (LPTSTR)VirtualAllocEx(hProcess, NULL, sizeof TCHAR * 512, MEM_COMMIT, PAGE_READWRITE);
for (int i = 0; i < itemsCount; i++) { TCHAR itemText[512] = { 0 };
LVITEM lvItem = { 0 }; lvItem.mask = LVIF_TEXT; lvItem.iSubItem = 0; lvItem.iItem = i; lvItem.pszText = pItemText; lvItem.cchTextMax = 512;
WriteProcessMemory(hProcess, lviAddress, &lvItem, sizeof(LVITEM), NULL);
int nSymbolsCount = SendMessage(hSysListView32, LVM_GETITEMTEXT, i, (LPARAM)lviAddress); if (nSymbolsCount > 0) ReadProcessMemory(hProcess, pItemText, itemText, sizeof TCHAR * nSymbolsCount, NULL);
wcout << itemText << endl; }
VirtualFreeEx(hProcess, pItemText, 0, MEM_RELEASE); VirtualFreeEx(hProcess, lviAddress, 0, MEM_RELEASE); CloseHandle(hProcess);
Однако, на этот раз проблема заключается в том, что не удаётся получить текст каждого элемента каждого столбца. В SysListView32 программы, с которой я работаю, 10 столбцов, но получить информацию о содержимом их элементов получается только для 0-2 столбцов. Дальше - неполная...
Как это исправить? Хотя если делать перебор не в цикле, а в ручную (ну самому i задавать), любой item любого column выдаёт. Странно...

Никто не запрещал использовать hotkeys. Это вариант решения показался мне жизнеспособным:
HWND hWnd = FindWindow(NULL, L"");
DWORD idAttach = GetWindowThreadProcessId(GetForegroundWindow(), 0); DWORD idAttachTo = GetWindowThreadProcessId(hWnd, 0); AttachThreadInput(idAttach, idAttachTo, TRUE); SetFocus(hWnd);
INPUT input = { 0 }; input.type = INPUT_KEYBOARD; input.ki.wScan = 0; input.ki.time = 0; input.ki.dwExtraInfo = 0;
// CONTROL key down. input.ki.wVk = VK_CONTROL; input.ki.dwFlags = 0; SendInput(1, &input, sizeof INPUT);
// "A" key down. input.ki.wVk = 'A'; input.ki.dwFlags = 0; SendInput(1, &input, sizeof INPUT);
// "A" key up. input.ki.wVk = 'A'; input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof INPUT);
// CONTROL key up. input.ki.wVk = VK_CONTROL; input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof INPUT);
// CONTROL key down. input.ki.wVk = VK_CONTROL; input.ki.dwFlags = 0; SendInput(1, &input, sizeof INPUT);
// "C" key down. input.ki.wVk = 'C'; input.ki.dwFlags = 0; SendInput(1, &input, sizeof INPUT);
// "C" key up. input.ki.wVk = 'C'; input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof INPUT);
// CONTROL key up. input.ki.wVk = VK_CONTROL; input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof INPUT);
AttachThreadInput(idAttach, idAttachTo, FALSE); SetFocus(NULL);
Но куда без очередных проблем... Проект на шарпе. Возникли трудности с переводом (не работает - пустой буфер обмена):
const ushort VK_CONTROL = 0x11; const uint KEYEVENTF_KEYUP = 0x0002;
enum INPUT_TYPE : uint { INPUT_MOUSE = 0, INPUT_KEYBOARD = 1, INPUT_HARDWARE = 2 }
[StructLayout(LayoutKind.Sequential)] struct KEYBDINPUT { public ushort wVk; public ushort wScan; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; }
[StructLayout(LayoutKind.Explicit, Size = 28)] struct INPUT { [FieldOffset(0)] public INPUT_TYPE type; [FieldOffset(4)] public KEYBDINPUT ki; }
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] static extern IntPtr FindWindow( [In, Optional, MarshalAs(UnmanagedType.LPTStr)] string lpszClass, [In, Optional, MarshalAs(UnmanagedType.LPTStr)] string lpszWindow);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] static extern IntPtr GetMessageExtraInfo();
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] static extern uint SendInput( [In] uint nInputs, [In, MarshalAs(UnmanagedType.LPArray)] INPUT[] pInputs, [In] int cbSize);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool AttachThreadInput( [In] uint idAttach, [In] uint idAttachTo, [In] bool fAttach);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool SetFocus([In, Optional] IntPtr hWnd);
static INPUT FormateKbdInputStruct(ushort vkCode, bool down) { return new INPUT() { type = INPUT_TYPE.INPUT_KEYBOARD, ki = new KEYBDINPUT() { wScan = 0, time = 0, dwExtraInfo = GetMessageExtraInfo(), wVk = vkCode, dwFlags = down ? 0 : KEYEVENTF_KEYUP } }; }
public MainForm() {
InitializeComponent();
Shown += delegate { IntPtr hWnd = FindWindow(null, "");
uint idAttach = GetWindowThreadProcessId(GetForegroundWindow(), 0); uint idAttachTo = GetWindowThreadProcessId(hWnd, 0); if (!AttachThreadInput(idAttach, idAttachTo, true)) return;
INPUT[] inputs = new INPUT[] { FormateKbdInputStruct(VK_CONTROL, true) }; SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT))); inputs[0] = FormateKbdInputStruct('A', true); SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT))); inputs[0] = FormateKbdInputStruct('A', false); SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT))); inputs[0] = FormateKbdInputStruct('C', true); SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT))); inputs[0] = FormateKbdInputStruct('C', false); SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT))); inputs[0] = FormateKbdInputStruct(VK_CONTROL, false); SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT)));
SetFocus(hWnd); SetFocus(IntPtr.Zero); AttachThreadInput(idAttach, idAttachTo, false);
Debug.WriteLine(Clipboard.GetData(DataFormats.UnicodeText)); // Пусто! }; }


Ответ

Нужно обнулять память для структуры LVITEM и массива символов перед каждым вызовом WriteProcessMemory / SendMessage
Данный код позволяет получить текст для всех столбцов ListView:
HWND hSysListView32 = FindWindowEx(hWnd, NULL, L"SysListView32", NULL);
DWORD dwProcessId; GetWindowThreadProcessId(hSysListView32, &dwProcessId); HANDLE hProcess = OpenProcess( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwProcessId);
if (!hProcess) return -1;
LVITEM* lviAddress = (LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof LVITEM, MEM_COMMIT, PAGE_READWRITE); LPTSTR pItemText = (LPTSTR)VirtualAllocEx(hProcess, NULL, sizeof TCHAR * 512, MEM_COMMIT, PAGE_READWRITE);
TCHAR itemText[512] = {0}; LVITEM lvItem = { 0 };
for (int i = 0; i < COUNT_ITEMS; i++) for(int j=0; j < COUNT_SUBITEMS; j++) {
memset(&itemText,0,sizeof(itemText)); //обнуление памяти memset(&lvItem,0,sizeof(LVITEM));
lvItem.mask = LVIF_TEXT; lvItem.iSubItem = j; lvItem.iItem = i; lvItem.pszText = pItemText; lvItem.cchTextMax = 512;
WriteProcessMemory(hProcess, lviAddress, &lvItem, sizeof(LVITEM), NULL);
int nSymbolsCount = SendMessage(hSysListView32, LVM_GETITEMTEXT, i, (LPARAM)lviAddress); if (nSymbolsCount > 0) ReadProcessMemory(hProcess, pItemText, itemText, sizeof TCHAR * nSymbolsCount, NULL);
wprintf(L"Item %d, subitem %d: %s
", i,j,itemText); }
VirtualFreeEx(hProcess, pItemText, 0, MEM_RELEASE); VirtualFreeEx(hProcess, lviAddress, 0, MEM_RELEASE); CloseHandle(hProcess);

Комментариев нет:

Отправить комментарий