将 Java 应用程序固定到 Windows 7 任务栏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1834599/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pinning a Java application to the Windows 7 taskbar
提问by Paul Lammertsma
I use Launch4j as a wrapper for my Java application under Windows 7, which, to my understanding, in essence forks an instance of javaw.exethat in turn interprets the Java code. As a result, when attempting to pin my application to the task bar, Windows instead pins javaw.exe. Without the required command line, my application will then not run.
我在 Windows 7 下使用 Launch4j 作为我的 Java 应用程序的包装器,据我所知,它本质上派生了一个实例javaw.exe,进而解释 Java 代码。结果,当尝试将我的应用程序固定到任务栏时,Windows 代替固定javaw.exe. 如果没有所需的命令行,我的应用程序将无法运行。


As you can see, Windows also does not realize that Java is the host application: the application itself is described as "Java(TM) Platform SE binary".
如您所见,Windows 也没有意识到 Java 是宿主应用程序:应用程序本身被描述为“Java(TM) Platform SE 二进制文件”。
I have tried altering the registry key HKEY_CLASSES_ROOT\Applications\javaw.exeto add the value IsHostApp. This alters the behavior by disabling pinning of my application altogether; clearly not what I want.
我曾尝试更改注册表项HKEY_CLASSES_ROOT\Applications\javaw.exe以添加值IsHostApp。这通过完全禁用我的应用程序的固定来改变行为;显然不是我想要的。


After reading about how Windows interprets instances of a single application(and a phenomenon discussed in this question), I became interested in embedding a Application User Model ID (AppUserModelID) into my Java application.
在阅读了 Windows 如何解释单个应用程序的实例(以及本问题中讨论的现象)之后,我对将应用程序用户模型 ID (AppUserModelID) 嵌入到我的 Java 应用程序中产生了兴趣。
I believe that I can resolve this by passing a unique AppUserModelIDto Windows. There is a shell32method for this, SetCurrentProcessExplicitAppUserModelID. Following Gregory Pakosz suggestion, I implemented it in an attempt to have my application recognized as a separate instance of javaw.exe:
我相信我可以通过AppUserModelID向 Windows传递一个 unique来解决这个问题。有一种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
}
This appears to have no effect, but the function returns without error. Diagnosing why is something of a mystery to me. Any suggestions?
这似乎没有效果,但函数返回时没有错误。诊断原因对我来说是个谜。有什么建议?
Working implementation
工作实施
The final implementation that worked is the answer to my follow-up questionconcerning how to pass the AppIDusing JNA.
最终有效的实现是我关于如何通过AppIDusing JNA 的后续问题的答案。
I had awarded the bounty to Gregory Pakosz' brilliant answer for JNI that set me on the right track.
我已将赏金授予 Gregory Pakosz 对 JNI 的精彩回答,这使我走上了正确的轨道。
For reference, I believe using this technique opens the possibility of using any of the APIs discussed in this articlein a Java application.
作为参考,我相信使用这种技术可以在 Java 应用程序中使用本文中讨论的任何 API 。
采纳答案by Gregory Pakosz
I don't have Windows 7 but here is something that might get you started:
我没有 Windows 7,但以下内容可能会让您入门:
On the Java side:
在 Java 方面:
package com.stackoverflow.homework;
public class MyApplication
{
static native boolean setAppUserModelID();
static
{
System.loadLibrary("MyApplicationJNI");
setAppUserModelID();
}
}
And on the native side, in the source code of the `MyApplicationJNI.dll library:
在本机端,在`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;
}
Your question explicitly asked for a JNI solution. However, since your application doesn't need any other native method, jnais another solution which will save you from writing native code just for the sake of forwarding to the windows api. If you decide to go jna, pay attention to the fact that SetCurrentProcessExplicitAppUserModelID()is expecting a UTF-16 string.
您的问题明确要求 JNI 解决方案。但是,由于您的应用程序不需要任何其他本机方法,因此jna是另一种解决方案,它可以让您不必为了转发到 windows api 而编写本机代码。如果您决定使用 jna,请注意SetCurrentProcessExplicitAppUserModelID()期待 UTF-16 字符串的事实。
When it works in your sandbox, the next step is to add operating system detection in your application as SetCurrentProcessExplicitAppUserModelID()is obviously only available in Windows 7:
当它在您的沙箱中工作时,下一步是在您的应用程序中添加操作系统检测,这SetCurrentProcessExplicitAppUserModelID()显然仅在 Windows 7 中可用:
- you may do that from the Java side by checking that
System.getProperty("os.name");returns"Windows 7". - if you build from the little JNI snippet I gave, you can enhance it by dynamically loading the
shell32.dlllibrary usingLoadLibrarythen getting back theSetCurrentProcessExplicitAppUserModelIDfunction pointer usingGetProcAddress. IfGetProcAddressreturnsNULL, it means the symbol is not present inshell32hence it's not Windows 7.
- 您可以通过检查
System.getProperty("os.name");返回值从 Java 端执行此操作"Windows 7"。 - 如果您从我提供的小 JNI 片段构建,则可以通过使用动态加载
shell32.dll库LoadLibrary然后SetCurrentProcessExplicitAppUserModelID使用GetProcAddress. 如果GetProcAddress返回NULL,则表示该符号不存在,shell32因此它不是 Windows 7。
EDIT: JNA Solution.
编辑:JNA 解决方案。
References:
参考:
- The JNI bookfor more JNI examples
- Java Native Access (JNA)
- 有关更多 JNI 示例的 JNI 书籍
- Java 本机访问 (JNA)
回答by torn
There is a Java library providing the new Windows 7 features for Java. It's called J7Goodiesby Strix Code. Applications using it can be properly pinned to the Windows 7 taskbar. You can also create your own jump lists, etc.
有一个 Java 库为 Java 提供了新的 Windows 7 功能。它被Strix Code称为J7Goodies。使用它的应用程序可以正确固定到 Windows 7 任务栏。您还可以创建自己的跳转列表等。
回答by Martijn Courteaux
Try to use JSmooth. I use always this one. In JSmooth is there an option under Skeletonby Windowed Wrappercalled
尝试使用JSmooth。我总是用这个。在 JSmooth 中有一个选项Skeleton被Windowed Wrapper称为
Lauch java app in exe process
在 exe 进程中启动 java 应用程序
See on this image.
请参阅此图像。


