【问题标题】:Retrieving item text from Win32 ListView using JNA使用 JNA 从 Win32 ListView 中检索项目文本
【发布时间】:2014-04-12 22:34:34
【问题描述】:

我正在尝试从 Win32 ListView 控件 (SysListView32) 中检索项目信息(文本就足够了)。我正在使用 JNA 的 sendMessage() 发送 LVM_GETITEMTEXT。 SendMessage() 接受一个指向 LVITEM 结构的指针,如下所示 (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;

以下是我对 LVITEM 结构的 Java 实现:

    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; 
        }
    }

Java 结构的大小为 52 字节,应该与 C++ 结构的大小相匹配。

这是我的 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);
...
}

我这样声明我的结构:

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

根据其他两篇文章的一些建议(见下文),我尝试了不同的 SendMessage() 实现,但结果不同。例如:

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

程序使用 ListView 使第三方软件崩溃,并且不检索项目的文本。这是结构的转储(设置 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]

ret= 0

这意味着我没有得到任何回报和

lvi.pszText.getString(0) =  8 8

(奇怪的符号链,在这里不能很好地复制)。

如果我这样做:

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

我明白了:

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]

(所以结构是空的?)和

ret= 0

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

在这种情况下,带有 ListView 的第三方软件不会崩溃。

我已成功从 ListView 控件中检索其他项目信息,例如计数(使用 LVM_GETITEMCOUNT)或选定项目(使用 LVM_GETSELECTEDCOUNT)。

我查看了几个类似的主题,例如: Retrieving item text with JNA and SendMessage()JNA: Pass Pointer to Structure to SendMessage function of User32.dll as the LPARAM 以及网络上的许多其他帖子并实施了许多建议,但问题仍然存在。

任何帮助我解决此问题的建议将不胜感激。

谢谢

【问题讨论】:

    标签: java listview jna


    【解决方案1】:

    如果有人感兴趣,我可以使用它(草稿版):

        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);
    

    【讨论】:

    • 此代码不运行。例如lngMemVar1 为空,导致ReadProcessMemory 失败,Kernel32 方法被静态调用,而它们是实例方法。
    猜你喜欢
    • 2019-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多