2013-02-20 79 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