将 Java 应用程序固定到 Windows 7 任务栏

我在Windows 7下使用Launch4j作为我的Java应用程序的包装器,据我所知,它本质上分叉了一个实例,反过来又解释了Java代码。因此,当尝试将应用程序固定到任务栏时,Windows 会改为固定 。如果没有所需的命令行,我的应用程序将无法运行。javaw.exejavaw.exe

Result of pinning a Launch4j application to the taskbar

如您所见,Windows也没有意识到Java是主机应用程序:应用程序本身被描述为“Java(TM)Platform SE二进制文件”。

我已尝试更改注册表项以添加值 。这通过完全禁用我的应用程序的固定来改变行为;显然不是我想要的。HKEY_CLASSES_ROOT\Applications\javaw.exeIsHostApp

Result of specifying javaw.exe as a host application

在阅读了 Windows 如何解释单个应用程序的实例(以及本问题中讨论的一种现象)之后,我开始对将应用程序用户模型 ID (AppUserModelID) 嵌入到我的 Java 应用程序中产生了兴趣。

我相信我可以通过将唯一的Windows传递给Windows来解决此问题。有一种方法,SetCurrentProcessExplicitAppUserModelID。根据Gregory Pakosz的建议,我实现了它,试图将我的应用程序识别为以下的单独实例:AppUserModelIDshell32javaw.exe

NativeLibrary lib;
try {
    lib = NativeLibrary.getInstance("shell32");
} catch (Error e) {
    Logger.out.error("Could not load Shell32 library.");
    return;
}
Object[] args = { "Vendor.MyJavaApplication" };
String functionName = "SetCurrentProcessExplicitAppUserModelID";
try {
    Function function = lib.getFunction(functionName);
    int ret = function.invokeInt(args);
    if (ret != 0) {
        Logger.out.error(function.getName() + " returned error code "
                + ret + ".");
    }
} catch (UnsatisfiedLinkError e) {
    Logger.out.error(functionName + " was not found in "
            + lib.getFile().getName() + ".");
    // Function not supported
}

这似乎不起作用,但函数返回时没有错误。诊断为什么对我来说是一个谜。有什么建议吗?

工作实施

最终有效的实现是我的后续问题的答案,即如何传递使用JNA。AppID

我把赏金授予了格雷戈里·帕科什(Gregory Pakosz)对JNI的精彩回答,这使我走上了正确的轨道。

作为参考,我相信使用这种技术开辟了在Java应用程序中使用本文中讨论的任何API的可能性。


答案 1

我没有Windows 7,但这里有一些东西可能会让你入门:

在Java方面:

package com.stackoverflow.homework;

public class MyApplication
{
  static native boolean setAppUserModelID();

  static
  {
    System.loadLibrary("MyApplicationJNI");
    setAppUserModelID();
  }
}

在本机方面,在“MyApplicationJNI.dll库的源代码中:

JNIEXPORT jboolean JNICALL Java_com_stackoverflow_homework_MyApplication_setAppUserModelID(JNIEnv* env)
{
  LPCWSTR id = L"com.stackoverflow.homework.MyApplication";
  HRESULT hr = SetCurrentProcessExplicitAppUserModelID(id);

  return hr == S_OK;
}

您的问题明确要求提供 JNI 解决方案。但是,由于您的应用程序不需要任何其他本机方法,因此jna是另一种解决方案,它将使您不必仅仅为了转发到Windows API而编写本机代码。如果您决定使用jna,请注意期望使用UTF-16字符串的事实。SetCurrentProcessExplicitAppUserModelID()

当它在沙盒中工作时,下一步是在应用程序中添加操作系统检测,因为显然仅在Windows 7中可用:SetCurrentProcessExplicitAppUserModelID()

  • 您可以通过检查返回 .System.getProperty("os.name");"Windows 7"
  • 如果你从我给出的小JNI片段构建,你可以通过使用LoadLibrary动态加载库来增强它,然后使用GetProcAddress取回函数指针。如果返回,则表示符号不存在,因此它不是Windows 7。shell32.dllSetCurrentProcessExplicitAppUserModelIDGetProcAddressNULLshell32

编辑:JNA解决方案

引用:


答案 2

有一个Java库为Java提供了新的Windows 7功能。它被Strix Code称为J7Goodies。使用它的应用程序可以正确固定到 Windows 7 任务栏。您还可以创建自己的跳转列表等。


推荐