当前位置: 首页 > 知识库问答 >
问题:

使用JNA从Win32 ListView检索项文本

赫连智
2023-03-14

我正在尝试从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++结构的大小相匹配。

这是我的用户32

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控件中检索了其他项信息,如count(使用LVM_GetTitemCount)或selected items(使用LVM_GETSELECTEDCOUNT)。

我回顾了几个类似的线程,例如:使用JNA和SendMessage()检索项目文本和JNA:将指向Structure的指针作为LPARAM传递给user32.dll的SendMessage函数以及web上的许多其他帖子,并实现了许多建议,但问题仍然存在。

任何能帮助我解决这个问题的建议都将不胜感激。

谢谢

共有1个答案

籍星汉
2023-03-14

我得到了这个工作,以防任何人有兴趣(草案版本):

    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);
 类似资料:
  • 我正在尝试使用查询检索dynamodb表中的所有项。下面是我的代码: 但是,我收到以下错误: 我的代码非常简单,出自boto dynamodb2文档,因此我不确定为什么会出现上述错误。任何见解都将受到赞赏(这是新的,有点迷失)。谢谢 编辑:我有一个散列键和一个范围键。我能够通过特定的哈希键进行查询。例如 但我如何检索所有项目?

  • 问题内容: 我有成千上万个包含多个JSON对象的文本文件,但是不幸的是,这些对象之间没有分隔符。对象存储为字典,它们的某些字段本身就是对象。每个对象可能具有可变数量的嵌套对象。具体来说,一个对象可能看起来像这样: 并在文本文件中串联了数百个这样的对象而没有分隔符。这意味着我既不能使用也不可以。 关于如何解决此问题的任何建议。是否有已知的解析器可以执行此操作? 问题答案: 这将从字符串中解码您的JS

  • 问题内容: 我正在学习Java,并且遇到了和的问题。 我有一个称为的对象,该对象具有从另一个名为的类创建的对象的数组列表。 我需要一种方法,其中返回item列表中一个对象的所有信息。 该随意选择的需求。 当我尝试编译时,出现错误,指出System.out.println行说.. 问题答案: 是一个方法,调用在你的return语句之后,因此由于无法访问而无法进行编译。 可能希望将其重写为:

  • 问题内容: 这是我第一次使用SAXParser(我在Android中使用它,但我认为这对这个特定问题没有影响),并且我正尝试从RSS feed中读取数据。到目前为止,它在很大程度上对我来说非常有用,但是当它到达包含HTML编码文本(例如)的标签时,我遇到了麻烦。该方法仅将读为,然后将下一组字符视为一个单独的实体,而不是立即获取全部内容。我希望它按原样阅读,而无需实际翻译HTML。我在文档处理程序中

  • 我需要从以下span元素中检索文本,而不需要将其拆分为文本部分。 我想检索一个没有破损的文本块。我正在使用这个xpath测试器http://www.freeformatter.com/xpath-tester.html

  • 我正在编写一个程序来模拟咖啡馆中的一个系统,在这个系统中,接受顾客订单的人给顾客一个代币号码,并将顾客的代币号码以及他/她订购的物品输入到一个系统中。recordOrder功能执行此操作,允许输入订单详细信息。订单由令牌ID、tID和表示订单中项目的字符串数组列表表示。 以下是我到目前为止所做的: 问题是,只有我输入的最后一个项目被打印出来,也就是说,假设我输入的令牌编号为9,项目编号为3,项目名