Вопрос

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

Result of pinning a Launch4j application to the taskbar

Как вы можете видеть, Windows также не осознает, что Java является основным приложением:само приложение описывается как "Java (TM) Platform SE binary".

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

Result of specifying javaw.exe as a host application

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

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

Это было полезно?

Решение

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

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

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

Редактировать: Решение JNA.

Ссылки:

Другие советы

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

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

Бесплатное java-приложение в исполняемом процессе

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

JSmooth

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

Martijn

Я реализовал доступ к методу 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 для доступа во время выполнения.

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top