【发布时间】: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 以及网络上的许多其他帖子并实施了许多建议,但问题仍然存在。
任何帮助我解决此问题的建议将不胜感激。
谢谢
【问题讨论】: