我使用Launch4j作为Windows 7下我的Java应用程序的包装器,根据我的理解,本质上要求javaw.exe
的实例反过来解释Java代码。因此,在尝试将我的应用程序固定到任务栏时,Windows会引导javaw.exe
。如果没有所需的命令行,我的应用程序将无法运行。
正如您所看到的,Windows也没有意识到Java是主机应用程序:应用程序本身被描述为“Java(TM)Platform SE binary”。
我尝试更改注册表项HKEY_CLASSES_ROOT\Applications\javaw.exe
以添加值IsHostApp
。这通过完全禁用我的应用程序的固定来改变行为;显然不是我想要的。
在阅读了how Windows interprets instances of a single application(和a phenomenon discussed in this question)之后,我开始对将应用程序用户模型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
}
这似乎没有效果,但函数返回没有错误。诊断为什么对我来说是个谜。有什么建议吗?
有关如何使用JNA传递AppID
的最终实现the answer to my follow-up question。
我已经将Gregory Pakosz给予JNI的精彩答案奖励给我,使我走上正轨。
作为参考,我相信使用这种技术可以在Java应用程序中使用in this article中讨论的任何API。
答案 0 :(得分:20)
我没有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");
返回"Windows 7"
来从Java端执行此操作。LoadLibrary
动态加载shell32.dll
库然后使用{{3}获取SetCurrentProcessExplicitAppUserModelID
函数指针来增强它}。如果GetProcAddress
返回NULL
,则表示该符号在shell32
中不存在,因此它不是Windows 7。编辑:GetProcAddress
。
参考文献:
答案 1 :(得分:5)
有一个Java库为Java提供了新的Windows 7功能。它被J7Goodies称为Strix Code。使用它的应用程序可以正确固定到Windows 7任务栏。您也可以创建自己的跳转列表等。
答案 2 :(得分:4)
尝试使用JSmooth。我总是用这个。在JSmooth中Skeleton
Windowed Wrapper
下的选项名称为
exe程序中的Lauch java应用程序
见此图片。
也可以传递命令行参数 我认为这可以为您提供解决方案。
马亭
答案 3 :(得分:4)
我已经使用JNA实现了对SetCurrentProcessExplicitAppUserModelID方法的访问,并且当用作MSDN文档建议时它可以很好地工作。我从来没有像你的代码片段那样使用JNA api。我的实现改为typical JNA usage。
首先是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进行访问。
答案 4 :(得分:3)
SetCurrentProcessExplicitAppUserModelID(或SetAppID())实际上会执行您要执行的操作。但是,修改安装程序以在快捷方式上设置AppUserModel.ID属性可能更容易 - 引用上面提到的Application User Model ID文档:
在应用程序快捷方式文件的System.AppUserModel.ID属性中。快捷方式(作为IShellLink,CLSID_ShellLink或.lnk文件)通过IPropertyStore和整个Shell中使用的其他属性设置机制支持属性。这允许任务栏识别引脚的正确快捷方式,并确保属于该进程的窗口与该任务栏按钮正确关联。 注意:创建该快捷方式时,应将System.AppUserModel.ID属性应用于快捷方式。使用Microsoft Windows Installer(MSI)安装应用程序时,MsiShortcutProperty表允许AppUserModelID在安装过程中创建时应用于快捷方式。
答案 5 :(得分:1)
最新的jna-platform
库现在包含SetCurrentProcessExplicitAppUserModelID
的JNA绑定:
答案 6 :(得分:0)
我在没有任何ID设置的情况下修复了我的。 Launch4J中有一个选项,如果你正在使用它,你说你那么...
您可以将标题更改为JNI Gui,然后使用JRE将其包装在jar中。 好处是它现在在运行中运行.exe而不是用你的jar运行javaw.exe。它可能是在引擎盖下进行的(不确定)。 另外我也注意到CPU资源减少了大约40-50%,甚至更好!
钉扎工作正常,所有窗口功能都已启用。
我希望这对某人有所帮助,因为我花了将近2天的时间尝试用我未修饰的javafx应用解决这个问题。