Listview of another Process
Listview of another Process
Is there a way with madCollection, to get the Text and the index of each Item of a Listview in another process?
-
- Posts: 18
- Joined: Thu Apr 28, 2005 12:57 am
create a inject dll for the target process, in the dll find the target window that contains the listview: from there, use ListView_GetItemCount (number of rows) and ListView_GetItemText to find the desired text...
Code: Select all
handleToTargetWnd:=FindWindowEx(handleToParentWnd, 0, 'SysListView32',nil)
-
- Posts: 18
- Joined: Thu Apr 28, 2005 12:57 am
neji,im not quite sure what u mean.. do u want to get a TListItem at every row... or just the text of every row... anyway.. try this...
u can manipulate i and j for formatting in the file .. or use ipc to send the text
directly to your main app
Code: Select all
var
text : array[1..100] of AnsiChar;
aFile : TextFile;
i : Integer;
j : Integer;
rowCount : Integer;
begin
// assingn a file path to the text file then find your parent window and
// do the following
hTargetWnd:=FindWindowEx(hParentWnd, 0, 'SysListView32',nil);
if hTargetWnd<> 0 then
begin
rowCount := ListView_GetItemCount(hTargetWnd);
for i:=0 to rowCount-1 do
begin
for j:=0 to rowCount-1 do
begin
ListView_GetItemText(hTargetWnd,i,j,@text,100);
Write(aFile,Trim(String(text)));
end;
end;
end.
directly to your main app
-
- Posts: 18
- Joined: Thu Apr 28, 2005 12:57 am
shellBullet is right. The easiest way to solve the problem is to inject a dll into the process which owns the target list view and then use the list view messages / APIs from inside the injected dll.
There's another possibility, though:
The only reason why some of the list view messages / APIs don't work for list views of other processes is that those non working list view messages work with pointers. And as you know, pointers are valid in your own process, only. You can work around that, though, by allocating memory in the target process and send a pointer to that buffer to the target list view. You can use AllocMemEx and FreeMemEx for this purpose. You'll have to use WriteProcessMemory and ReadProcessMemory to access this buffer. madShell is using this method internally to get access to the desktop items.
There's another possibility, though:
The only reason why some of the list view messages / APIs don't work for list views of other processes is that those non working list view messages work with pointers. And as you know, pointers are valid in your own process, only. You can work around that, though, by allocating memory in the target process and send a pointer to that buffer to the target list view. You can use AllocMemEx and FreeMemEx for this purpose. You'll have to use WriteProcessMemory and ReadProcessMemory to access this buffer. madShell is using this method internally to get access to the desktop items.
thanks for the reply. I tried to do that by allocating memory and using Read/Writeprocessmemory.
The Code, I have used to find the index of the item I looked for :
It worked well, but I'm not done yet
I still need to know, how I can "select" this item (the selection that appears when clicking an item with the mouse) with code. Does Anybody know how that can be done?
The Code, I have used to find the index of the item I looked for :
Code: Select all
function GetItemIndex(aText : String; const CaseSensitive : Boolean = FALSE) : Integer;
function GetListView : Cardinal;
begin
result := FindWindow(nil,'Form1');
result := FindWindowEx(result, 0, 'TListView', nil);
end;
var
ListView: HWND;
ProcessId: DWORD;
Process: THandle;
Size: Cardinal;
MemLocal: Pointer;
MemRemote: Pointer;
NumBytes: Cardinal;
IconIndex: Integer;
IconLabel: string;
begin
result := 0;
ProcessId := 0;
ListView := GetListView;
GetWindowThreadProcessId(ListView, @ProcessId);
Process := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_READ or
PROCESS_VM_WRITE, False, ProcessId);
if (Process <> 0) then
try
Size := SizeOf(TLVItem) + SizeOf(Char) * MAX_PATH + 1;
MemLocal := VirtualAlloc(nil, Size, MEM_RESERVE or MEM_COMMIT,
PAGE_READWRITE);
MemRemote := VirtualAllocEx(Process, nil, Size, MEM_RESERVE or MEM_COMMIT,
PAGE_READWRITE);
if Assigned(MemLocal) and Assigned(MemRemote) then
try
for IconIndex := 0 to SendMessage(ListView, LVM_GETITEMCOUNT, 0, 0) - 1 do
begin
ZeroMemory(MemLocal, SizeOf(TLVItem));
with PLVItem(MemLocal)^ do
begin
mask := LVIF_TEXT;
iItem := IconIndex;
pszText := LPTSTR(Cardinal(MemRemote) + Cardinal(SizeOf(TLVItem)));
cchTextMax := MAX_PATH;
end;
NumBytes := 0;
if WriteProcessMemory(Process, MemRemote, MemLocal, Size, NumBytes) and
Boolean(SendMessage(ListView, LVM_GETITEM, 0, LPARAM(MemRemote))) and
ReadProcessMemory(Process, MemRemote, MemLocal, Size, NumBytes) then
begin
IconLabel := string(
PChar(Cardinal(MemLocal) + Cardinal(SizeOf(TLVItem))));
if CaseSensitive then
begin
IconLabel := LowerCase(IconLabel);
aText := LowerCase(aText);
end;
if IconLabel = aText then
begin
Result := IconIndex;
exit;
end;
end;
end;
except
end;
if Assigned(MemRemote) then
VirtualFreeEx(Process, MemRemote, 0, MEM_RELEASE);
if Assigned(MemLocal) then
VirtualFree(MemLocal, 0, MEM_RELEASE);
finally
CloseHandle(Process);
end;
end;
I still need to know, how I can "select" this item (the selection that appears when clicking an item with the mouse) with code. Does Anybody know how that can be done?
I looked through the Listview messages and the only one I think it could be it is then LVM_SETITEMSTATE message, am I right?
but it didn't work... if an Item is selected before sending the message, it get's unselected...but my wanted item isnt selected then
Anyway, I tried it withThe LVM_SETITEMSTATE message changes the state of an item in a list view control. You can explicitly send this message or by using the ListView_SetItemState macro.
Code: Select all
ListView_SetItemState(mein_handle, itemIndex, LVIS_FOCUSED + LVIS_SELECTED,LVIS_FOCUSED + LVIS_SELECTED);
ListView_EnsureVisible(mein_handle,itemIndex,TRUE);
I recommend to use the messages instead of the APIs. When using the APIs you can't really see what's going on. The APIs internally use the messages. When using the ListView_SetItemState API it looks like no pointers would be involved. However, check out the message documentation and suddenly you'll see that setting item states does involve pointers. So you need to do the AllocMemEx etc trick here, too.