35 votes

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

J'utilise Launch4j comme un wrapper pour mon application Java sous Windows 7, qui, à ma connaissance, dans l'essence de fourches à une instance d' javaw.exe qui, à son tour, interprète le code Java. En conséquence, lors de la tentative de rejeter ma demande à la barre des tâches de Windows au lieu de broches javaw.exe. Sans la ligne de commande nécessaire, ma demande ne sera pas exécuté.

Result of pinning a Launch4j application to the taskbar

Comme vous pouvez le voir, Windows ne se rendent pas compte que Java est l'hôte de l'application: l'application elle-même est décrit comme "Java(TM) Platform SE binary".

J'ai essayé de modifier la clé de registre HKEY_CLASSES_ROOT\Applications\javaw.exe d'ajouter de la valeur IsHostApp. Cela modifie le comportement par la désactivation de l'épinglage de ma candidature au total; est clairement pas ce que je veux.

Result of specifying javaw.exe as a host application

Après avoir lu au sujet de la façon dont Windows interprète les instances d'une même application (et un phénomène discuté de cette question), je me suis intéressé à l'incorporation d'un Utilisateur de l'Application de l'ID de Modèle (AppUserModelID) dans mon application Java.

Je crois que je peux résoudre ce problème en passant un unique AppUserModelID pour Windows. Il y a un shell32 méthode pour cela, SetCurrentProcessExplicitAppUserModelID. Suivant Grégoire Pakosz suggestion, j'ai mis en œuvre dans une tentative pour que ma demande soit reconnu comme une instance distincte de l' 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 avoir aucun effet, mais la fonction renvoie sans erreur. Diagnostiquer pourquoi est quelque chose d'un mystère pour moi. Toutes les suggestions?

Travail de mise en œuvre

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

J'avais reçu la prime de Grégoire Pakosz brillante de la réponse pour la JNI qui m'ont mis sur la bonne voie.

Pour référence, je crois que l'utilisation de cette technique ouvre la possibilité d'utiliser l'Api discutées dans cet article dans une application Java.

21voto

Gregory Pakosz Points 35546

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 void native setAppUserModelID();

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

Et sur le natif de côté, dans le code source de la " MyApplicationJNI.dll bibliothèque:

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

  return hr == S_OK;
}

Votre question explicitement demandé une JNI solution. Cependant, depuis que votre application n'a pas besoin d'une autre méthode native, jna est une autre solution qui vous permettra d'économiser de l'écriture de code natif juste pour le plaisir de transmettre à l'api windows. Si vous décidez d'aller jna, de payer l'attention sur le fait qu' SetCurrentProcessExplicitAppUserModelID() s'attend à un UTF-16 de la chaîne.

Quand il fonctionne dans votre bac à sable, la prochaine étape est d'ajouter de la détection du système d'exploitation de votre application en SetCurrentProcessExplicitAppUserModelID() est évidemment disponible uniquement sous Windows 7:

  • vous pouvez le faire à partir de la Java côté en vérifiant qu' System.getProperty("os.name"); retours "Windows 7".
  • si vous générez à partir de la petite JNI extrait de code que j'ai donné, vous pouvez l'améliorer en chargement dynamique de l' shell32.dll bibliothèque à l'aide d' LoadLibrary puis de reprendre l' SetCurrentProcessExplicitAppUserModelID pointeur de fonction à l'aide de GetProcAddress. Si GetProcAddress retours NULL, cela signifie que le symbole n'est pas présent dans shell32 donc ce n'est pas Windows 7.

EDIT: JNA Solution.

Références:

5voto

torn Points 492

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

4voto

Martijn Courteaux Points 33836

Essayez d'utiliser JSmooth . J'utilise toujours celui-ci. Dans JSmooth, existe-t-il une option sous Skeleton par Windowed Wrapper appelée

Lancement de l'application Java dans le processus EXE

Voir sur cette image.

JSmooth

Des arguments de ligne de commande peuvent également être passés.
Je pense que cela peut être une solution pour vous.

Martijn

4voto

The_Fire Points 71

J'ai mis en œuvre l'accès à la SetCurrentProcessExplicitAppUsermodelid méthode utilisant la JNA et il fonctionne très bien lorsqu'il est utilisé comme la documentation MSDN suggère. Je n'ai jamais utilisé la JNA de l'api dans la voie que vous avez dans votre extrait de code. Ma mise en œuvre suit le typique de l'utilisation de la JNA à la place.

D'abord le Shell32 définition de l'interface:

interface Shell32 extends StdCallLibrary {

    int SetCurrentProcessExplicitAppUserModelID( WString appID );

}

Ensuite, à l'aide de la " 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 de l'API dans le dernier article, vous avez mentionné utiliser Windows COM qui est assez difficile à utiliser directement avec la JNA. J'ai eu quelques succès de la création d'une DLL personnalisée d'appeler ces API (eg. à l'aide de la SHGetPropertyStoreForWindow pour définir un autre ID de l'application pour un sous-module fenêtre) que j'ai ensuite utiliser la JNA à l'accès à l'exécution.

3voto

Eric Brown Points 9233

SetCurrentProcessExplicitAppUsermodelid (ou SetAppID()) serait en fait de faire ce que vous essayez de faire. Cependant, il peut être plus facile de modifier votre installateur pour définir la AppUserModel.ID de propriété sur votre raccourci - citation de l' Utilisateur de l'Application de l'ID de Modèle de document mentionné ci-dessus:

Dans le Système.AppUserModel.ID de propriété de l'application du fichier de raccourci. Un raccourci (comme un IShellLink, CLSID_ShellLink, ou un .lnk fichier) prend en charge les propriétés à travers le IPropertyStore et d'autres biens mécanismes de fixation utilisé tout au long de la Coque. Cela permet à la barre des tâches pour identifier le bon raccourci à la broche et s'assure que windows appartenant au processus sont correctement associés avec le bouton de barre des tâches. Remarque: Le Système.AppUserModel.ID de propriété doivent être appliquées à un raccourci lorsque ce raccourci est créé. Lors de l'utilisation de Microsoft Windows Installer (MSI) pour installer l'application, la MsiShortcutProperty tableau permet à l'AppUserModelID être appliqué pour le raccourci lorsqu'il est créé lors de l'installation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X