Using JNA to get/set application identifier

前端 未结 3 1150
忘了有多久
忘了有多久 2020-12-04 12:48

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

相关标签:
3条回答
  • 2020-12-04 13:12

    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.VersionInformation
    

    This 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: RelaunchCommand and RelaunchDisplayName must 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();
    
    0 讨论(0)
  • 2020-12-04 13:15

    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

    0 讨论(0)
  • 2020-12-04 13:33

    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);
    
    }
    
    0 讨论(0)
提交回复
热议问题