Solved

Help converting C++ Code to Delphi...

Posted on 2002-04-30
7
349 Views
Last Modified: 2010-04-04
I have this code from one of Jeffrey Richter's articles in
the September version of MSJ {watch for wrap}
(http://www.microsoft.com/msj/defaultframe.asp?
page=/msj/0997/win320997.htm&nav=/msj/0997/newnav.htm)
that will read the contents of another app's Listview to
the clipboard.

I need to be able to read the ItemText to defined class.
Can someone help me out with the conversion process?

Here's the C++ Code, the attempted Delphi conversion is
below...

   // Open a handle to the remote process's kernel object
   DWORD dwProcessId;
   GetWindowThreadProcessId(hwndLV, &dwProcessId);
   HANDLE hProcess = OpenProcess(
      PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
      FALSE, dwProcessId);

   if (hProcess == NULL) {
      MessageBox(hwnd, __TEXT("Could not communicate with process"),
         g_szAppName, MB_OK | MB_ICONWARNING);
      return;
   }

   // Prepare a buffer to hold the ListView's data.
   // Note: Hardcoded maximum of 10240 chars for clipboard data.
   // Note: Clipboard only accepts data that is in a block allocated
   //       with GlobalAlloc using the GMEM_MOVEABLE
   //            and GMEM_DDESHARE flags.
   HGLOBAL hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
                                  sizeof(TCHAR) * 10240);
   LPTSTR pClipData = (LPTSTR) GlobalLock(hClipData);
   pClipData[0] = 0;

   // Allocate memory in the remote process's address space
   LV_ITEM* plvi = (LV_ITEM*) VirtualAllocEx(hProcess,
                    NULL, 4096, MEM_RESERVE | MEM_COMMIT,
                    PAGE_READWRITE);

   // Get each ListView item's text data
   for (int nIndex = 0; nIndex < nCount; nIndex++) {

      // Initialize a local LV_ITEM structure
      LV_ITEM lvi;
      lvi.mask = LVIF_TEXT;
      lvi.iItem = nIndex;
      lvi.iSubItem = 0;
      // NOTE: The text data immediately follows the LV_ITEM structure
      //       in the memory block allocated in the remote process.
      lvi.pszText = (LPTSTR) (plvi + 1);
      lvi.cchTextMax = 100;

      // Write the local LV_ITEM structure to the remote memory block
      WriteProcessMemory(hProcess, plvi, &lvi, sizeof(lvi), NULL);

      // Tell the ListView control to fill the remote LV_ITEM structure
      ListView_GetItem(hwndLV, plvi);

      // If this is not the first item, add a carriage-return/linefeed
      if (nIndex > 0) lstrcat(pClipData, __TEXT("\r\n"));

      // Read the remote text string into the end of our
      // clipboard buffer
      ReadProcessMemory(hProcess, plvi + 1,
         &pClipData[lstrlen(pClipData)], 1024, NULL);
   }

   // Free the memory in the remote process's address space
   VirtualFreeEx(hProcess, plvi, 0, MEM_RELEASE);

   // Cleanup and put our results on the clipboard
   CloseHandle(hProcess);
   OpenClipboard(hwnd);
   EmptyClipboard();
   BOOL fOk = (SetClipboardData(CF_TEXT, hClipData) == hClipData);
   CloseClipboard();
   if (!fOk) {
      GlobalFree(hClipData);
      MessageBox(hwnd, __TEXT("Error putting text on the clipboard"),
             g_szAppName, MB_OK | MB_ICONINFORMATION);
   }


****************** Delphi code *********************

var
  Buffer: PChar;
  Len: Integer;
  dwProcessId, numbytes: DWORD;
  plvi: Pointer;
  lvi: LV_ITEM;
  hProcess : THandle;
  nIndex: Integer;
