Épingler une application Java à la barre des tâches Windows 7

j'utilise Launch4j comme un wrapper pour mon application Java sous Windows 7, qui, à ma connaissance, en essence bifurque une instance de javaw.exe qui à son tour interprète le code Java. Par conséquent, lorsque vous tentez d'épingler mon application à la barre des tâches, Windows place les pins javaw.exe . Sans la ligne de commande requise, mon application ne fonctionnera pas.

Result of pinning a Launch4j application to the taskbar

comme vous pouvez le voir, Windows ne fait pas non plus réalisez que Java est l'application hôte: l'application elle-même est décrite comme "Java(TM) plate-forme se binaire".

j'ai essayé de modifier la clé de registre HKEY_CLASSES_ROOTApplicationsjavaw.exe pour ajouter la valeur IsHostApp . Cela modifie le comportement en désactivant l'épinglage de mon application tout à fait; clairement pas ce que je veux.

Result of specifying javaw.exe as a host application

après avoir lu sur comment Windows interprète les instances d'un simple application (et un phénomène discuté dans cette question ), je me suis intéressé à l'intégration D'une application utilisateur ID modèle (AppUserModelID) dans mon application Java.

je crois que je peux résoudre ce problème en passant un AppUserModelID unique à Windows. Il existe une méthode shell32 pour cette, SetCurrentProcessExplicitAppUserModelID . Suite à la suggestion de Gregory Pakosz, Je l'ai mis en œuvre dans une tentative d'avoir mon application reconnu comme une instance distincte de javaw.exe :

NativeLibrary lib;
try {
    lib = NativeLibrary.getInstance("shell32");
} catch (Error e) {
    Logger.out.error("Could not load Shell32 library.");
    return;
}
Object[] args = { "Vendor.MyJavaApplication" };
String functionName = "SetCurrentProcessExplicitAppUserModelID";
try {
    Function function = lib.getFunction(functionName);
    int ret = function.invokeInt(args);
    if (ret != 0) {
        Logger.out.error(function.getName() + " returned error code "
                + ret + ".");
    }
} catch (UnsatisfiedLinkError e) {
    Logger.out.error(functionName + " was not found in "
            + lib.getFile().getName() + ".");
    // Function not supported
}

cela semble n'avoir aucun effet, mais la fonction retourne sans erreur. Diagnostiquer pourquoi est quelque chose d'un mystère pour moi. Toutes les suggestions?

"1519360920 de Travail" mise en œuvre

La mise en œuvre finale qui a fonctionné, c'est la réponse à ma question de suivi concernant la façon de passer le AppID utilisation de la JNA.

J'avais attribué la prime à la réponse brillante de Gregory Pakosz pour JNI qui m'a mis sur la bonne voie.

pour référence, je crois que l'utilisation de cette technique ouvre la possibilité d'utiliser n'importe lequel des API discutés dans cet article dans une application Java.

35
demandé sur Community 2009-12-02 20:44:01

7 réponses

Je N'ai pas Windows 7 Mais voici quelque chose qui pourrait vous aider à démarrer:

Sur le Java côté:

package com.stackoverflow.homework;

public class MyApplication
{
  static native boolean setAppUserModelID();

  static
  {
    System.loadLibrary("MyApplicationJNI");
    setAppUserModelID();
  }
}

