Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LVM_GETITEMTEXT for x32 and x64 in C

Tags:

c

listview

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);
like image 956
Lienau Avatar asked Oct 14 '22 19:10

Lienau


2 Answers

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.

like image 63
David Heffernan Avatar answered Nov 12 '22 23:11

David Heffernan


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;
like image 36
Anatoliy Avatar answered Nov 12 '22 21:11

Anatoliy