Also command line arguments can be passed.
I think this can be a solution for you.
也可以传递命令行参数。
我认为这可以为您提供解决方案。
Martijn
马丁
回答by The_Fire
I have implemented access to the SetCurrentProcessExplicitAppUserModelID method using JNA and it works quite well when used as the MSDN documentation suggests. I've never used the JNA api in the way you have in your code snippet. My implementation follows the typical JNA usageinstead.
我已经使用 JNA 实现了对 SetCurrentProcessExplicitAppUserModelID 方法的访问,当按照 MSDN 文档的建议使用时,它工作得很好。我从未像您在代码片段中那样使用过 JNA api。我的实现遵循典型的 JNA 用法。
First the Shell32 interface definition:
首先是Shell32接口定义:
interface Shell32 extends StdCallLibrary {
int SetCurrentProcessExplicitAppUserModelID( WString appID );
}
Then using JNA to load Shell32 and call the function:
然后使用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 );
Many of the API's in the last article you mentioned make use of Windows COM which is quite difficult to use directly with JNA. I have had some success creating a custom DLL to call these API's (eg. using the SHGetPropertyStoreForWindow to set a different app ID for a submodule window) which I then use JNA to access at runtime.
您在上一篇文章中提到的许多 API 都使用了 Windows COM,这很难直接与 JNA 一起使用。我在创建自定义 DLL 以调用这些 API(例如,使用 SHGetPropertyStoreForWindow 为子模块窗口设置不同的应用程序 ID)方面取得了一些成功,然后我在运行时使用 JNA 进行访问。
回答by Eric Brown
SetCurrentProcessExplicitAppUserModelID (or SetAppID()) would in fact do what you're trying to do. However, it might be easier to modify your installer to set the AppUserModel.ID property on your shortcut - quoting from the Application User Model IDdocument mentioned above:
SetCurrentProcessExplicitAppUserModelID(或 SetAppID())实际上会做你想做的事情。但是,修改安装程序以在快捷方式上设置 AppUserModel.ID 属性可能更容易 - 引用上述应用程序用户模型 ID文档:
In the System.AppUserModel.IDproperty of the application's shortcut file. A shortcut (as an IShellLink, CLSID_ShellLink, or a .lnk file) supports properties through IPropertyStore and other property-setting mechanisms used throughout the Shell. This allows the taskbar to identify the proper shortcut to pin and ensures that windows belonging to the process are appropriately associated with that taskbar button. Note: The System.AppUserModel.ID property should be applied to a shortcut when that shortcut is created. When using the Microsoft Windows Installer (MSI) to install the application, the MsiShortcutPropertytable allows the AppUserModelID to be applied to the shortcut when it is created during installation.
在应用程序快捷方式文件的System.AppUserModel.ID属性中。快捷方式(作为 IShellLink、CLSID_ShellLink 或 .lnk 文件)通过 IPropertyStore 和整个 Shell 中使用的其他属性设置机制支持属性。这允许任务栏识别正确的固定快捷方式,并确保属于该进程的窗口与该任务栏按钮适当关联。注意: System.AppUserModel.ID 属性应在创建快捷方式时应用于快捷方式。使用 Microsoft Windows Installer (MSI) 安装应用程序时,MsiShortcutProperty表允许在安装过程中创建快捷方式时将 AppUserModelID 应用到快捷方式。
回答by rednoah
The latest jna-platformlibrary now includes JNA bindings for SetCurrentProcessExplicitAppUserModelID:
最新的jna-platform库现在包括 JNA 绑定SetCurrentProcessExplicitAppUserModelID:
回答by LazerBanana
I fixed mine without any ID settings. There is an option in Launch4J if you are using it and you say you do then...
我在没有任何 ID 设置的情况下修复了我的。Launch4J 中有一个选项,如果你正在使用它并且你说你这样做了......
You can change the header to JNI Gui and then wrap it around the jar with the JRE. The good thing is that it runs .exe in the process now instead on running javaw.exe with your jar. It probably does it under the hood (not sure). Also I have noticed also that it takes around 40-50% less CPU resource which is even better!
您可以将标题更改为 JNI Gui,然后使用 JRE 将其包裹在 jar 中。好消息是它现在在进程中运行 .exe 而不是用你的 jar 运行 javaw.exe。它可能在引擎盖下进行(不确定)。我还注意到,它占用的 CPU 资源减少了大约 40-50%,这更好!
And the pinning works fine and all that window features are enabled.
并且固定工作正常,所有窗口功能都已启用。
I hope it helps to someone as I spent nearly 2 days trying to solve that issue with my undecorated javafx app.
我希望它对某人有所帮助,因为我花了将近 2 天的时间试图用我未修饰的 javafx 应用程序解决该问题。

