JNA-如何从SysTreeView获取第一项

时间:2018-10-03 11:59:32

标签: java jna

尝试使用jna 4.5.2并在SysTreeView中遇到问题。

我的考试班:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.DesktopWindow;
import com.sun.jna.platform.WindowUtils;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.win32.W32APIOptions;

public class SysTreeViewExample {

    static final int TV_FIRST = 0x1100;

    static final int TVM_GETCOUNT = TV_FIRST + 5;
    static final int TVM_GETNEXTITEM = TV_FIRST + 10;
    static final int TVM_GETITEMW = TV_FIRST + 62;

    static final int TVGN_ROOT = 0;

    static final int TVIF_TEXT = 1;
    static final int TVIF_CHILDREN = 64;


    //https://docs.microsoft.com/en-us/windows/desktop/api/commctrl/ns-commctrl-tagtvitemw
    public static class TVITEMW extends Structure {

        private static final int MEMSIZE = 260;

        public WinDef.UINT mask;
        public WinNT.HANDLE hItem;
        public WinDef.UINT state;
        public WinDef.UINT stateMask;
        public Pointer pszText = new Memory(MEMSIZE);
        public int cchTextMax = MEMSIZE;
        public int iImage;
        public int iSelectedImage;
        public int cChildren;
        public WinDef.LPARAM lParam;

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("mask", "hItem", "state", "stateMask", "pszText", "cchTextMax", "iImage", "iSelectedImage", "cChildren", "lParam");
        }
    }

    public interface User32Ext extends User32 {

        User32Ext INSTANCE = Native.loadLibrary("user32", User32Ext.class, W32APIOptions.DEFAULT_OPTIONS);

        LRESULT SendMessageW(HWND hWnd, int msg, WPARAM wParam, TVITEMW tvitemw);
    }

    public static void main(String[] args) {

        List<DesktopWindow> timeTrackerWindows = WindowUtils.getAllWindows(false).stream()//
                .filter(desktopWindow -> desktopWindow.getFilePath().contains("TimeTracker.exe"))//
                .collect(Collectors.toList());

        List<WinDef.HWND> sysTreeViewHwnds = timeTrackerWindows.stream()//
                .map(DesktopWindow::getHWND)//
                .flatMap(windowHwnd -> {

                    List<WinDef.HWND> sysTreeViews = new ArrayList<>();

                    char[] buff = new char[8 * 1024];

                    User32.INSTANCE.EnumChildWindows(windowHwnd, (windowChildHwnd, data) -> {

                        User32.INSTANCE.GetClassName(windowChildHwnd, buff, buff.length);

                        String className = Native.toString(buff);
                        if (className.contains("SysTreeView"))
                            sysTreeViews.add(windowChildHwnd);

                        return true;
                    }, null);

                    return sysTreeViews.stream();
                })//
                .collect(Collectors.toList());

        sysTreeViewHwnds.forEach(sysTreeViewHwnd -> {
            //https://docs.microsoft.com/en-us/windows/desktop/controls/tvm-getcount
            WinDef.LRESULT countItems = User32.INSTANCE.SendMessage(sysTreeViewHwnd, TVM_GETCOUNT, new WinDef.WPARAM(0), new WinDef.LPARAM(0));
            System.out.println(countItems);//return correct value

            //https://docs.microsoft.com/en-us/windows/desktop/controls/tvm-getnextitem
            WinDef.LRESULT handleFirstItem = User32.INSTANCE.SendMessage(sysTreeViewHwnd, TVM_GETNEXTITEM, new WinDef.WPARAM(TVGN_ROOT), null);

            TVITEMW tvitemw = new TVITEMW();
            tvitemw.hItem = new WinNT.HANDLE(handleFirstItem.toPointer());
            tvitemw.mask = new WinDef.UINT(TVIF_TEXT | TVIF_CHILDREN);

            //https://docs.microsoft.com/en-us/windows/desktop/controls/tvm-getitem
            WinDef.LRESULT isGetItem = User32Ext.INSTANCE.SendMessageW(sysTreeViewHwnd, TVM_GETITEMW, new WinDef.WPARAM(0), tvitemw);
            System.out.println(isGetItem);// return 0
        });
    }
}

我不明白我在做什么错? 也许当尝试获取第一个SysTreeView项时

//https://docs.microsoft.com/en-us/windows/desktop/controls/tvm-
WinDef.LRESULT handleFirstItem = User32.INSTANCE.SendMessage(sysTreeViewHwnd, TVM_GETNEXTITEM, new WinDef.WPARAM(TVGN_ROOT), null);

或者在创建TVITEMW或发送消息TVM_GETITEMW时。

我使用了来自 JNA: Pass Pointer to Structure to SendMessage function of User32.dll as the LPARAM 但没有成功

在拥有SysTreeView的过程中,可能需要为TVITEMW分配内存,然后发送消息TVM_GETITEMW,然后选择TVITEMW。 但是怎么做,我没找到。

If I execute my code, I get an error.

1 个答案:

答案 0 :(得分:0)

我的解决方案: 1)SysTreeView过程中的VirtualAllocEx TVITEMW->获取指向分配内存的指针 2)在分配内存中写处理内存TVITEMW 3)SendMessage TVM_GETITEMW,指针从1开始 4)从1开始读取ProcessMemory指针 5)获取文字