2013-02-20 82 views
0

我需要执行一项简单的任务:在浏览器窗口中打印列表视图项目的名称。假设我在桌面上打开“C:\ Documents and Settings”,那么我想要做的是使用JNA编写一个java程序,在打开的资源管理器窗口中打印所有文件夹/文件的名称。JNA:将指针传递给User32.dll的SendMessage函数作为LPARAM

我已经能够做到:获取打开的资源管理器窗口的句柄以及其内部的listview的句柄。

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

我创建了结构LVITEM在我的界面USER32如下:

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,而不是代表指针的长整型值。

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

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

我在做什么错?请帮忙。我已经花了很多时间研究,由于我是JNA的新手,没有能够理解发生了什么问题。

环境:Win XP的专业版, JNA版本:3.4

回答

1

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

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

我还建议在初始化User32库时使用W32APIOptions.DEFAULT_OPTIONS;它们会自动处理映射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位)。

+0

嗨technomage,谢谢你的回复。但我有一个问题。如何为SendMessage定义我自己的方法签名,其中第四个参数是LVITEM类型? 当我把: LRESULT SendMessageA(HWND hWnd,int Msg,WPARAM wParam,LVITEM lvItem);在用户32和 LRESULT lrs = User32.INSTANCE.SendMessageA(handleToListView,(0x1000 + 45),新的WPARAM(j),lvItem);我的程序只是在运行时崩溃。 – 2013-02-20 13:38:34

+0

另外,我是否需要通过显式地发出一些allocateMemory类型命令来将内存分配给结构? – 2013-02-20 13:43:23

+0

您的程序崩溃是因为您的'LVITEM'字段的大小不合适。 UINT将是4个字节,而不是两个,并且pszText必须是指针类型。 – technomage 2013-02-20 19:54:06