使用JNA获取/设置应用程序标识符

继续我之前关于Windows 7任务栏的问题 ,我想诊断为什么Windows没有确认我的应用程序独立于javaw.exe 。 我目前有以下JNA代码来获取AppUserModelID

 public class AppIdTest { public static void main(String[] args) { NativeLibrary lib; try { lib = NativeLibrary.getInstance("shell32"); } catch (Error e) { System.err.println("Could not load Shell32 library."); return; } Object[] functionArgs = new Object[1]; String functionName = null; Function function; try { functionArgs[0] = new String("Vendor.MyJavaApplication") .getBytes("UTF-16"); functionName = "GetCurrentProcessExplicitAppUserModelID"; function = lib.getFunction(functionName); // Output the current AppId System.out.println("1: " + function.getString(0)); functionName = "SetCurrentProcessExplicitAppUserModelID"; function = lib.getFunction(functionName); // Set the new AppId int ret = function.invokeInt(functionArgs); if (ret != 0) { Logger.out.error(function.getName() + " returned error code " + ret + "."); } functionName = "GetCurrentProcessExplicitAppUserModelID"; function = lib.getFunction(functionName); // Output the current AppId System.out.println("2: " + function.getString(0)); // Output the current AppID, converted from UTF-16 System.out.println("3: " + new String(function.getByteArray(0, 255), "UTF-16")); } catch (UnsupportedEncodingException e) { System.err.println("System does not support UTF-16 encoding."); } catch (UnsatisfiedLinkError e) { System.err.println(functionName + " was not found in " + lib.getFile().getName() + "."); } } } 

该应用程序的输出似乎是胡言乱语:

 1: ‹ÿU‹ìƒìL¡¬Ÿv3ʼnEüSV‹uƒ& 2: ‹ÿU‹ìƒìL¡¬Ÿv3ʼnEüSV‹uƒ& 3: ????????????????P??????????? 

意识到输出可能是UTF-16的事实,在(3)中我试图从UTF-16转换字节数组。 PWSTR ,我不知道我的方法是否正确,因为(a)我不知道PWSTR的大小,(b)我不知道GetCurrentProcessExplicitAppUserModelID是否确实返回了字节数组或字符串。

我知道JSmooth将在一个模拟这种效果的包装器中运行GUI进程。 Launch4j声称也这样做,但似乎不起作用。 我希望无论Java包装器如何设置AppUserModelID

这里出了什么问题?

我没有看到你的问题,否则即使没有赏金,我也会试一试。

这就是我想出的。 请注意,正如代码本身所述,我没有使用CoTaskMemFree函数(来自Ole32.dll )实现正确的内存清理。 所以我建议你只采用SetCurrentProcessExplicitAppUserModelID()的实现

 package com.stackoverflow.AppIdTest; import com.sun.jna.Native; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; import com.sun.jna.WString; import com.sun.jna.ptr.PointerByReference; public class AppIdTest { public static void main(String[] args) throws Exception { setCurrentProcessExplicitAppUserModelID(AppIdTest.class.getName()); System.out.println(getCurrentProcessExplicitAppUserModelID()); } // DO NOT DO THIS, IT'S JUST FOR TESTING PURPOSE AS I'M NOT FREEING THE MEMORY // AS REQUESTED BY THE DOCUMENTATION: // // http://msdn.microsoft.com/en-us/library/dd378419%28VS.85%29.aspx // // "The caller is responsible for freeing this string with CoTaskMemFree when // it is no longer needed" public static String getCurrentProcessExplicitAppUserModelID() { final PointerByReference r = new PointerByReference(); if (GetCurrentProcessExplicitAppUserModelID(r).longValue() == 0) { final Pointer p = r.getValue(); return p.getString(0, true); // here we leak native memory by lazyness } return "N/A"; } public static void setCurrentProcessExplicitAppUserModelID(final String appID) { if (SetCurrentProcessExplicitAppUserModelID(new WString(appID)).longValue() != 0) throw new RuntimeException("unable to set current process explicit AppUserModelID to: " + appID); } private static native NativeLong GetCurrentProcessExplicitAppUserModelID(PointerByReference appID); private static native NativeLong SetCurrentProcessExplicitAppUserModelID(WString appID); static { Native.register("shell32"); } } 

对你起作用吗?

至少在这里它正确打印回来:

com.stackoverflow.AppIdTest.AppIdTest

如果您只需要设置AppUserModelId,那么上面的JNA代码就足够了。 但是,如果您想利用Java应用程序中的新Windows 7function,请查看J7Goodies是一个提供Windows 7任务栏扩展的Java库。


编辑 :来自J7Goodies程序员指南的更多信息

4.2。 设置AppUserModelID

为了使用任何Windows 7function,应用程序必须显式设置其进程标识符 – 应用程序用户模型ID( AppUserModelID )。 它不能超过128个字符,不能包含空格。 每个部分都应该是驼峰式的,例如:

  CompanyName.ProductName.SubProduct.VersionInformation 

必须在显示任何GUI(窗口)之前设置此标识符。 你通过调用它来设置它:

 // Remember to set AppUserModelID before creating any UI AppUserModelId.setCurrentProcessId("StrixCode.J7Goodies.Appname"); 

4.3。 设置窗口属性

除非定义了窗口属性,否则无法将Java应用程序固定到Windows 7任务栏。 这些属性包括四个字段:

  • AppUserModelID – 与传递给AppUserModelId.setCurrentProcessId(String)
  • RelaunchDisplayName – 应用程序的名称
  • RelaunchCommand – 用于启动应用程序的完整命令。 对于Java程序,它将是: -jar
  • RelaunchIcon – 应用程序图标的路径

重要说明 :必须始终将RelaunchCommandRelaunchDisplayName设置在一起。 要设置这些属性,请使用简单的WindowProperties类。

 WindowProperties props = new WindowProperties(myFrame); props.setRelaunchCommand(""); props.setRelaunchDisplayName("My Java Application"); props.setRelaunchIcon(""); props.setAppUserModelID("StrixCode.J7Goodies.Appname"); props.save(); 

这是一个关于如何通过JNA调用SetCurrentProcessExplicitAppUserModelID的更简单示例:

 import com.sun.jna.*; import com.sun.jna.win32.*; interface Shell32 extends StdCallLibrary { Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32", Shell32.class, W32APIOptions.DEFAULT_OPTIONS); NativeLong SetCurrentProcessExplicitAppUserModelID(WString appID); }