et du côté natif, dans le code source du `MyApplicationJNI.dll bibliothèque:

JNIEXPORT jboolean JNICALL Java_com_stackoverflow_homework_MyApplication_setAppUserModelID(JNIEnv* env)
{
  LPCWSTR id = L"com.stackoverflow.homework.MyApplication";
  HRESULT hr = SetCurrentProcessExplicitAppUserModelID(id);

  return hr == S_OK;
}

votre question demandait explicitement une solution JNI. Cependant, puisque votre application n'a pas besoin d'une autre méthode native, jna est une autre solution qui vous sauvera de l'écriture du code natif pour le simple plaisir de le transmettre à l'api windows. Si vous décidez d'aller jna, faites attention au fait que SetCurrentProcessExplicitAppUserModelID() attend une chaîne UTF-16.

quand il fonctionne dans votre bac à sable, la prochaine étape est d'ajouter la détection du système d'exploitation dans votre application comme SetCurrentProcessExplicitAppUserModelID() est évidemment seulement disponible dans Windows 7:

  • vous pouvez faire cela du côté de Java en vérifiant que System.getProperty("os.name"); retourne "Windows 7" .
  • si vous construisez à partir du petit snippet JNI que j'ai donné, vous pouvez l'améliorer en chargeant dynamiquement la bibliothèque shell32.dll en utilisant LoadLibrary puis en récupérant le pointeur de fonction SetCurrentProcessExplicitAppUserModelID en utilisant GetProcAddress . Si GetProcAddress retourne NULL , cela signifie que le symbole n'est pas présent dans shell32 donc ce n'est pas Windows 7.

EDIT: JNA Solution .

, les Références:

20
répondu Gregory Pakosz 2017-05-23 11:54:08

il existe une bibliothèque Java fournissant les nouvelles fonctionnalités de Windows 7 pour Java. Il s'appelle J7Goodies par code Strix . Les Applications qui l'utilisent peuvent être correctement épinglées à la barre des tâches Windows 7. Vous pouvez également créer vos propres listes de raccourcis, etc.

5
répondu torn 2010-12-02 14:42:43

Essayez d'utiliser JSmooth . J'utilise toujours celui-ci. Dans JSmooth il y a une option sous Skeleton par Windowed Wrapper appelé

Lauch application java en exe processus de

voir sur cette image.

JSmooth

peut aussi passer des arguments en ligne de commande.

Je pense que ça peut être une solution pour toi.

Martijn

4
répondu Martijn Courteaux 2017-02-08 14:18:14

j'ai implémenté l'accès à la méthode SetCurrentProcessExplicitAppUsermodelid en utilisant JNA et cela fonctionne très bien quand utilisé comme le suggère la documentation MSDN. Je n'ai jamais utilisé L'api JNA comme vous l'avez fait avec votre code snippet. Mon implémentation suit l'usage typique de JNA à la place.

première définition de L'interface Shell32:

interface Shell32 extends StdCallLibrary {

    int SetCurrentProcessExplicitAppUserModelID( WString appID );

}

puis en utilisant JNA pour charger Shell32 et appeler la fonction:

final Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
    {
       put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
       put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
    }
};
Shell32 shell32 = (Shell32) Native.loadLibrary("shell32", Shell32.class,
           WIN32API_OPTIONS);
WString wAppId = new WString( "Vendor.MyJavaApplication" );
shell32.SetCurrentProcessExplicitAppUserModelID( wAppId );

beaucoup d'API dans le dernier article que vous avez mentionné utilisent Windows COM qui est assez difficile à utiliser directement avec JNA. J'ai réussi à créer une DLL personnalisée pour appeler ces API (par ex. utiliser le SHGetPropertyStoreForWindow pour définir un ID d'application différent pour une fenêtre submodule) que j'utilise ensuite JNA pour accéder à l'exécution.

4
répondu The_Fire 2009-12-22 18:32:14

SetCurrentProcessExplicitAppUsermodelid (ou SetAppID ()) ferait en fait ce que vous essayez de faire. Cependant, il pourrait être plus facile de modifier votre installateur pour configurer L'AppUserModel.Propriété ID sur votre raccourci-citation du Application User Model ID document mentionné ci-dessus:

dans le système .AppUserModel.ID propriété du fichier raccourci de la demande. Un raccourci (comme un IShellLink), CLSID_ShellLink, ou un .lnk file) supporte les propriétés par IPropertyStore et d'autres mécanismes de paramétrage des propriétés utilisés dans L'ensemble de L'interpréteur de commandes. Cela permet à la barre des tâches d'identifier le raccourci approprié pour épingler et assure que les fenêtres appartenant au processus sont associés de manière appropriée avec ce bouton de barre des tâches. Note: The System.AppUserModel.La propriété ID doit être appliquée à un raccourci lorsque ce raccourci est créé. Lorsque vous utilisez Microsoft Windows Installer (MSI) pour installer l'application, le MsiShortcutProperty table permet L'AppUserModelID à appliquer sur le raccourci quand il est créé pendant l'installation.

3
répondu Eric Brown 2009-12-11 19:24:28

la bibliothèque la plus récente jna-platform comprend maintenant des reliures JNA pour SetCurrentProcessExplicitAppUserModelID :

https://github.com/java-native-access/jna/pull/680

1
répondu rednoah 2016-07-22 12:33:13

j'ai réparé le mien sans réglages D'identité. Il y a une option dans Launch4J si vous l'utilisez et vous dites que vous le faites alors...

vous pouvez changer l'en-tête en JNI Gui et l'enrouler autour du pot avec le JRE. La bonne chose est qu'il s'exécute .exe dans le processus maintenant à la place sur javaw exécution.exe avec ton bocal. Il est sans doute sous le capot (pas sûr). J'ai également remarqué qu'il faut environ 40-50% moins de ressources CPU, ce qui est encore mieux!

et l'épinglage fonctionne très bien et toutes les fonctionnalités de la fenêtre sont activées.

j'espère que cela aidera quelqu'un que j'ai passé près de 2 jours à essayer de résoudre ce problème avec mon javafx app non décorée.

0
répondu LazerBanana 2017-01-19 11:25:33