0

簡単なタスクを実行する必要があります。エクスプローラ ウィンドウ内のリスト ビュー アイテムの名前を出力します。デスクトップで「C:\Documents and Settings」を開き、JNA を使用して Java プログラムを作成し、開いたエクスプローラー ウィンドウ内のフォルダー/ファイルのすべての名前を出力するとします。

私ができたこと:開いているエクスプローラーウィンドウのハンドルと、その中のリストビューへのハンドルを取得します。

私が発見したこと: User32.dll の SendMessage 関数を呼び出し、上記のリストビューへのハンドルと、メッセージ コード (LVM_GETITEMTEXTA の場合は (0x1000 + 45)) を渡す必要があります。名前を取得する必要があるリスト ビュー アイテムのインデックス番号、および 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) を出力すると、ポインタを表す long 値の代わりに 0 が返されます。

lrs または lvItem.pszText を印刷すると、フォルダーの名前がわかりません。空白の値 / 0 を取得します。

JNA のドキュメントには、構造体へのポインターは JNA では構造体として扱われると書かれていることは知っています。しかし、lvItem.getPointer を実行しない場合、構造体を LPARAM コンストラクターへの引数として必要な long 値に変換するにはどうすればよいでしょうか?

私は何を間違っていますか?助けてください。私はすでに多くの時間を調査に費やしてきましたが、JNA を初めて使用するため、何が問題なのか理解できませんでした。

環境:Win XP Pro、JNAバージョン:3.4

4

1 に答える 1

1

内でプリミティブ配列を使用するとStructure、JNA はそれをネイティブ 内にネストされたプリミティブ配列として解釈しstructます。LVITEMフィールドにはポインター型があり、pszTextより具体的には書き込み可能なバイトバッファーを表すため、Memory(または NIO バッファー) を使用する必要があります。使用は、ネイティブ(つまり、バッファーが読み取り専用の場合) にStringのみ適しています。呼び出しの後、メモリ バッファからネイティブ NUL 終了文字列を抽出するためにconst char *使用できます。Pointer.getString(0)

構造体を値に「変換」するLPARAM必要はありません。SendMessage4 番目のパラメーターの型LVITEM(つまり、ネイティブ) については、独自のメソッド シグネチャを自由に定義できますstruct *

ライブラリW32APIOptions.DEFAULT_OPTIONSを初期化するときにも使用することをお勧めします。User32これらは自動的にマッピングStringを処理し、適切なネイティブ API マッピング (Windows ANSI または UNICODE、デフォルトは UNICODE) へのマッピングを処理するため、およびの代わりにをSendMessage使用できます。StringWStringSendMessageSendMessageW

編集

呼び出された関数が書き込むバッファを割り当てるには:

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 に答える