JNA: Pass Pointer to Structure to SendMessage function of User32.dll as the LPARAM

一笑奈何 提交于 2019-11-28 12:43:39

问题


I need to perform a simple task : Print out the names of the list view items inside an explorer window. Suppose, I open "C:\Documents and Settings" on my desktop, then what I want to do is that write a java program using JNA to print out all the names of the folders / files within the opened explorer window.

What I have been able to do: Get the handle of the opened explorer window and the handle to the listview inside it.

What I have found out: I need to call the SendMessage function of User32.dll and pass it the handle to the listview found above, along with the message code (which is (0x1000 + 45) for LVM_GETITEMTEXTA), along with the 0 based index number of the list view item whose name I need to get, and, an LPARAM (which is a long value). This LPARAM will accept a pointer to a structure of type LVITEM. You can refer the documentation of the message here : http://msdn.microsoft.com/en-us/library/windows/desktop/bb761055(v=vs.85).aspx

I have created the structure LVITEM in my interface for User32 as follows:

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" });
        }

    }

My structure initialization is as follows:

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;

I am calling the SendMessage function inside a for loop to print the names of all the list view items as follows:

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)));
}

If I print lvItem.getPointer().getLong(0) - I get 0, instead of a long value which represents the pointer.

If I print lrs or lvItem.pszText - I dont get the name of the folder. I get a blank value / 0.

I know that the JNA documentation says that a pointer to a structure is treated as a structure in JNA. But if I dont do lvItem.getPointer, then how will I be able to convert the structure to a long value which is required as an argument to the LPARAM constructor?

What am I doing wrong? Please help. I have already spent alot of time researching and since I am new to JNA, havent been able to understand what is going wrong.

Environment: Win XP Pro, JNA version : 3.4


回答1:


If you use a primitive array within a Structure, JNA interprets it as a primitive array nested within the native struct. The LVITEM field pszText has pointer type, and more specifically represents a writable byte buffer, so you must use Memory (or an NIO buffer). Using String is only appropriate for native const char * (i.e. where the buffer is read-only). After the call, you can use Pointer.getString(0) to extract the native NUL-terminated string from the memory buffer.

As for "converting" a structure into an LPARAM value, there's no need. You are free to define your own method signature for SendMessage where the fourth parameter is of type LVITEM (i.e. a native struct *).

I'd also recommend using the W32APIOptions.DEFAULT_OPTIONS when initializing your User32 library; they automatically handle mapping String and SendMessage to the appropriate native API mappings (windows ANSI or UNICODE, defaulting to UNICODE) so you can use String instead of WString and SendMessage instead of SendMessageW.

EDIT

For allocating the buffer to which the called function will write:

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

The above structure (LVITEM) should return 60 for its size (more if you're on 64-bit).



来源:https://stackoverflow.com/questions/14975347/jna-pass-pointer-to-structure-to-sendmessage-function-of-user32-dll-as-the-lpar

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!