我正在学习新的 Java FFM API。 在学习过程中,我决定使用Windows SDK来控制
Taskbar
。
界面
ITtaskbarList3
代表Taskbar
并提供控制它的功能。
我使用
jextract
工具生成必要的类:
jextract --output target/generated-sources/jextract -t "taskbar_test.gen" -l :shell32 -l :Explorerframe -l :ole32 -I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\shared" -I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um" -I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\km" -I "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\km\crt" "C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\ShObjIdl_core.h"
在下面的代码中,我尝试从
CLSID
获取 IID
和 string
并使用它们来获取 ITaskbarList3
的实例:
package taskbar_test;
import taskbar_test.gen.CLSID;
import taskbar_test.gen.ShObjIdl_core_h;
import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
public class ComStart {
public static final String GUID_FORMAT = "{%s}";
// CLSID of ITaskbarList3
public static final String CLSID_CONST = "56FDF344-FD6D-11d0-958A-006097C9A090";
// IID of ITaskbarList3
public static final String IID_CONST = "EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF";
public static void main(String[] args) {
try (var arena = Arena.ofConfined()) {
// https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-clsidfromstring#remarks
// The CLSID format is {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}.
var clsidString = arena.allocateFrom(GUID_FORMAT.formatted(CLSID_CONST));
var iidString = arena.allocateFrom(GUID_FORMAT.formatted(IID_CONST));
var clsid = arena.allocate(CLSID.layout());
var iid = arena.allocate(CLSID.layout());
var taskbarPtr = arena.allocate(ShObjIdl_core_h.C_POINTER);
int hr = ShObjIdl_core_h.CoInitializeEx(MemorySegment.NULL, ShObjIdl_core_h.COINIT_MULTITHREADED());
if (hr != ShObjIdl_core_h.S_OK()) {
throw new RuntimeException("CoInitialize failed with error code: " + hr);
}
hr = ShObjIdl_core_h.CLSIDFromString(clsidString, clsid);
if (hr != ShObjIdl_core_h.S_OK()) {
throw new RuntimeException("CLSIDFromString failed with error code: " + hr);
}
hr = ShObjIdl_core_h.IIDFromString(iidString, iid);
if (hr != ShObjIdl_core_h.S_OK()) {
throw new RuntimeException("IIDFromString failed with error code: " + hr);
}
hr = ShObjIdl_core_h.CoCreateInstance(clsid, MemorySegment.NULL, ShObjIdl_core_h.CLSCTX_REMOTE_SERVER(), iid, taskbarPtr);
if (hr != ShObjIdl_core_h.S_OK()) {
if (hr == ShObjIdl_core_h.REGDB_E_CLASSNOTREG()) {
System.out.println("COM class is not registered!");
}
throw new RuntimeException("CoCreateInstance failed with error code: " + hr);
}
} finally {
ShObjIdl_core_h.CoUninitialize();
}
}
}
我希望获得实例,但我从函数
CLSIDFromString
得到错误,字符串的格式不正确。我不明白为什么,因为格式遵循文档。
代码应该是什么样子才能正确获取实例,以便我可以管理任务栏,即设置进度值。
谢谢你。
您已使用 UTF-8 编码将 String 转换为 MemorySegment,这是
allocateFrom(String)
的默认编码。指定 Windows 宽字符集 UTF_16LE 作为 allocateFrom: 的额外参数
var clsidString = arena.allocateFrom(GUID_FORMAT.formatted(CLSID_CONST), StandardCharsets.UTF_16LE);
var iidString = arena.allocateFrom(GUID_FORMAT.formatted(IID_CONST), StandardCharsets.UTF_16LE);