Java JNA:将指向结构的指针作为LPRAM传递给User32.dll的SendMessage函数
我需要执行一项简单的任务:在资源管理器窗口中打印列表视图项的名称。假设我在桌面上打开“C:\Documents and Settings”,那么我要做的是使用JNA编写一个java程序,在打开的资源管理器窗口中打印出所有文件夹/文件的名称 我所能做的是:获取打开的资源管理器窗口的句柄以及其中listview的句柄 我发现:我需要调用User32.dll的SendMessage函数,并将句柄传递给上面找到的listview,以及消息代码(对于LVM_GETITEMTEXTA是(0x1000+45)),以及我需要获取名称的列表视图项的基于0的索引号,以及LPRAM(一个长值)。 此LPRAM将接受指向LVITEM类型结构的指针。 您可以在此处参阅该消息的文档: 我在User32的界面中创建了结构LVITEM,如下所示:Java JNA:将指向结构的指针作为LPRAM传递给User32.dll的SendMessage函数,java,winapi,jna,Java,Winapi,Jna,我需要执行一项简单的任务:在资源管理器窗口中打印列表视图项的名称。假设我在桌面上打开“C:\Documents and Settings”,那么我要做的是使用JNA编写一个java程序,在打开的资源管理器窗口中打印出所有文件夹/文件的名称 我所能做的是:获取打开的资源管理器窗口的句柄以及其中listview的句柄 我发现:我需要调用User32.dll的SendMessage函数,并将句柄传递给上面找到的listview,以及消息代码(对于LVM_GETITEMTEXTA是(0x1000+45)
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(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)));
}
我的结构初始化如下:
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(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)));
}
我在for循环中调用SendMessage函数以打印所有列表视图项的名称,如下所示:
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(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)));
}
for(int j=0;j如果在结构中使用基元数组,JNA将其解释为嵌套在本机结构中的基元数组。LVITEM
字段pszText
具有指针类型,更具体地说是表示可写字节缓冲区,因此必须使用内存(或NIO缓冲区)。使用String
仅适用于本机const char*
(即缓冲区为只读的)。调用后,您可以使用Pointer.getString(0)
从内存缓冲区提取本机NUL终止的字符串
至于将结构“转换”为LPARAM
值,没有必要。您可以为SendMessage
定义自己的方法签名,其中第四个参数的类型为LVITEM
(即本机struct*
)
我还建议您在初始化User32
库时使用w32api选项。默认\u选项
;它们会自动处理字符串
和发送消息
到适当的本机API映射(windows ANSI或UNICODE,默认为UNICODE)因此,您可以使用String
代替WString
和SendMessage
代替SendMessage w
编辑
用于分配被调用函数将写入的缓冲区:
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位,则会返回更多)。Hi-technomage,谢谢您的回答。但我有一个问题。如果第四个参数的类型为LVITEM,我将如何为SendMessage定义我自己的方法签名?当我输入:LRESULT SendMessageA(HWND HWND,int Msg,WPARAM WPARAM WPARAM,LVITEM LVITEM);在User32和的接口中,LRESULT lrs=User32.INSTANCE.SendMessageA(handleToListView,(0x1000+45),新WPARAM(j),lvItem);我的程序只是在运行时崩溃。另外,我是否需要通过显式发出一些allocateMemory类型命令来将内存分配给结构?您的程序崩溃是因为LVITEM
字段的大小不正确。UINT将是4字节,而不是2字节,并且pszText必须是指针类型。结构自动分配自己的内存,除非s您显式地将一个指针
传递给ctor。我已经尝试按照您的建议做了,下面就是我所做的!我在结构LVItem中将pszText声明为指针-公共指针pszText;LVItem的构造函数现在看起来如下所示:public LVItem(){Memory m=new Memory(260);pszText=m.getPointer(0);cchTextMax=260;}对sendmessage的调用现在是这样的:LRESULT lrs=User32.INSTANCE.SendMessageA(handleToListView,(0x1000+45),new WPARAM(1),lvItem);我让他们这样做:lvItem.read();