Привязка приложения Java к панели задач Windows 7

Я использую Launch4j как оболочку для своего Java-приложения под Windows 7, что, по моему мнению, по сути javaw.exe экземпляр javaw.exe который, в свою очередь, интерпретирует Java-код. В результате при попытке javaw.exe мое приложение к панели задач Windows вместо этого javaw.exe . Без требуемой командной строки мое приложение не будет запущено.

Результат привязки приложения Launch4j к панели задач

Как вы можете видеть, Windows также не понимает, что Java является хост-приложением: само приложение описывается как «Java SE TM Platform».

Я попытался изменить раздел реестра HKEY_CLASSES_ROOT\Applications\javaw.exe чтобы добавить значение IsHostApp . Это изменяет поведение, полностью отключив привязку моего приложения; явно не то, что я хочу.

Результат задания javaw.exe в качестве приложения-хозяина

Прочитав о том, как Windows интерпретирует экземпляры одного приложения (и явление, обсуждаемое в этом вопросе ), я заинтересовался внедрением идентификатора модели пользовательской модели приложения (AppUserModelID) в мое приложение Java.

Я считаю, что могу решить эту проблему, передав уникальный Windows AppUserModelID в Windows. Для этого shell32 метод shell32 , SetCurrentProcessExplicitAppUserModelID . Следуя предложению Грегори Пакоша, я внедрил его в попытке распознать приложение как отдельный экземпляр 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 } 

Это, кажется, не имеет никакого эффекта, но функция возвращается без ошибок. Диагностика почему для меня что-то загадочное. Какие-либо предложения?

Рабочая реализация

Заключительная реализация, которая работала, является ответом на мой последующий вопрос о том, как передать AppID с помощью JNA.

Я наgradleил щедростью shiny ответ Грегори Пакоша за JNI, который поставил меня на правильный путь.

Для справки, я считаю, что использование этого метода открывает возможность использования любого из API, обсуждаемых в этой статье в приложении Java.

    У меня нет Windows 7, но здесь вы можете начать:

    На стороне Java:

     package com.stackoverflow.homework; public class MyApplication { static native boolean setAppUserModelID(); static { System.loadLibrary("MyApplicationJNI"); setAppUserModelID(); } } 

    И на родной стороне, в исходном коде библиотеки MyApplicationJNI.dll:

     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; } 

    В вашем вопросе явным образом попросил решение JNI. Однако, поскольку вашему приложению не нужен какой-либо другой собственный метод, jna – это еще одно решение, которое избавит вас от написания собственного кода только для перенаправления на windows api. Если вы решите пойти в jna, обратите внимание на то, что SetCurrentProcessExplicitAppUserModelID() ожидает строку UTF-16.

    Когда он работает в вашей песочнице, следующим шагом является добавление обнаружения операционной системы в ваше приложение, поскольку SetCurrentProcessExplicitAppUserModelID() , очевидно, доступно только в Windows 7:

    • вы можете сделать это со стороны Java, проверив, что System.getProperty("os.name"); возвращает "Windows 7" .
    • если вы построите из небольшого fragmentа JNI, который я дал, вы можете улучшить его, динамически загрузив библиотеку shell32.dll с помощью LoadLibrary затем верните указатель функции SetCurrentProcessExplicitAppUserModelID с помощью GetProcAddress . Если GetProcAddress возвращает NULL , это означает, что символ отсутствует в shell32 следовательно, это не Windows 7.

    EDIT: решение JNA .

    Рекомендации:

    • Книга JNI для более примеров JNI
    • Java Native Access (JNA)

    Существует Java-библиотека, предоставляющая новые функции Windows 7 для Java. Это называется J7Goodies от Strix Code . Приложения, использующие его, могут быть правильно закреплены на панели задач Windows 7. Вы также можете создавать свои собственные списки переходов и т. Д.

    Попробуйте использовать JSmooth . Я всегда пользуюсь этим. В JSmooth есть опция под Skeleton от Windowed Wrapper называемая

    Приложение Lauch java в exe-процессе

    См. На этом изображении.

    JSmooth

    Также могут передаваться аргументы командной строки.
    Я думаю, это может быть для вас решением.

    Мартейн

    Я реализовал доступ к методу SetCurrentProcessExplicitAppUserModelID с использованием JNA, и он отлично работает при использовании в документации MSDN. Я никогда не использовал JNA api так, как вы это делали в своем fragmentе кода. Моя реализация следует за типичным использованием JNA .

    Сначала определение интерфейса Shell32:

     interface Shell32 extends StdCallLibrary { int SetCurrentProcessExplicitAppUserModelID( WString appID ); } 

    Затем, используя JNA для загрузки Shell32 и вызова функции:

     final Map WIN32API_OPTIONS = new HashMap() { { 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 ); 

    Многие из API в последней упомянутой вами статье используют Windows COM, который довольно сложно использовать напрямую с JNA. У меня был некоторый успех, создав пользовательскую DLL для вызова этих API (например, используя SHGetPropertyStoreForWindow, чтобы установить другой идентификатор приложения для windows подмодуля), который затем я использую JNA для доступа во время выполнения.

    SetCurrentProcessExplicitAppUserModelID (или SetAppID ()) фактически сделает то, что вы пытаетесь сделать. Однако может быть проще изменить установщик, чтобы установить свойство AppUserModel.ID в ярлык – цитирование из документа идентификатора модели приложения, упомянутого выше:

    В свойстве System.AppUserModel.ID файла ярлыка приложения. Ярлык (как IShellLink, CLSID_ShellLink или .lnk-файл) поддерживает свойства через IPropertyStore и другие механизмы определения свойств, используемые во всей оболочке. Это позволяет панели задач идентифицировать правильный ярлык для вывода и гарантирует, что windows, принадлежащие процессу, соответствующим образом связаны с этой кнопкой панели задач. Примечание. Свойство System.AppUserModel.ID следует применять к ярлыку при создании этого ярлыка. При использовании установщика Microsoft Windows (MSI) для установки приложения таблица MsiShortcutProperty позволяет применять AppUserModelID к ярлыку при его создании во время установки.

    Последняя библиотека jna-platform теперь включает привязки JNA для SetCurrentProcessExplicitAppUserModelID :

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

    Я исправил мой без настроек ID. В Launch4J есть опция, если вы используете ее, и вы говорите, что потом …

    Вы можете изменить заголовок на JNI Gui, а затем обернуть его вокруг банки JRE. Хорошо, что теперь он запускает .exe, а вместо этого запускает javaw.exe с вашей банкой. Вероятно, он находится под капотом (не уверен). Также я заметил также, что на ресурс CPU на 40-50% меньше, что еще лучше!

    И пиннинг работает отлично, и все функции windows включены.

    Я надеюсь, что это поможет кому-то, так как я потратил почти 2 дня на то, чтобы решить эту проблему с помощью моего неприкрытого приложения javafx.

    Давайте будем гением компьютера.