Utiliser JNA pour obtenir/définir l'identificateur d'application

suite à ma question précédente concernant la barre des tâches de Windows 7 , je voudrais diagnostiquer pourquoi Windows ne reconnaît pas que mon application est indépendante de javaw.exe . J'ai actuellement le code JNA suivant pour obtenir le 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() + ".");
        }
    }
}

La sortie de l'application est apparemment charabia:

1: ‹ÿU‹ìƒìL¡¬Ÿv3ʼnEüSV‹uƒ&
2: ‹ÿU‹ìƒìL¡¬Ÿv3ʼnEüSV‹uƒ&
3: ????????????????P???????????

étant conscient du fait que la sortie peut-être UTF-16, dans (3) j'ai essayé de convertir un tableau d'octets à partir de UTF-16. En toute honnêteté, je ne sais pas si mon approche ici est juste car (a) Je ne sais pas la taille d'un PWSTR et (b) Je ne sais pas si GetCurrentProcessExplicitAppUserModelID retourne effectivement un tableau d'octets ou une chaîne.

Je suis conscient que JSmooth va exécuter le processus GUI dans un wrapper qui simule cet effet. Launch4j prétend faire la même chose, mais ne semble pas fonctionner. Je suis à la recherche de la AppUserModelID set indépendamment du Java wrapper .

Qu'est-ce qui ne va pas ici?

21
demandé sur Community 2009-12-15 17:13:25

3 réponses

Je n'ai pas vu votre question avant sinon j'aurais essayé même sans une prime.

voilà ce que j'ai trouvé. s'il vous plaît noter, comme indiqué dans le code lui-même, je n'ai pas mis en œuvre la bonne mémoire nettoyer avec la fonction CoTaskMemFree (de Ole32.dll ). Donc je vous suggère de prendre seulement l'implémentation pour 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");
  }
}

ça vous va?

au moins ici il imprime correctement:

com.stackoverflow.AppIdTest.AppIdTest

19
répondu Gregory Pakosz 2009-12-18 15:28:25

si vous avez juste besoin de définir L'AppUserModelId alors le code JNA ci-dessus est suffisant. Cependant, si vous voulez profiter des nouvelles fonctionnalités de Windows 7 dans votre application Java, alors consultez J7Goodies une bibliothèque Java fournissant des extensions de la barre des tâches Windows 7.


modifier : plus d'informations de J7Goodies Guide du programmeur

4.2. Définition AppUserModelID

pour utiliser L'une des fonctionnalités de Windows 7, une application doit explicitement définir son identificateur de processus – Utilisateur de l'Application de l'ID de Modèle ( AppUserModelID ). Il peut pas avoir plus de 128 caractères et ne peut contenir d'espaces. Chaque section devrait être en casiers à chameaux, par exemple:

 CompanyName.ProductName.SubProduct.VersionInformation

cet identificateur doit être réglé avant qu'une GUI (fenêtre) ne soit affichée. Vous le réglez en appelant:

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

4.3. Définition Des Propriétés De La Fenêtre

une application Java ne peut pas être épinglée dans la barre des tâches Windows 7 à moins que ses propriétés de fenêtre ne soient définies. Le propriétés se composent de quatre champs:

  • AppUserModelID – le même que passé à AppUserModelId.setCurrentProcessId(String)
  • RelaunchDisplayName – nom de l'application
  • RelaunchCommand – la commande complète utilisée pour lancement de l'application. Dans le cas d'un programme Java, ce sera: <path to javaw.exe> -jar <path to application jar>
  • RelaunchIcon-chemin vers l'icône de l'application

Important : RelaunchCommand et RelaunchDisplayName doivent toujours être mis ainsi. Pour définir ces propriétés, utilisez la classe 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();
3
répondu torn 2013-08-23 17:38:09

voici un exemple plus simple sur la façon d'appeler 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);

}
3
répondu rednoah 2016-08-04 08:34:50