Following up on my previous question concerning the Windows 7 taskbar, I would like to diagnose why Windows isn\'t acknowledging that my application is independent of
If you just need to set the AppUserModelId then the above JNA code is enough. However if you want to take advantage of the new Windows 7 features in you Java application then check out J7Goodies a Java library providing Windows 7 taskbar extensions.
EDIT: more info from J7Goodies Programmer's Guide
4.2. Setting AppUserModelID
In order to use any of the Windows 7 features an application must explicitly set its process identifier – Application User Model ID (
AppUserModelID). It can have no more than 128 characters and cannot contain spaces. Each section should be camel-cased, for example:CompanyName.ProductName.SubProduct.VersionInformationThis identifier must be set before any GUI (window) is shown. You set it by calling:
// Remember to set AppUserModelID before creating any UI
AppUserModelId.setCurrentProcessId("StrixCode.J7Goodies.Appname");
4.3. Setting Window Properties
A Java application cannot be pinned to the Windows 7 taskbar unless its window properties are defined. The properties consist of four fields:
- AppUserModelID – the same as passed to
AppUserModelId.setCurrentProcessId(String)- RelaunchDisplayName – application’s name
- RelaunchCommand – the full command used to launch the application. In case of a Java program it will be:
<path to javaw.exe> -jar <path to application jar>- RelaunchIcon – path to application’s icon
Important:
RelaunchCommandandRelaunchDisplayNamemust always be set together. To set these properties use the straightforward WindowProperties class.
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();
I didn't see your question before otherwise I would have given a try even without a bounty.
Here is what I came up with. Please note, as stated in the code itself, I didn't implement proper memory clean up with the CoTaskMemFree function (from Ole32.dll). So I suggest you take only the implementation for 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");
}
}
Does it work for you?
At least here it correctly prints back:
com.stackoverflow.AppIdTest.AppIdTest
Here's a more simple example on how to call SetCurrentProcessExplicitAppUserModelID via 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);
}