跟进my previous question concerning the Windows 7 taskbar,我想诊断为什么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转换字节数组。说实话,我不知道我的方法是否正确,因为(a)我不知道PWSTR
的大小和(b)我不知道GetCurrentProcessExplicitAppUserModelID
是否确实返回字节数组或字符串。
我知道JSmooth会在一个模拟这种效果的包装器中运行GUI进程。 Launch4j声称也这样做,但似乎不起作用。无论Java包装器,我都希望AppUserModelID
设置。
这里出了什么问题?
答案 0 :(得分:19)
我没有看到你的问题,否则即使没有赏金,我也会试一试。
这是我想出的。 请注意,正如代码本身所述,我没有使用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
答案 1 :(得分:3)
如果您只需要设置AppUserModelId,那么上面的JNA代码就足够了。但是,如果您想利用Java应用程序中的新Windows 7功能,请查看J7Goodies提供Windows 7任务栏扩展的Java库。
编辑:来自J7Goodies程序员指南的更多信息
4.2。设置AppUserModelID
要使用任何Windows 7功能,必须明确指定应用程序 设置其进程标识符 - 应用程序用户模型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程序,它将是:
<path to javaw.exe> -jar <path to application jar>
- RelaunchIcon - 应用程序图标的路径
重要:必须始终设置
RelaunchCommand
和RelaunchDisplayName
一起。要设置这些属性,请使用简单的WindowProperties类。
WindowProperties props = new WindowProperties(myFrame);
props.setRelaunchCommand("<full path to javaw.exe –arguments>");
props.setRelaunchDisplayName("My Java Application");
props.setRelaunchIcon("<full path to an .ico or .exe file>");
props.setAppUserModelID("StrixCode.J7Goodies.Appname");
props.save();
答案 2 :(得分:3)
以下是有关如何通过SetCurrentProcessExplicitAppUserModelID
致电JNA
的更简单示例:
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);
}