#cpp #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\n", lvi->pszText); else printf("%d\n", 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)); // Пусто! }; }
Ответы
Ответ 1
Нужно обнулять память для структуры 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\n", i,j,itemText); } VirtualFreeEx(hProcess, pItemText, 0, MEM_RELEASE); VirtualFreeEx(hProcess, lviAddress, 0, MEM_RELEASE); CloseHandle(hProcess);
Комментариев нет:
Отправить комментарий