Привязка приложения 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.
Ответы
Ответ 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 к ярлыку при его создании во время установки.
Ответ 6
В последней библиотеке jna-platform
теперь есть привязки JNA для SetCurrentProcessExplicitAppUserModelID
:
https://github.com/java-native-access/jna/pull/680
Ответ 7
Я установил мой без каких-либо настроек идентификатора.
В Launch4J есть опция, если вы используете ее, и вы говорите, что делаете то...
Вы можете изменить заголовок на JNI Gui, а затем обернуть его вокруг банки JRE.
Хорошо, что теперь он запускает .exe, а вместо этого запускает javaw.exe с вашей банкой. Вероятно, он находится под капотом (не уверен).
Кроме того, я заметил также, что он требует около 40-50% ресурсов ЦП, что еще лучше!
И пиннинг работает отлично, и все функции окна включены.
Я надеюсь, что это поможет кому-то, так как я потратил почти 2 дня на то, чтобы решить эту проблему с помощью моего неприкрытого приложения javafx.