Показать сообщение отдельно
  #16  
Старый 24.04.2009, 17:37
Nyctos Kasignete Nyctos Kasignete вне форума
Активный
 
Регистрация: 29.03.2009
Сообщения: 300
Репутация: 94
По умолчанию

Я вернулась чуть раньше =)
И пример притащила... Всё оказывается несколько сложнее, чем я изначально полагала! Так вот просто забрать содержимое 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;
Ещё чуть-чуть поясню. Процедура получает следующие параметры:
  1. Handle окна ListView (того самого, который имеет класс SysListView32). Этот дескриптор находите так же, как и раньше.
  2. Количество столбцов в этом ListView.
  3. Последний параметр, как уже сказано, — объект типа TStringGrid, который либо лежит на форме вашего собственного приложения, либо создается динамически.
Вот пример использования этой процедуры:
Код:
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;
Ответить с цитированием