Hi All,Â
Â
I’m trying to retrieve item information (text would be enough) from a Win32 ListView control (SysListView32) in an external application. I’m using JNA’s sendMessage() to send a LVM_GETITEM message. SendMessage () takes a pointer to a LVITEM structure (http://msdn.microsoft.com/en-us/library/windows/desktop/bb774760(v=vs.85).aspx). Here is my Java implementation of the LVITEM structure.
Â
public static class LVITEM extends Structure {
Â
       public static class ByReference extends LVITEM implements Structure.ByReference {}
Â
    public int mask;
    public int iItem;Â
    public int iSubItem;Â
    public int state;Â
    public int stateMask;Â
    public Pointer pszText;
    public int cchTextMax;Â
    public int iImage;Â
    public int lParam;Â
    public int iIndent;Â
Â
    @Override
    protected List getFieldOrder() {
      return Arrays.asList(new String[] {Â
         "mask",  "iItem",  "iSubItem",  "state", "stateMask", "pszText", "cchTextMax",  "iImage", "lParam",  "iIndent" });
    }
  }
Â
The size of the Java structure is 40 bytes which should match the size of the native structure.
Â
After reading a bunch my understanding is that I need to allocate memory space in the process of the external application. I have got some ideas in other posts. Here is my code (stripped of non relevant lines).
Â
This is my Kernel32:
Â
static class Kernel32 {
      Â
       static { Native.register("kernel32"); }
Â
       public static int PROCESS_QUERY_INFORMATION = 0x0400;
       public static int PROCESS_VM_OPERATION = 0x0008;
       public static int PROCESS_VM_WRITE = 0x0020;
       public static int PROCESS_VM_READ = 0x0010;
       public static int PAGE_READWRITE = 0x04;
       public static int MEM_RESERVE = 0x2000;
       public static int MEM_COMMIT = 0x1000;
      Â
      Â
       public static native int GetLastError();      Â
       public static native int OpenProcess(int dwDesiredAccess, boolean bInheritHandle, Pointer pointer);      Â
       public static native Pointer VirtualAllocEx(int ProcessToAllocateRamIn, int AddresToStartAt, int DesiredSizeToAllocate, int AllocationType, int  ProtectType);
       public static native int WriteProcessMemory(int hProcess, Pointer AdressToChange, Pointer ValuesToWrite,int nSize, IntByReference irgendwas);
      public static native int ReadProcessMemory (int hProcess, Pointer lpBaseAddress, Pointer lpBuffer, int nSize, IntByReference lpNumberOfBytesWritten);
Â
}
Â
My User32 looks like:
Â
public interface User32 extends StdCallLibrary {
           User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);  Â
          Â
           int LVM_FIRST                     = 0x1000;          // ListView Messages
           int LVM_GETITEM                   = LVM_FIRST + 5;
         Â
           int LVIF_TEXT = 0x0001;          // ListView Item Features
         Â
           int MEM_COMMIT = 0x00001000;
           int PAGE_READWRITE = 0x04;          Â
                             Â
           int SendMessage (WinDef.HWND hWnd, int msg, int wparam, Pointer lvItem);
           int GetWindowThreadProcessId(HWND hWnd, PointerByReference pref);
}
Â
Â
And here is the function that aims to retrieve the info for an item in the ListView:
Â
public static String GetListViewItem (HWND hWnd, int itemIdx){
Â
       PointerByReference lngProcID; int lngProcHandle;
       LVITEM lvi; String strLvItem;
       Pointer lngVarPtr1; Pointer lngVarPtr2;
       Pointer lngMemVar1; Pointer lngMemVar2;
       int lngMemLen1; int lngMemLen2;
      Â
//Get the process Id
       lngProcID = new PointerByReference();
       user32.GetWindowThreadProcessId(hWnd, lngProcID);
              Â
//Open process and get handle
       lngProcHandle = Kernel32.OpenProcess(Kernel32.PROCESS_VM_OPERATION | Kernel32.PROCESS_VM_WRITE | Kernel32.PROCESS_VM_READ, false, lngProcID.getValue());
     Â
Â
       lvi = new LVITEM();
       StringBuilder sb = new StringBuilder();
       sb.setLength(255);
       strLvItem = sb.toString();Â
    Â
       lngVarPtr1 = new NativeString(strLvItem,true).getPointer();
       lngVarPtr2 = lvi.getPointer();
       lngMemLen1 = strLvItem.length();
       lngMemLen2 = lvi.size();
      Â
             Â
       //Reserve or commit a region of memory within the virtual address space of the external process.
       lngMemVar1 = Kernel32.VirtualAllocEx(lngProcHandle, 0, lngMemLen1, Kernel32.MEM_RESERVE|Kernel32.MEM_COMMIT, Kernel32.PAGE_READWRITE);
       lngMemVar2 = Kernel32.VirtualAllocEx(lngProcHandle, 0, lngMemLen2, Kernel32.MEM_RESERVE|Kernel32.MEM_COMMIT, Kernel32.PAGE_READWRITE);
      Â
       IntByReference byteswritten1 = new IntByReference();
       IntByReference byteswritten2 = new IntByReference();
      Â
//Initialize structure’s elements
       lvi.cchTextMax = 255;
       lvi.iItem = itemIdx;
       lvi.iSubItem = 0;
       lvi.mask = 1;
       lvi.pszText = lngMemVar1;
      Â
//Write data to the external process memory      Â
       int a = Kernel32.WriteProcessMemory(lngProcHandle, lngMemVar1, lngVarPtr1, lngMemLen1, byteswritten1);
       int b = Kernel32.WriteProcessMemory(lngProcHandle, lngMemVar2, lngVarPtr2, lngMemLen2, byteswritten2);
      Â
//Send LVM_GETITEM message
       int r = user32.SendMessage (hWnd, User32.LVM_GETITEM, 0, lngMemVar2);
Â
//Read external process memory
       IntByReference bytesread = new IntByReference();
       b = Kernel32.ReadProcessMemory(lngProcHandle, lngMemVar1, lngVarPtr1, lngMemLen1, bytesread);
     Â
Â
       return strLvItem;
   }
Â
In summary, everything seems to run smoothly: the process Id is confirmed by spy++, I get a process handle and GetLastError() is 0 for VirtualAllocEx(),WriteProcessMemory() and ReadProcessMemory(). In WriteProcessMemory() byteswritten1= 255 and byteswritten2 = 40 as expected. In ReadProcessMemory (), bytesread= 255 as expected.
Â
However, at the end, strLvItem contains 255 null characters. I don’t seem to be able to recover the name of the items in the ListView. I don’t understand why everything runs without errors but I get nothing in my strLvItem String.
Â
I have been struggling with this for a couple of days and tried many things but nothing seems to work. I believe the problem is in passing the LVITEM structure to SendMessage() (although it runs without error).
Â
Any thoughts would be much appreciated.
Â
Thanks,
Â
EZ
--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
dB. | Moscow - Geneva - Seattle - New York
code.dblock.org - @dblockdotorg - artsy.net - github/dblock
I think the signature of ReadProcessMemory is incorrect. I could be wrong, but giving it a pointer doesn't actually copy the memory back, it probably needs something  ByReference?Would appreciate if you contributed these signatures to JNA proper, with tests.ThxdB.
...Any thoughts would be much appreciated. <u
    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);
EZ
...<p style="margin-botto
--
You received this message because you are subscribed to the Google Groups "Java Native Access" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jna-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.