Pinning eine Java-Anwendung auf der Windows-7-Taskleiste
-
11-09-2019 - |
Frage
Ich verwende launch4j als Wrapper für meine Java-Anwendung unter Windows 7, die mein Verständnis im Wesentlichen Gabel eine Instanz von javaw.exe
wiederum, dass der Java-Code interpretiert. Als Ergebnis beim Versuch, meine Anwendung auf die Taskleiste Pin, Pins von Windows statt javaw.exe
. Ohne die erforderliche Befehlszeile, wird meine Anwendung dann nicht ausgeführt werden.
Wie Sie sehen können, von Windows auch nicht erkennen, dass Java die Host-Anwendung ist. Die Anwendung selbst als „Java (TM) Platform SE binären“ beschrieben wird
Ich habe versucht, den Registrierungsschlüssel HKEY_CLASSES_ROOT\Applications\javaw.exe
Ändern Sie den Wert IsHostApp
hinzuzufügen. Dadurch ändert sich das Verhalten von insgesamt Pinning meiner Anwendung zu deaktivieren; eindeutig nicht das, was ich will.
Nach der Lektüre über , wie Windows interpretiert Instanzen eines einzelne Anwendung (und ein Phänomen, in dieser Frage diskutiert ), wurde ich daran interessiert, eine Anwendung Benutzermodell ID (AppUserModelID) in meine Java-Anwendung eingebettet werden.
Ich glaube, dass ich dieses Problem lösen kann eine einzigartige AppUserModelID
auf Windows, indem. Es gibt eine shell32
Methode hierfür SetCurrentProcessExplicitAppUserModelID
. Nach Gregory Pakosz Vorschlag, ich habe es in einem Versuch implementiert meine Anwendung als separate Instanz von javaw.exe
erkannt haben:
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
}
Dies scheint keine Wirkung zu haben, aber die Funktion zurück, ohne Fehler. warum Diagnostizieren ist so etwas wie ein Rätsel für mich. Irgendwelche Vorschläge?
Arbeits Umsetzung
Die endgültige Implementierung, die gearbeitet ist die Antwort auf meine Folgefrage darüber, wie die AppID
mit JNA zu übergeben.
ich die Prämie zu Gregory Pakosz‘brillanter Antwort für JNI verliehen hatte, die mich auf dem richtigen Weg gesetzt.
Als Referenz ich diese Technik glauben mit eröffnet die Möglichkeit diskutiert jede der APIs verwenden in diesem Artikel in einer Java-Anwendung.
Lösung
Ich habe nicht Windows 7, aber hier ist etwas, das Sie begonnen haben könnte bekommen:
Auf der Java-Seite:
package com.stackoverflow.homework;
public class MyApplication
{
static native boolean setAppUserModelID();
static
{
System.loadLibrary("MyApplicationJNI");
setAppUserModelID();
}
}
Und auf der nativen Seite im Quellcode der `MyApplicationJNI.dll Bibliothek:
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;
}
Ihre Frage explizit für eine JNI-Lösung gefragt. Da jedoch Ihre Anwendung benötigt keine andere native Methode, jna wird eine andere Lösung, die sparen Sie vom Schreiben nativen Code, nur um auf den Windows-aPI weiterzuleiten. Wenn Sie sich entscheiden jna zu gehen, achten Sie auf die Tatsache, dass SetCurrentProcessExplicitAppUserModelID()
ein UTF-16-String erwartet.
Wenn es in Ihrer Sandbox arbeitet, ist der nächste Schritt des Betriebssystem erkennt in Ihrer Anwendung hinzuzufügen als SetCurrentProcessExplicitAppUserModelID()
in Windows offensichtlich nur verfügbar ist, 7:
- Sie können tun, dass aus der Java-Seite an, dass
System.getProperty("os.name");
Überprüfung kehrt"Windows 7"
. - , wenn Sie aus dem kleinen bauen JNI Snippet Ich gab, können Sie es durch dynamischen Laden der
shell32.dll
Bibliothek verbessern können mitLoadLibrary
dann dieSetCurrentProcessExplicitAppUserModelID
Funktionszeiger mit immer wiederGetProcAddress
. WennGetProcAddress
NULL
zurückkehrt, bedeutet das Symbol inshell32
nicht vorhanden ist, daher ist es nicht Windows 7.
EDIT:. JNA Lösung
Referenzen:
- Das JNI Buch für mehr JNI Beispiele
- Java Native Access (JNA)
Andere Tipps
Es ist eine Java-Bibliothek, die neuen Funktionen von Windows 7 für Java bietet. Es heißt J7Goodies von Strix-Code . indem es Anwendungen werden können, um die Windows-7-Taskleiste richtig festgesteckt. Sie können auch Ihre eigenen Sprunglisten erstellen, etc.
Versuchen Sie JSmooth zu verwenden. Ich benutze immer diese. In JSmooth gibt es eine Option unter Skeleton
von Windowed Wrapper
genannt
Lauch Java-Anwendung in exe-Prozess
Sehen Sie auf diesem Bild.
auch Befehl Zeilenargumente können übergeben werden.
Ich denke, dass dies eine Lösung für Sie sein kann.
Martijn
Ich habe Zugriff auf die SetCurrentProcessExplicitAppUserModelID Methode JNA implementiert und es funktioniert sehr gut, wenn sie als die MSDN-Dokumentation schlägt. Ich habe noch nie die JNA api in der Art und Weise verwendet, die Sie in Ihrem Code-Schnipsel haben. Meine Implementierung folgt die typische JNA Nutzung statt.
Zuerst wird die Shell32 Interface-Definition:
interface Shell32 extends StdCallLibrary {
int SetCurrentProcessExplicitAppUserModelID( WString appID );
}
Dann JNA mit Shell32 und rufen Sie die Funktion laden:
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 );
Viele der API im letzten Artikel, den Sie nutzen Windows COM genannt, die ziemlich schwierig ist, direkt mit JNA zu verwenden. Ich habe einige Erfolge Erstellen einer benutzerdefinierten DLL hatte diese API aufrufen (z. B. die SHGetPropertyStoreForWindow mit einer anderen App-ID für ein Submodul Fenster setzen), die ich dann JNA verwenden zur Laufzeit zugreifen zu können.
SetCurrentProcessExplicitAppUserModelID (oder SetAppID ()) würde in der Tat tun, was Sie versuchen zu tun. Allerdings könnte es einfacher sein, Ihre Installation zu modifizieren, um die AppUserModel.ID Eigenschaft auf Ihrer Verknüpfung zu setzen - Zitat aus dem Anwendungsbenutzermodell ID Dokument erwähnt oben:
In der System.AppUserModel.ID Eigenschaft der Verknüpfungsdatei der Anwendung. Eine Verknüpfung (als IShellLink, CLSID_ShellLink oder eine LNK-Datei) unterstützt Eigenschaften durch IPropertyStore und anderen Eigentum-Einstellung im gesamt Shell verwendet Mechanismen. Dies ermöglicht die Taskleiste die richtige Verknüpfung zu identifizieren und Pin stellt sicher, dass die Fenster zu dem Prozess gehören, sind in geeigneter Weise mit dem Taskleistenschaltfläche zugeordnet. Hinweis: Die System.AppUserModel.ID Eigenschaft sollte auf eine Verknüpfung angewandt werden, wenn die Verknüpfung erstellt wird. Wenn das Microsoft Windows Installer (MSI) mit der Anwendung zu installieren, die
Die neueste
jna-platform
Bibliothek enthält jetzt JNA Bindungen fürSetCurrentProcessExplicitAppUserModelID
:
Ich reparierte Mine ohne ID-Einstellungen. Es gibt eine Option in launch4j, wenn Sie es verwenden, und Sie sagen, Sie tun dann ...
Sie können den Header JNI Gui ändern und es dann mit der JRE um das Glas wickeln. Die gute Sache ist, dass es .exe im Prozess ausgeführt werden nun statt javaw.exe mit Ihrem Glas auf Laufen. Wahrscheinlich tut es unter der Haube (nicht sicher). Auch ich habe auch bemerkt, dass es sich um 40-50% weniger CPU-Ressourcen nimmt die sogar besser ist!
Und das Pinning funktioniert gut und alle, dass Fensterfunktionen aktiviert sind.
Ich hoffe, es hilft jemand, wie ich fast 2 Tage damit verbracht, dieses Problem mit meinem undecorated javafx App zu lösen.