35

我在 Windows 7 下使用 Launch4j 作为我的 Java 应用程序的包装器,据我了解,它本质上是派生出一个实例javaw.exe,进而解释 Java 代码。结果,当尝试将我的应用程序固定到任务栏时,Windows 改为固定javaw.exe. 如果没有所需的命令行,我的应用程序将无法运行。

将 Launch4j 应用程序固定到任务栏的结果

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

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

将 javaw.exe 指定为主机应用程序的结果

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

我相信我可以通过将唯一的传递AppUserModelID给 Windows 来解决这个问题。有一种shell32方法,SetCurrentProcessExplicitAppUserModelID. 按照 Gregory Pakosz 的建议,我实现了它,试图让我的应用程序被识别为一个单独的实例javaw.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
}

这似乎没有效果,但函数返回没有错误。诊断为什么对我来说是个谜。有什么建议么?

工作实施

最终的实现是对我关于如何通过using JNA的后续问题的回答。AppID

我已将赏金授予 Gregory Pakosz 对 JNI 的出色回答,这让我走上了正轨。

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

4

7 回答 7

21

我没有 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,请注意SetCurrentProcessExplicitAppUserModelID()期待 UTF-16 字符串的事实。

当它在您的沙箱中运行时,下一步是在您的应用程序中添加操作系统检测,这SetCurrentProcessExplicitAppUserModelID()显然仅在 Windows 7 中可用:

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

编辑:JNA 解决方案

参考:

于 2009-12-13T16:59:46.797 回答
5

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

于 2010-12-02T14:42:43.350 回答
4

尝试使用JSmooth。我总是用这个。在 JSmooth 中是否有一个选项Skeletonby Windowed Wrappercalled

在 exe 进程中启动 java 应用程序

参见这张图片。

JS平滑
(来源:andrels.com

也可以传递命令行参数。
我认为这可能是您的解决方案。

马汀

于 2009-12-12T18:57:58.187 回答
4

我已经使用 JNA 实现了对 SetCurrentProcessExplicitAppUserModelID 方法的访问,并且按照 MSDN 文档的建议使用它时效果很好。我从来没有像你在代码片段中那样使用过 JNA api。我的实现遵循典型的 JNA 用法

首先是Shell32接口定义:

interface Shell32 extends StdCallLibrary {

    int SetCurrentProcessExplicitAppUserModelID( WString appID );

}

然后使用JNA加载Shell32并调用函数:

final Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
    {
       put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
       put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
    }
};
Shell32 shell32 = (Shell32) Native.loadLibrary("shell32", Shell32.class,
           WIN32API_OPTIONS);
WString wAppId = new WString( "Vendor.MyJavaApplication" );
shell32.SetCurrentProcessExplicitAppUserModelID( wAppId );

您提到的上一篇文章中的许多 API 都使用了 Windows COM,这很难直接与 JNA 一起使用。我已经成功创建了一个自定义 DLL 来调用这些 API(例如,使用 SHGetPropertyStoreForWindow 为子模块窗口设置不同的应用程序 ID),然后我使用 JNA 在运行时访问它。

于 2009-12-22T18:32:14.870 回答
3

SetCurrentProcessExplicitAppUserModelID(或 SetAppID())实际上会做你想做的事情。但是,修改安装程序以在快捷方式上设置 AppUserModel.ID 属性可能更容易 - 引用上述应用程序用户模型 ID文档:

在应用程序快捷方式文件的System.AppUserModel.ID属性中。快捷方式(作为 IShellLink、CLSID_ShellLink 或 .lnk 文件)通过 IPropertyStore 和整个 Shell 中使用的其他属性设置机制支持属性。这允许任务栏识别正确的固定快捷方式,并确保属于该进程的窗口与该任务栏按钮适当关联。注意:创建快捷方式时,应将 System.AppUserModel.ID 属性应用于快捷方式。使用 Microsoft Windows Installer (MSI) 安装应用程序时,MsiShortcutProperty表允许 AppUserModelID 在安装期间创建快捷方式时应用到快捷方式。

于 2009-12-11T19:24:28.183 回答
1

最新的jna-platform库现在包括 JNA 绑定SetCurrentProcessExplicitAppUserModelID

https://github.com/java-native-access/jna/pull/680

于 2016-07-22T12:33:13.680 回答
0

我在没有任何 ID 设置的情况下修复了我的。Launch4J 中有一个选项,如果你正在使用它并且你说你会这样做......

您可以将标头更改为 JNI Gui,然后使用 JRE 将其包裹在 jar 周围。好消息是它现在在进程中运行 .exe,而不是在你的 jar 中运行 javaw.exe。它可能在引擎盖下完成(不确定)。此外,我还注意到它减少了大约 40-50% 的 CPU 资源,这甚至更好!

并且固定工作正常,并且所有窗口功能都已启用。

我希望它对某人有所帮助,因为我花了将近 2 天的时间试图用我未装饰的 javafx 应用程序解决这个问题。

于 2017-01-19T11:25:33.583 回答