El vengador de la capa El vengador de la capa - 1 month ago 4
Java Question

Retrieving item text from Win32 ListView using JNA

I’m trying to retrieve item information (text would be enough) from a Win32 ListView control (SysListView32). I’m using JNA’s sendMessage() to send LVM_GETITEMTEXT. SendMessage () takes a pointer to a LVITEM structure which looks like this (http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760(v=vs.85).aspx):

typedef struct {
UINT mask;
int iItem;
int iSubItem;
UINT state;
UINT stateMask;
LPTSTR pszText;
int cchTextMax;
int iImage;
LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
int iIndent;
#endif
#if (_WIN32_WINNT >= 0x0501)
int iGroupId;
UINT cColumns;
UINT puColumns;
#endif
#if (_WIN32_WINNT >= 0x0600)
int piColFmt;
int iGroup;
#endif
} LVITEM, *LPLVITEM;


The following is my Java implementation of the LVITEM structure:

public static class LVITEM extends Structure {
public WinDef.UINT mask;
public int iItem;
public int iSubItem;
public WinDef.UINT state;
public WinDef.UINT stateMask;
public Pointer pszText;
public int cchTextMax;
public int iImage;
public WinDef.LPARAM lParam;
public int iIndent;
public int iGoupId;
public WinDef.UINT cColumns;
public WinDef.UINT puColumns;

@Override
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"mask", "iItem", "iSubItem", "state", "stateMask", "pszText", "cchTextMax", "iImage", "lParam", "iIndent", "iGoupId", "cColumns", "puColumns" });
}

//Constructor
public LVITEM() {
Memory m = new Memory(260);
mask = new WinDef.UINT((long)1); //code for LVIF_TEXT
iItem = 0;
iSubItem = 0; //no subitem
pszText = m.getPointer(0);
cchTextMax = 260;
iImage = 0;
lParam = new WinDef.LPARAM(0);
iIndent = 0;
}
}


The size of the Java structure is 52 bytes which should match the size of the C++ structure.

This is my User32

public interface User32 extends StdCallLibrary {
User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);
...
int SendMessage (WinDef.HWND hWnd, int msg, WinDef.WPARAM wparam, LVITEM lvItem);
//Several alternative definitions
//int SendMessage (WinDef.HWND hWnd, int msg, int wparam, Pointer lvItem);
...
}


I declare my structure like this:

LVITEM lvi = new LVITEM();
lvi.iItem = itemIdx; // the zero-based index of the ListView item


Based on some suggestions from two other posts (see below) I have tried different implementations of SendMessage() with different results. For instance:

int ret = user32.SendMessage(hWnd, User32.LVM_GETITEMTEXT, 0,lvi);


The program crashes the third party software with the ListView and doesn’t retrieve the text of the item. This is the dump of the structure (setting jna.dump_memory=true):

ListView$LVITEM(auto-allocated@0x3173e08 (52 bytes)) {
WinDef$UINT mask@0=1
int iItem@4=0
int iSubItem@8=0
WinDef$UINT state@c=0
WinDef$UINT stateMask@10=0
Pointer pszText@14=native@0x380338
int cchTextMax@18=104
int iImage@1c=0
WinDef$LPARAM lParam@20=0
int iIndent@24=0
int iGoupId@28=0
WinDef$UINT cColumns@2c=0
WinDef$UINT puColumns@30=0
}
memory dump
[01000000]
[00000000]
[00000000]
[00000000]
[00000000]
[38033800]
[04010000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]


and

ret= 0


which means I didnt get anything back and

lvi.pszText.getString(0) = 8 8


(weird chain of symbols which don't copy well here).

If for instance I do:

int ret = user32.SendMessage(hWnd, User32.LVM_GETITEMTEXT, new WPARAM(0),new LPARAM(lvi.getPointer().getLong(0)));


I get:

ListView$LVITEM(auto-allocated@0x31733e0 (52 bytes)) {
WinDef$UINT mask@0=1
int iItem@4=0
int iSubItem@8=0
WinDef$UINT state@c=0
WinDef$UINT stateMask@10=0
Pointer pszText@14=native@0x380178
int cchTextMax@18=104
int iImage@1c=0
WinDef$LPARAM lParam@20=0
int iIndent@24=0
int iGoupId@28=0
WinDef$UINT cColumns@2c=0
WinDef$UINT puColumns@30=0
}
memory dump
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]
[00000000]


(so the structure is empty?) and

ret= 0


and

lvi.pszText.getString(0) = 05 05 � 8


In this case the third party software with the ListView does not crash.

I have been successful retrieving other item information from the ListView control like count (with LVM_GETITEMCOUNT) or selected items (with LVM_GETSELECTEDCOUNT).

I have reviewed a couple of similar threads such as:
Retrieving item text with JNA and SendMessage()
and
JNA: Pass Pointer to Structure to SendMessage function of User32.dll as the LPARAM
and many other posts on the web and implemented many the suggestions, but the problem persists.

Any suggestions to help me resolve this would be much appreciated.

Thank you

Answer

I got this to work in case anyone is interested (draft version):

    PointerByReference lngProcID;
    int lngProcHandle;
    LVITEM lvi;
    int strSize = 255;
    int result = 0;
    IntByReference byteIO = new IntByReference();
    Pointer lngVarPtr1 = null;Pointer lngMemVar1 = null;
    Pointer lngVarPtr2 = null;Pointer lngMemVar2 = null;
    Pointer lviVarPtr = null;Pointer lviVar = null;
    int lngMemLen1; int lngMemLen2;

    lngProcID = new PointerByReference();
    int ThreadId = user32.GetWindowThreadProcessId(hWnd, lngProcID);

    lngProcHandle = Kernel32.OpenProcess(Kernel32.PROCESS_VM_OPERATION | Kernel32.PROCESS_VM_WRITE | Kernel32.PROCESS_VM_READ, false, lngProcID.getValue());

    lvi = new LVITEM();
    lngMemLen1 = strSize;
    lngMemLen2 = lvi.size(); 

    lngMemVar2 = Kernel32.VirtualAllocEx(lngProcHandle, 0, lngMemLen2, Kernel32.MEM_RESERVE|Kernel32.MEM_COMMIT, Kernel32.PAGE_READWRITE);        

    lvi.cchTextMax = strSize;
    lvi.iItem = itemIdx;
    lvi.iSubItem = 0;
    lvi.mask = User32.LVIF_TEXT;
    lvi.pszText = lngMemVar1;       

    //result  = Kernel32.WriteProcessMemory(lngProcHandle, lngMemVar1, lngVarPtr1, lngMemLen1, byteswritten1);
    result = Kernel32.WriteProcessMemory(lngProcHandle, lngMemVar2, lvi, lngMemLen2, byteIO);

    result = user32.SendMessage (hWnd, User32.LVM_GETITEM, 0, lngMemVar2);

   lngVarPtr1 = new Memory(strSize + 1);
   result = Kernel32.ReadProcessMemory(lngProcHandle, lngMemVar1, lngVarPtr1, lngMemLen1, byteIO);

    result = Kernel32.VirtualFreeEx (lngProcHandle, lngMemVar1, 0, Kernel32.MEM_RELEASE);
    result = Kernel32.VirtualFreeEx (lngProcHandle, lngMemVar2, 0, Kernel32.MEM_RELEASE);        
    result = Kernel32.CloseHandle(lngProcHandle);

    return lngVarPtr1.getWideString(0);
Comments