使用JNA在Windows资源管理器中获取所选文件项

时间:2014-01-07 10:12:43

标签: c# java windows winapi jna

我正在使用Java为Windows编写OSX快速查找替代方案,并且在如何在n活动的资源管理器窗口中获取文件的活动选择时出现问题,以下是我的尝试:

    @Override
    public void nativeKeyReleased(NativeKeyEvent e) {
        System.out.println("key up:"
                + NativeKeyEvent.getKeyText(e.getKeyCode()));
        if (e.getKeyCode() == NativeKeyEvent.VK_SPACE) {
            System.out.println("Space detected! intercept active window");
            char[] buffer = new char[MSWindowConstants.MAX_TITLE_LENGTH * 2];
            User32DLL.GetWindowTextW(User32DLL.GetForegroundWindow(),
                    buffer, MSWindowConstants.MAX_TITLE_LENGTH);
            System.out.println("Active window title: "
                    + Native.toString(buffer));

            PointerByReference pointer = new PointerByReference();
            User32DLL.GetWindowThreadProcessId(
                    User32DLL.GetForegroundWindow(), pointer);
            Pointer process = Kernel32.OpenProcess(
                    Kernel32.PROCESS_QUERY_INFORMATION
                            | Kernel32.PROCESS_VM_READ, false,
                    pointer.getValue());
            Psapi.GetModuleBaseNameW(process, null, buffer,
                    MSWindowConstants.MAX_TITLE_LENGTH);
            System.out.println("Active window process: "
                    + Native.toString(buffer));

            if(MSWindowConstants.SHELL_PROCESS_NAME.equals(Native.toString(buffer))){
                System.out.println("shell focused! intercept selection");
                // retrieve selected FileItems and get the path ...

                //Ole32.INSTANCE

            }



        }

MSEnumeration类:

public class MSEnumeration {



public static class Psapi {
    static {
        Native.register("psapi");
    }

    public static native int GetModuleBaseNameW(Pointer hProcess,
            Pointer hmodule, char[] lpBaseName, int size);
}

public static class Kernel32 {
    static {
        Native.register("kernel32");
    }
    public static int PROCESS_QUERY_INFORMATION = 0x0400;
    public static int PROCESS_VM_READ = 0x0010;

    public static native int GetLastError();

    public static native Pointer OpenProcess(int dwDesiredAccess,
            boolean bInheritHandle, Pointer pointer);
}

public static class User32DLL {
    static {
        Native.register("user32");
    }

    public static native int GetWindowThreadProcessId(HWND hWnd,
            PointerByReference pref);

    public static native HWND GetForegroundWindow();

    public static native int GetWindowTextW(HWND hWnd, char[] lpString,
            int nMaxCount);
}

//  public static class Shell32DLL{
//      static {
//          Native.register("shell32");
//      }
//      
//      public static native Shell32 Windows();
//  }
//  
//  public static class SHDocVwDLL{
//      static {
//          Native.register("shdocvw");
//      }
//      
//      public static native ShellWindows ShellWindows();
//      
//  }

}

我对如何在JNA中实现以下内容感到困惑:

Get current selection in WindowsExplorer from a C# application?

IntPtr handle = GetForegroundWindow();

List<string> selected = new List<string>();
var shell = new Shell32.Shell();
foreach(SHDocVw.InternetExplorer window in shell.Windows())
{
    if (window.HWND == (int)handle)
    {
        Shell32.FolderItems items =     ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
        foreach(Shell32.FolderItem item in items)
        {
            selected.Add(item.Path);
        }
    }
}

如何将其转换为JNA调用?

我查看了JNA的Shell32类和COM(Ole32类),但仍然没有让我到处找。

我现在能想到的唯一解决方法是将给定的C#编译成一个单独的可执行文件,它接受参数并返回文件的路径,但我真的不喜欢在java中嵌入另一个可执行文件的想法。

修改

取得一些进展:

public static final String CLSID_ShellWindows = "9BA05972-F6A8-11CF-A442-00A0C90A8F39";

public static final String IID_IShellWindows = "85CB6900-4D95-11CF-960C-0080C7F4EE85";

HRESULT hr = Ole32.INSTANCE
                        .CoCreateInstance(
                                GUID.fromString(CLSID_ShellWindows),
                                null,
                                WTypes.CLSCTX_ALL,
                                GUID.fromString(IID_IShellWindows),
                                p);

                System.out.println("result:" + W32Errors.SUCCEEDED(hr)
                        + "raw:" + hr.toString());

但由于某种原因结果永远不会......

1 个答案:

答案 0 :(得分:2)

我放弃了JNA(嗯,对于这项具体任务)并使用com4j(优秀的documentations)代替。

首先使用com4j中的shell32.dll

为您想要的dll生成代码,在本例中为tlbimp.jar

这个例子可能有点过时,但无论如何我都会把它放在这里

if (isExplorer(getHWNDProcessName(hwnd))) {
        IWebBrowser2 browser = getIWebBrowser2(hwnd);
        IShellFolderViewDual3 view = getIShellFolderViewDual3(browser);
        if (view != null && browser.visible()) {

            lastHWND = hwnd;
            FolderItems items = view.selectedItems();
            ArrayList<Path> paths = new ArrayList<>(items.count());
            for (Com4jObject object : items) {
                FolderItem item = object.queryInterface(FolderItem.class);
                if (item != null) {
                    paths.add(Paths.get(item.path()));
                    // this is for example only, do not create a new File just to get length
                    System.out.println("file: " + item.path() + " length: "
                            + new File(item.path()).length() + " type:" + item.type());
                }
            }
        }
    }


// some methods used in the example...

public static IWebBrowser2 getIWebBrowser2(HWND hWnd) {
    // TODO this can be potentially optimized
    IShellWindows windows = ClassFactory.createShell().windows()
            .queryInterface(IShellWindows.class);
    for (Com4jObject window : windows) {
        IWebBrowser2 browser = window.queryInterface(IWebBrowser2.class);
        if (browser.hwnd() == getHWNDValue(hWnd))
            return browser;
    }
    return null;
}

public static IShellFolderViewDual3 getIShellFolderViewDual3(IWebBrowser2 browser) {
    if (browser == null)
        return null;
    return browser.document().queryInterface(IShellFolderViewDual3.class);
}

注意:某些方法调用可能会丢失,我只发布了如何获取所选项目的基本部分。

重要

您需要同时使用Shell32.dllShdocvw.dll,因此您要做的是使用不同的dll生成代码两次

java -jar tlbimp.jar -o wsh -p test.wsh %WINDIR%\system32\Shell32.dll
java -jar tlbimp.jar -o wsh -p test.wsh %WINDIR%\system32\Shdocvw.dll

因此,我们可以使用IWebBrowser2和其他好东西,有关此类的功能列表,请参阅docs