我正在使用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());
但由于某种原因结果永远不会......
答案 0 :(得分:2)
我放弃了JNA(嗯,对于这项具体任务)并使用com4j(优秀的documentations)代替。
首先使用com4j中的shell32.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.dll
和Shdocvw.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