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 javaw.exe
. I presently have the following JNA code to obtain the 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() + ".");
}
}
}
The output of the application is seemingly gibberish:
1: ‹ÿU‹ìƒìL¡¬Ÿv3ʼnEüSV‹uƒ&
2: ‹ÿU‹ìƒìL¡¬Ÿv3ʼnEüSV‹uƒ&
3: ????????????????P???????????
Being aware of the fact that the output may be UTF-16, in (3) I attempted to convert a byte array from UTF-16. In all honesty I don't know if my approach here is right as (a) I don't know the size of a PWSTR
and (b) I don't know if GetCurrentProcessExplicitAppUserModelID
is indeed returning a byte array or string.
I'm aware that JSmooth will run the GUI process in a wrapper which simulates this effect. Launch4j claims to do the same, but doesn't appear to work. I am looking to have the AppUserModelID
set regardless of the Java wrapper.
What is going wrong here?
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