begin
  // Open a handle to the remote process's kernel object
  // Passing Handle of the listview to this function
  GetWindowThreadProcessId(Handle, @dwProcessId);
  hProcess := OpenProcess(PROCESS_VM_OPERATION or
                          PROCESS_VM_READ or
                          PROCESS_VM_WRITE,FALSE, dwProcessId);
  if hProcess = 0 then
    ShowMessage('Could not communicate with process');
  // Prepare a buffer to hold the ListView's data.
  // Note: Hardcoded maximum of 10240 chars for clipboard data.
  // Note: Clipboard only accepts data that is in a block
  //       allocated with GlobalAlloc using the GMEM_MOVEABLE and    
  //       GMEM_DDESHARE flags.
  // Allocate memory in the remote process's address space
  plvi := VirtualAllocEx(hProcess, 0, 4096,
                         MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
  // Get each ListView item's text data
  // This class has a Count property that is populated with the
  // count of items in the listview.
  for nIndex := 0 to Count do
  begin
    // Initialize a local LV_ITEM structure
    lvi.mask := LVIF_TEXT;
    lvi.iItem := nIndex;
    lvi.iSubItem := 0;
    // NOTE: The text data immediately follows the LV_ITEM structure
    //       in the memory block allocated in the remote process.
    lvi.pszText := PChar(plvi);
    lvi.cchTextMax := 100;
    // Write the local LV_ITEM structure to the remote memory block
    WriteProcessMemory(hProcess, plvi, @lvi, sizeof(lvi), numbytes);
    // Tell the ListView control to fill the remote LV_ITEM structure
    ListView_GetItem(Handle, lvi);
    // Read the remote text string into the end of our clipboard buffer
    ReadProcessMemory(hProcess, PChar(plvi), @Buffer, 1024, numbytes);
    // Now that we have the text, let's add it to our stringlist.
    Items.Add(String(Buffer); // Items is a TStringList in the class.
  end;
  // Free the memory in the remote process's address space
  VirtualFreeEx(hProcess, plvi, 0, MEM_RELEASE);
  // Cleanup and put our results on the clipboard
  CloseHandle(hProcess);
end;
0
Comment
Question by:EddieShipman
  • 4
  • 3
7 Comments
 
LVL 20

Accepted Solution

by:
Madshi earned 100 total points
ID: 6981268
Seems like Jeffrey Richter had the same idea that I had, didn't know his article. Anyway, here is a question with the same topic, I answered there with full Delphi code:

http://www.experts-exchange.com/delphi/Q.20288008.html

Please note that both my code there and Jeffrey's code here only works in NT based systems (NT4, 2k, XP), not in win9x/ME. But I've added a comment to the other question about how to do it in win9x/ME. It's possible, there, too. With a bit of hacking...

Regards, Madshi.
0
 
LVL 26

Author Comment

by:EddieShipman
ID: 6981306
I see you only handle subitem 0 in that code. How would I get ALL the subitems. Basically, I want to "clone" the listview from another app to my listview...
0
 
LVL 20

Expert Comment

by:Madshi
ID: 6981344
Well, Jeffrey's code also only handles subitem 0 or am I missing something?   :-)

Anyway, you can give in other subitem indexes, of course, too. No problem...
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 26

Author Comment

by:EddieShipman
ID: 6981576
The GrabListView program from the other thread really worked for me...Thanks for the link...
You get the points...

BTW, do you frequent the Borland NG's? What is your
NG handle?

0
 
LVL 20

Expert Comment

by:Madshi
ID: 6981625
Thanx for the points. What is "Borland NG"?
0
 
LVL 26

Author Comment

by:EddieShipman
ID: 6981639
Borland newsgroups on forums.borland.com.

If not, I think you should, as your knowledge could be very
useful there. You would probably qualify for TeamB admission. TeamB is the group of experts whit very in-depth
knowledge of Delphi...

0
 
LVL 26

Author Comment

by:EddieShipman
ID: 6981643
I'm surprised you didn't know about them, you've posted a few messages there:

"Mathias Rauen" <madshi@gmx.net>

Hey, I'm also surprised you place your bank account info on your web site..
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now