Подтвердить что ты не робот

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

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

Result of pinning a Launch4j application to the taskbar

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

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

Result of specifying javaw.exe as a host application

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

Я считаю, что могу решить эту проблему, передав уникальную AppUserModelID в Windows. Для этого существует метод 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.

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

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

4b9b3361

Ответ 1

У меня нет 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 - это еще одно решение, которое избавит вас от написания собственного кода только для ради переадресации в окна api. Если вы решите пойти в jna, обратите внимание на то, что SetCurrentProcessExplicitAppUserModelID() ожидает строку UTF-16.

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

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

EDIT: JNA Solution.

Литература:

Ответ 2

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

Ответ 3

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

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

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

JSmooth

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

Мартейн

Ответ 4

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

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

interface Shell32 extends StdCallLibrary {

    int SetCurrentProcessExplicitAppUserModelID( WString appID );

}

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

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

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

Ответ 5

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

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

Ответ 7

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

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

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

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