5

I've been trying to get the text of items in listview another process. I found an awesome tutorial on CodeProject. Thanks to this article I was able to do this on x32. But when try to run on x64, it crashes the application I'm trying to access when SendMessage is called. In the articles comments people had simliar problems because of different pointer sizes. Some people suggested using a x64 compiler which I cant use. I need my program to run on both x32/x64. One guy suggested:

I have the answer. The LVITEM structure is wrong under 64-bit systems. Pointers are 64-bit now, so the text pointer has to be followed by a dummy value, to offset the length member correctly.

I think this would be the best solution, as I could run it for x32 and x64 with one exe. I just have no idea how to do what hes talking about. I have included my code which currently works on x32. If anyone can help me out. That would be awesoem.

LVITEMLVITEM lvi, *_lvi;
char item[512];
char *_item;
unsigned long pid;
HANDLE process;

GetWindowThreadProcessId(procList, &pid);
process = OpenProcess(0x001f0fff, FALSE, pid);
_lvi = (LVITEM*)VirtualAllocEx(process, NULL, sizeof(LVITEM), 0x1000, 4);
_item = (char*)VirtualAllocEx(process, NULL, 512, 0x1000, 4);

lvi.cchTextMax = 512;
int r, c;
for (r = 0; r < rowCount; r++)
{
    for (c = 0; c < columnCount; c++)
    {
        lvi.iSubItem = c;
        lvi.pszText =_item;

        // Insert lvi into programs's memory
        WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL);
        // Have program write text to in its memory where we told it to
        SendMessage(procList, LVM_GETITEMTEXT, (WPARAM)r, (LPARAM)_lvi);
        // Get TVITEM back from programs
        ReadProcessMemory(process, _item, item, 512, NULL);
     }
 }
 // Clean up the mess we made
 VirtualFreeEx(process, _lvi, 0, MEM_RELEASE);
 VirtualFreeEx(process, _item, 0, MEM_RELEASE);
 CloseHandle(process);
Lienau
  • 1,353
  • 1
  • 20
  • 38
  • 1
    How does this compile? Won't work anyway if this is actually a 64-bit process. You need a 64-bit compiler. They are plentiful. – Hans Passant Dec 24 '10 at 21:54

2 Answers2

2

I don't think you'll be able to achieve this. In a 32 bit process your pointers will be too short. I believe that VirtualAllocEx will fail when called from a 32 bit process and with a 64 bit process handle as its first parameter. I think you would see this if you added error checking to your code.

Your only solution will be to have 2 versions, x86 and x64. That should be no real trouble - usually it can be done with single source.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Hmm, you might be able to get somewhere in x86 by using the lpAddress parameter of VirtualAllocEx to request memory which fits into a 32 bit pointer without truncation. But you will need to detect that the other process is a 64 bit process and modify the struct layout accordingly. And even then I would not be surprised if it still failed! – David Heffernan Dec 24 '10 at 22:33
  • When I comment out SendMessage, the other program does not crash. So I do not think the issue is with VirtualAllocEx. And I know compliing for both x32 and x64 would solve the problem but I would prefer to use the solution suggested in the comments on the article from codeproject that I quoted in my question if at all possible. – Lienau Dec 25 '10 at 00:26
  • @Lienau of course it only crashes when you send the data to the other process. That doesn't mean that the SendMessage call is wrong, just that the data is wrong. Did you do all the things I suggested? – David Heffernan Dec 25 '10 at 07:50
  • @Lienau No, I really don't think you will get this to work. And as Hans said, you should just have two versions, one for 32 bit and one for 64 bit. – David Heffernan Dec 25 '10 at 12:05
  • I guess I'm just going to have to go with the two versions. Thanks for your help. – Lienau Dec 25 '10 at 14:02
2

Sending LVM_GETITEMTEXT message from 32-bit application to 64-bit ListView is actually possible.

I was able to achieve this by using not the original LVITEM (60 bytes long) but LVITEM structure (88 bytes long) with seven 4-byte placeholders inserted between members. It works on my Win7 Pro 64-bit, though I have not tested this approach yet on other machines.

Below is the structure. This is C++, but nothing prevents us from doing the same in .NET.

typedef struct {
    UINT   mask;
    int    iItem;
    int    iSubItem;
    UINT   state;
    UINT   stateMask;

    int    placeholder1;
    LPTSTR pszText;
    int    placeholder11;

    int    cchTextMax;
    int    iImage;

    LPARAM lParam;
    int    placeholder2;

#if (_WIN32_IE >= 0x0300)
    int    iIndent;
#endif 

#if (_WIN32_WINNT >= 0x0501)
    int    iGroupId;

    UINT   cColumns;
    int    placeholder3;

    UINT   puColumns;
    int    placeholder4;
#endif 

#if (_WIN32_WINNT >= 0x0600)
    int    piColFmt;
    int    placeholder5;

    int    iGroup;
    int    placeholder6;
#endif 
} LVITEM64, *LPLVITEM64;
Anatoliy
  • 21
  • 1
  • Can you please provide a sample source which contains the struct above and sends 'LVM_GETITEMTEXT ' between 32bitprocess and 64bitprocess? – Csabi Jul 23 '13 at 17:22