[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1608
  • Last Modified:

ListView_GetItem

Hi.

I'm having real problems using the ListView_ macros in CommCtrl.pas

Can someone tell me what's wrong with this please?

////////////////////////// Delphi Code ////////////////////////////

procedure ShowItems;
var
  CPManager,
  ListView    : hWnd;
  TmpPC       : PChar;
  ListItem    : LV_ITEM;
  CurrentPos,
  ItemCount   : Integer;
begin
  CPManager:=FindWindow('TCPManager_MainWindow', 'CP Manager');
  ListView:=FindWindowEx(CPManager, 0, 'TListView', nil);
  GetMem(TmpPC, 255);
  ItemCount:=ListView_GetItemCount(ListView);
  for CurrentPos:=0 to ItemCount-1 do begin
    ListItem.mask:=LVIF_TEXT;
    ListItem.iItem:=CurrentPos;
    ListItem.iSubItem:=0;
    ListItem.pszText:=TmpPC;
    ListItem.cchTextMax:=255;
    if ListView_GetItem(ListView, ListItem) then
      ShowMessage(TmpPC);
  end;
  FreeMem(TmpPC);
end;

///////////////////////////////////////////////////////////////////


Thanks for any help,

MoonCalf
0
MoonCalf
Asked:
MoonCalf
  • 6
  • 6
  • 4
  • +3
1 Solution
 
AloneCommented:
But what are you want to do?
0
 
TasomiaCommented:
0
 
DrDelphiCommented:
I don't know what exactly you are trying to do, but I do see one glaring problem. You VAR'ed TempPc as PChar and never initliazed it or assigned it a value before assigning ListItem.pszText equal to TempPc. And then you go on the show TempPc, which STILL doesn't have a value.


Good luck!!


BTW, you needn't use GetMem for Pchar... StrPcopy is cleaner. If you insist on using GetMem, you should free up that pointer with FreeMem.


GL

 
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
DrDelphiCommented:
I don't know what exactly you are trying to do, but I do see one glaring problem. You VAR'ed TempPc as PChar and never initliazed it or assigned it a value before assigning ListItem.pszText equal to TempPc. And then you go on the show TempPc, which STILL doesn't have a value.


Good luck!!


BTW, you needn't use GetMem for Pchar... StrPcopy is cleaner. If you insist on using GetMem, you should free up that pointer with FreeMem.


GL

 
0
 
DrDelphiCommented:
oops! G-g-g-got a little stutter there! S-S-S-S-Sooorry!

0
 
DrDelphiCommented:
I have to apologize again. I just noticed that you do in fact make a call to FreeMem. What can I say? It's been a long week! <g>

Good luck!!
0
 
MadshiCommented:
I guess you want to ask the list view of another process, right? I'm sorry to say, but the list view stuff works internally with messages. And most of them contain pointers. And in 32bit programming a pointer is private to each process. So this all doesn't work with list views of other processes.

The usual solution to your problem would be to put your list view loop into a little dll and inject this dll into the other process. There's also another solution, but it's undocumented...

Regards, Madshi.
0
 
MoonCalfAuthor Commented:
Hi Guys.

Thank you, everyone, for all comments.  Every comment is appreciated.

Madshi - "There's also another solution, but it's undocumented..."????

Could you explain it a little for me?

Thanks,

MoonCalf.
0
 
MoonCalfAuthor Commented:
BTW, Tasomia : Thanks for the example which is great, but I was hoping that by answering the question I could also learn to manipulate an external processeses ListView.  (For example, the Task Manager.)

Thanks,

MoonCalf.
0
 
MadshiCommented:
Well, you are sending a pointer to the list view of another process. The other process now wants to write the requested information to the address you gave in. But the other process writes the information in the address in its own memory/address context. Now in NT we can do the following:

(1) Allocate memory in the context of the other process by using VirtualAllocEx.
(2) Send the list view message, giving in the pointer you got from (1). Now the other process can correctly save the requested info to the requested address.
(3) But the info is now in the context of the other process, so we have to use ReadProcessMemory to get access to that info.
(4) Finally you should free the allocated memory from (1) by using VirtualFreeEx.

I'm using this logic quite often, it works absolutely fine. Unfortunately win9x doesn't support VirtualAllocEx/VirtualFreeEx, there comes the undocumented part: You can set up a memory mapped file (CreateFileMapping(-1, ...) + MapViewOfFile). The buffer will be in shared memory (which is shared between all processes system wide), so the other process can successfully write to the address and you can successfully read it - without even using ReadProcessMemory.

Regards, Madshi.
0
 
MoonCalfAuthor Commented:
Hi Madshi.  Thanks for the comment, but huh??

Could you do me an example please.  You're talking about something that I have absolutely no idea about!

Thanks,

MoonCalf.
0
 
MadshiCommented:
Ehm, sorry, no time for a real tested example. Let me just hack a bit with your sources, maybe it helps you understanding what I mean:

procedure ShowItems;
var
 CPManager,
 ListView    : hWnd;
 TmpPC       : PChar;
 PListItem   : ^LV_ITEM;
 ListItem    : LV_ITEM;
 CurrentPos,
 ItemCount   : Integer;
 pid         : dword;  // process ID
 ph          : dword;  // process handle
 c1          : dword;  // dummy variable
 arrCh
begin
 CPManager:=FindWindow('TCPManager_MainWindow', 'CP Manager');
 ListView:=FindWindowEx(CPManager, 0, 'TListView', nil);

 // ask the process ID of the other process
 GetWindowThreadProcessID(ListView, @pid);

 // open the other process
 ph := OpenProcess(PROCESS_ALL_ACCESS, false, pid);

 // allocate memory in the other process
 TmpPC := VirtualAllocEx(ph, nil, 255, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
 PListItem := VirtualAllocEx(ph, nil, sizeOf(LV_ITEM), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

 ItemCount:=ListView_GetItemCount(ListView);
 for CurrentPos:=0 to ItemCount-1 do begin
   ListItem.mask:=LVIF_TEXT;
   ListItem.iItem:=CurrentPos;
   ListItem.iSubItem:=0;
   ListItem.pszText:=TmpPC;
   ListItem.cchTextMax:=255;
   WriteProcessMemory(ph, PListItem, @ListItem, sizeOf(ListItem), c1);
   if ListView_GetItem(ListView, PListItem^) then begin
     ReadProcessMemory(
     ShowMessage(TmpPC);
   end;
 end;
 FreeMem(TmpPC);
end;
0
 
MoonCalfAuthor Commented:
Thanks.  I'll give it a try and get back.

MoonCalf.
0
 
MadshiCommented:
Sorry, I accidently hit the submit button, was not ready yet. Real code comes in a few moment...
0
 
MoonCalfAuthor Commented:
ok
0
 
MadshiCommented:
I guess this one should work in NT/2k/XP, but it will not work in 95/98/ME, because VirtualAllocEx is not supported there. Sorry, but you have to care about the 9x solution yourself, I told you how to do it, that's all I can do now, have no more time...

procedure ShowItems;
var CPManager,
    ListView    : hWnd;
    TmpPC       : PChar;
    PListItem   : ^LV_ITEM;
    ListItem    : LV_ITEM;
    CurrentPos,
    ItemCount   : Integer;
    pid         : dword;  // process ID
    ph          : dword;  // process handle
    c1          : dword;  // dummy variable
    arrCh       : array [0..255] of char;
begin
  CPManager:=FindWindow('TCPManager_MainWindow', 'CP Manager');
  ListView:=FindWindowEx(CPManager, 0, 'TListView', nil);

  // ask the process ID of the other process
  GetWindowThreadProcessID(ListView, @pid);

  // open the other process
  ph := OpenProcess(PROCESS_ALL_ACCESS, false, pid);

  // allocate memory in the other process
  TmpPC := VirtualAllocEx(ph, nil, 255, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  PListItem := VirtualAllocEx(ph, nil, sizeOf(LV_ITEM), MEM_COMMIT, PAGE_EXECUTE_READWRITE);

  ItemCount:=ListView_GetItemCount(ListView);
  for CurrentPos:=0 to ItemCount-1 do begin
    ListItem.mask:=LVIF_TEXT;
    ListItem.iItem:=CurrentPos;
    ListItem.iSubItem:=0;
    ListItem.pszText:=TmpPC;
    ListItem.cchTextMax:=255;

    // write the prepared item to the other process
    WriteProcessMemory(ph, PListItem, @ListItem, sizeOf(ListItem), c1);

    // ask the item content
    if ListView_GetItem(ListView, PListItem^) then begin

      // read the item string back from the other process and show it
      ReadProcessMemory(ph, TmpPC, @arrCh, 255, c1);
      ShowMessage(arrCh);
    end;
  end;
  // free the memory of the other process
  VirtualFreeEx(ph, TmpPC, 0, MEM_RELEASE);
  VirtualFreeEx(ph, PListItem, 0, MEM_RELEASE);

  // close handle
  CloseHandle(ph);
end;
0
 
DragonSlayerCommented:
Madshi rulez! :)
0
 
MoonCalfAuthor Commented:
What can I say?

Thanks Madshi, that was perfect.

Thanks everyone else, but Madshi's example has give me enough insight into this to get on with the project and do all that other stuff myself.

MoonCalf.
0
 
MadshiCommented:
Thanx, guys...   :-)
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

  • 6
  • 6
  • 4
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now