|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#16
|
|||
|
|||
Я вернулась чуть раньше =)
И пример притащила... Всё оказывается несколько сложнее, чем я изначально полагала! Так вот просто забрать содержимое ListView из чужого окна путем посылки ему сообщения LVM_GETITEMTEXT не получится. Нужно свершать дополнительные манипуляции по выделению памяти под текстовый буфер в чужом процессе. Сразу говорю, что я воспользовалась этим примером (и авторство себе не присваиваю). Но я заточила тот пример под наши конкретные нужды и написала процедуру, считывающую всё содержимое ListView в объект StringGrid, который передается процедуре как параметр по ссылке. Это может быть как реально существующий на форме StringGrid, так и динамически создаваемый (runtime) с помощью конструктора Create. Просто, думаю, со StringGrid очень удобно работать в дальнейшем, анализируя содержимое. Вот как выглядит процедура: Код:
procedure TForm1.GetListViewData(LVHandle: HWND; ColumnCount: Integer; var DataGrid: TStringGrid); var hProcess: THandle; dwProcessID: DWORD; dwBytesWriten: DWORD; nItemCount: Integer; i, j, nTextLength: Integer; plviRemoteLVItem: PLVItem; lviRemoteLVItem: LV_ITEM; pszText: PChar; svText: ShortString; begin if LVHandle = 0 then Exit; dwProcessID := 0; nItemCount := ListView_GetItemCount(LVHandle); GetWindowThreadProcessId(LVHandle, @dwProcessID); if dwProcessID = 0 then Exit; hProcess := OpenProcess(PROCESS_ALL_ACCESS, True, dwProcessID); if hProcess = 0 then Exit; pszText := VirtualAllocEx(hProcess, nil, 255, MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); if GetLastError <> 0 then Exit; plviRemoteLVItem := VirtualAllocEx(hProcess, nil, SizeOf(LV_ITEM), MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE); if GetLastError <> 0 then Exit; { единицу прибавляю в том предположении, что есть фиксированные строка и столбец } DataGrid.RowCount := nItemCount + 1; DataGrid.ColCount := ColumnCount + 1; ZeroMemory(@lviRemoteLVItem, SizeOf(LV_ITEM)); lviRemoteLVItem.mask := LVIF_TEXT; lviRemoteLVItem.pszText := pszText; lviRemoteLVItem.cchTextMax := 255; for i := 0 to nItemCount - 1 do begin lviRemoteLVItem.iSubItem := 0; if not WriteProcessMemory(hProcess, plviRemoteLVItem, @lviRemoteLVItem, SizeOf(LV_ITEM), dwBytesWriten) then Exit; nTextLength := SendMessage(LVHandle, LVM_GETITEMTEXT, i, Integer(plviRemoteLVItem)); ZeroMemory(@svText, 255); ReadProcessMemory(hProcess, lviRemoteLVItem.pszText, @svText[1], nTextLength, dwBytesWriten); DataGrid.Cells[1, i + 1] := StrPas(PChar(@svText[1])); for j := 1 to ColumnCount - 1 do begin lviRemoteLVItem.iSubItem := j; if not WriteProcessMemory(hProcess, plviRemoteLVItem, @lviRemoteLVItem, SizeOf(LV_ITEM), dwBytesWriten) then Exit; nTextLength := SendMessage(LVHandle, LVM_GETITEMTEXT, i, Integer(plviRemoteLVItem)); ZeroMemory(@svText, 255); ReadProcessMemory(hProcess, lviRemoteLVItem.pszText, @svText[1], nTextLength, dwBytesWriten); DataGrid.Cells[j + 1, i + 1] := StrPas(PChar(@svText[1])); end; end; VirtualFreeEx(hProcess, pszText, 0, MEM_RELEASE); VirtualFreeEx(hProcess, plviRemoteLVItem, 0, MEM_RELEASE); CloseHandle(hProcess); end;
Код:
procedure TForm1.Button1Click(Sender: TObject); var StrGrid: TStringGrid; begin StrGrid := TStringGrid.Create(Self); try GetListViewData(ListViewHandle, 4, StrGrid); { теперь таблица StrGrid содержит всё, что было в ListView. Тут можно выполнять какие-то манипуляции с данными, обращаясь к ним, например, так: StrGrid.Cells[3, 5] } // Анализ и обработка... finally StrGrid.Free; end; end; |