简体   繁体   English

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

[英]Using JNA to get/set application identifier

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 . 继续我之前关于Windows 7任务栏的问题 ,我想诊断为什么Windows没有确认我的应用程序独立于javaw.exe I presently have the following JNA code to obtain the AppUserModelID : 我目前有以下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() + ".");
        }
    }
}

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. 意识到输出可能是UTF-16的事实,在(3)中我试图从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. PWSTR ,我不知道我的方法是否正确,因为(a)我不知道PWSTR的大小和(b)我不知道GetCurrentProcessExplicitAppUserModelID是否确实返回了一个字节数组或字符串。

I'm aware that JSmooth will run the GUI process in a wrapper which simulates this effect. 我知道JSmooth将在一个模拟这种效果的包装器中运行GUI进程。 Launch4j claims to do the same, but doesn't appear to work. Launch4j声称也这样做,但似乎不起作用。 I am looking to have the AppUserModelID set regardless of the Java wrapper . 我希望无论Java包装器如何设置AppUserModelID

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 ). 请注意,正如代码本身所述,我没有使用CoTaskMemFree函数(来自Ole32.dll )实现正确的内存清理。 So I suggest you take only the implementation for SetCurrentProcessExplicitAppUserModelID() 所以我建议你只采用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 : 这是一个关于如何通过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);

}

If you just need to set the AppUserModelId then the above JNA code is enough. 如果您只需要设置AppUserModelId,那么上面的JNA代码就足够了。 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. 但是,如果您想利用Java应用程序中的新Windows 7功能,请查看J7Goodies是一个提供Windows 7任务栏扩展的Java库。


EDIT : more info from J7Goodies Programmer's Guide 编辑 :来自J7Goodies程序员指南的更多信息

4.2. 4.2。 Setting AppUserModelID 设置AppUserModelID

In order to use any of the Windows 7 features an application must explicitly set its process identifier – Application User Model ID ( AppUserModelID ). 为了使用任何Windows 7功能,应用程序必须显式设置其进程标识符 - 应用程序用户模型ID( AppUserModelID )。 It can have no more than 128 characters and cannot contain spaces. 它不能超过128个字符,不能包含空格。 Each section should be camel-cased, for example: 每个部分都应该是驼峰式的,例如:

  CompanyName.ProductName.SubProduct.VersionInformation 

This identifier must be set before any GUI (window) is shown. 必须在显示任何GUI(窗口)之前设置此标识符。 You set it by calling: 你通过调用它来设置它:

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

4.3. 4.3。 Setting Window Properties 设置窗口属性

A Java application cannot be pinned to the Windows 7 taskbar unless its window properties are defined. 除非定义了窗口属性,否则无法将Java应用程序固定到Windows 7任务栏。 The properties consist of four fields: 这些属性包括四个字段:

  • AppUserModelID – the same as passed to AppUserModelId.setCurrentProcessId(String) AppUserModelID - 与传递给AppUserModelId.setCurrentProcessId(String)
  • RelaunchDisplayName – application's name RelaunchDisplayName - 应用程序的名称
  • RelaunchCommand – the full command used to launch the application. RelaunchCommand - 用于启动应用程序的完整命令。 In case of a Java program it will be: <path to javaw.exe> -jar <path to application jar> 对于Java程序,它将是: <path to javaw.exe> -jar <path to application jar>
  • RelaunchIcon – path to application's icon RelaunchIcon - 应用程序图标的路径

Important : RelaunchCommand and RelaunchDisplayName must always be set together. 重要说明 :必须始终将RelaunchCommandRelaunchDisplayName设置在一起。 To set these properties use the straightforward WindowProperties class. 要设置这些属性,请使用简单的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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM