0

我需要执行一个简单的任务:在资源管理器窗口中打印出列表视图项的名称。假设我在桌面上打开“C:\Documents and Settings”,然后我想做的是使用 JNA 编写一个 java 程序来打印打开的资源管理器窗口中的所有文件夹/文件的名称。

我能做的:获取打开的资源管理器窗口的句柄和其中的列表视图的句柄。

我发现了什么:我需要调用 User32.dll 的 SendMessage 函数并将它的句柄传递给上面找到的列表视图,以及消息代码(对于 LVM_GETITEMTEXTA 是 (0x1000 + 45)),以及基于 0我需要获取其名称的列表视图项的索引号,以及一个 LPARAM(它是一个长值)。该 LPARAM 将接受指向 LVITEM 类型结构的指针。您可以在此处参考消息的文档:http: //msdn.microsoft.com/en-us/library/windows/desktop/bb761055 (v=vs.85).aspx

我在 User32 的界面中创建了结构 LVITEM,如下所示:

public static class LVITEM extends Structure
    {
        public short mask;
        public int iItem;
        public int iSubItem;
        public short state;
        public short stateMask;
        public char[] pszText;
        public int cchTextMax;
        public int iImage;
        public LPARAM lParam;
        public int iIndent;

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

    }

我的结构初始化如下:

User32.LVITEM lvItem = new User32.LVITEM(); //User32 is the name of the interface containing the LVITEM structure
lvItem.mask = 0x00000001; //code for LVIF_TEXT
lvItem.pszText= new char[260];
lvItem.iSubItem = 0;
lvItem.cchTextMax = 260;

我在 for 循环中调用 SendMessage 函数来打印所有列表视图项的名称,如下所示:

for(int j=0;j<nItems;j++)
{
lvItem.iItem= j;
LRESULT lrs = User32.INSTANCE.SendMessageA(handleToListView, (0x1000 + 45) , new WPARAM(j), new LPARAM(lvItem.getPointer().getLong(0)));
}

如果我打印 lvItem.getPointer().getLong(0) - 我得到 0,而不是代表指针的 long 值。

如果我打印 lrs 或 lvItem.pszText - 我没有得到文件夹的名称。我得到一个空白值/ 0。

我知道 JNA 文档说指向结构的指针在 JNA 中被视为结构。但是,如果我不执行 lvItem.getPointer,那么我将如何将结构转换为作为 LPARAM 构造函数的参数所需的长值?

我究竟做错了什么?请帮忙。我已经花了很多时间进行研究,而且由于我是 JNA 的新手,所以无法理解出了什么问题。

环境:Win XP Pro,JNA 版本:3.4

4

1 回答 1

1

如果在 a 中使用原始数组Structure,JNA 会将其解释为嵌套在本机 中的原始数组struct。该LVITEM字段pszText具有指针类型,并且更具体地表示可写字节缓冲区,因此您必须使用Memory(或 NIO 缓冲区)。UsingString仅适用于本机const char *(即缓冲区是只读的)。调用后,您可以使用Pointer.getString(0)从内存缓冲区中提取本机以 NUL 结尾的字符串。

至于将结构“转换”为LPARAM值,则没有必要。SendMessage对于第四个参数的类型LVITEM(即 native struct *),您可以自由定义自己的方法签名。

我还建议W32APIOptions.DEFAULT_OPTIONS在初始化User32库时使用;它们会自动处理映射StringSendMessage到适当的本机 API 映射(Windows ANSI 或 UNICODE,默认为 UNICODE),因此您可以使用String代替WStringSendMessage代替SendMessageW.

编辑

分配被调用函数将写入的缓冲区:

public static class LVITEM extends Structure
{
    ...
    private static final int MEMSIZE = 260;
    public Pointer pszText = new Memory(MEMSIZE);
    public int cchTextMax = MEMSIZE;

上述结构 (LVITEM) 的大小应返回 60(如果您使用 64 位,则返回更多)。

于 2013-02-20T12:52:05.833 回答