Fijación de una aplicación Java a la barra de tareas de Windows 7
-
11-09-2019 - |
Pregunta
Yo uso Launch4j como envoltura para mi aplicación Java en Windows 7, que, a mi entender, en esencia horquillas una instancia de javaw.exe
que a su vez interpreta el código Java. Como resultado, cuando se trata de fijar mi solicitud a la barra de tareas, en lugar de Windows pines javaw.exe
. Sin la línea de comandos es necesario, mi solicitud será entonces no se ejecutan.
Como se puede ver, Windows también no se da cuenta de que Java es la aplicación host:. La propia aplicación se describe como "Java (TM) SE binaria"
He intentado alterar el HKEY_CLASSES_ROOT\Applications\javaw.exe
clave de registro para añadir el valor IsHostApp
. Esto altera el comportamiento mediante la desactivación de la fijación de mi solicitud por completo; claramente no es lo que quiero.
Después de leer sobre cómo Windows interpreta instancias de una sola aplicación (y un fenómeno discutido en esta pregunta ), me interesé en la incorporación de un identificador de solicitud de modelo de usuario (AppUserModelID) en mi aplicación Java.
Creo que puedo resolver esto pasando un AppUserModelID
único para Windows. Hay un método shell32
para esto, SetCurrentProcessExplicitAppUserModelID
. Después de Gregory Pakosz sugerencia, he implementado en un intento para que mi aplicación reconocida como una instancia independiente de 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
}
Esto parece tener ningún efecto, pero la función devuelve sin error. El diagnóstico de por qué es un misterio para mí. ¿Alguna sugerencia?
implementación funcional
La aplicación final que trabajó es la respuesta a mi pregunta de seguimiento relación con la forma de pasar el AppID
usando JNA.
Me había adjudicado a la generosidad brillante respuesta Gregory Pakosz' para la JNI que me puso en el camino correcto.
A modo de referencia, creo que el uso de esta técnica abre la posibilidad de utilizar cualquiera de las API discutidos en este artículo en una aplicación Java.
Solución
No tengo Windows 7, pero aquí es algo que podría empezar:
En el lado de Java:
package com.stackoverflow.homework;
public class MyApplication
{
static native boolean setAppUserModelID();
static
{
System.loadLibrary("MyApplicationJNI");
setAppUserModelID();
}
}
Y en el lado nativo, en el código fuente de la biblioteca `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;
}
Su pregunta pidió explícitamente una solución JNI. Sin embargo, dado que su aplicación no necesita ningún otro método nativo, JNA es otra solución que permitirá ahorrar que desde escribir código nativo por el simple hecho de remitir a la API de windows. Si usted decide ir JNA, prestar atención al hecho de que SetCurrentProcessExplicitAppUserModelID()
espera una cadena UTF-16.
Cuando se trabaja en su caja de arena, el siguiente paso es añadir la detección de sistema operativo en su aplicación como SetCurrentProcessExplicitAppUserModelID()
es, obviamente, sólo está disponible en Windows 7:
- Puede hacerlo desde el lado de Java mediante la comprobación de que
System.getProperty("os.name");
devuelve"Windows 7"
. - si se construye desde el pequeño fragmento de código JNI di, puede mejorarlo mediante la carga dinámicamente la biblioteca
shell32.dll
usandoLoadLibrary
luego volver al puntero de funciónSetCurrentProcessExplicitAppUserModelID
usandoGetProcAddress
. SiGetProcAddress
vuelveNULL
, significa que el símbolo no está presente enshell32
por lo tanto, no es de Windows 7.
EDIT:. Solución JNA
Referencias:
- El libro JNI para más ejemplos JNI
- Java Native Acceso (JNA)
Otros consejos
Hay una biblioteca de Java que proporciona las nuevas características de Windows 7 para Java. Se llama Código Strix . Las aplicaciones que utilizan que se pueden fijar correctamente a la barra de tareas de Windows 7. También puede crear sus propias listas de salto, etc.
Trate de usar JSmooth . Yo siempre uso de éste. En JSmooth hay una opción en Skeleton
por Windowed Wrapper
llamado
aplicación java Lauch en proceso exe
Ver sobre esta imagen.
También comando argumentos de línea se pueden pasar.
Creo que esto puede ser una solución para usted.
Martijn
He implementado el acceso al método SetCurrentProcessExplicitAppUserModelID usando JNA y funciona bastante bien cuando se utiliza según la documentación de MSDN sugiere. Nunca he utilizado la API JNA en la forma que tiene en su fragmento de código. Mi aplicación sigue la uso JNA típica lugar.
En primer lugar la definición de interfaz Shell32:
interface Shell32 extends StdCallLibrary {
int SetCurrentProcessExplicitAppUserModelID( WString appID );
}
Luego, utilizando JNA para cargar Shell32 y llamar a la función:
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 );
Muchas de las API en el último artículo que usted ha mencionado hacer uso de COM de Windows que es bastante difícil de usar directamente con JNA. He tenido cierto éxito la creación de un archivo DLL personalizado para llamar a éstos del API (por ejemplo. Mediante el SHGetPropertyStoreForWindow para establecer un ID de aplicación diferente para una ventana submódulo) que luego utilizo JNA para acceder en tiempo de ejecución.
SetCurrentProcessExplicitAppUserModelID (o SetAppID ()) sería, de hecho, hacer lo que estamos tratando de hacer. Sin embargo, podría ser más fácil de modificar su instalador para establecer la propiedad AppUserModel.ID en su acceso directo - citando el documento usuario de la aplicación Modelo ID mencionado anteriormente:
En el System.AppUserModel.ID propiedad del archivo de acceso directo de la aplicación. Un acceso directo (como IShellLink, CLSID_ShellLink, o un archivo .lnk) soporta propiedades a través IPropertyStore y otros mecanismos de propiedad de fijación utilizados en el Shell. Esto permite que la barra de tareas para identificar el acceso directo a la clavija adecuada y asegura que las ventanas que pertenecen al proceso están asociados apropiadamente con ese botón de la barra de tareas. Nota: La propiedad System.AppUserModel.ID se debe aplicar a un acceso directo cuando se crea ese acceso directo. Cuando se utiliza el Microsoft Windows Installer (MSI) para instalar la aplicación, la mesa de MsiShortcutProperty permite al AppUserModelID que se aplicará al acceso directo cuando se crea durante la instalación.
La última biblioteca jna-platform
ahora incluye fijaciones JNA para SetCurrentProcessExplicitAppUserModelID
:
Me fijo mina sin ningún ajuste de ID. Hay una opción en Launch4J si lo está utilizando y que diga lo hace entonces ...
Puede cambiar la cabecera para JNI Gui y luego se envuelve alrededor de la jarra con el JRE. Lo bueno es que se ejecuta .exe en el proceso ahora en lugar de correr javaw.exe junto con su contenedor. Probablemente lo hace bajo el capó (no estoy seguro). También me he dado cuenta de que también se tarda alrededor de un 40-50% menos de recursos de CPU que es aún mejor!
Y la colocación de clavos funciona bien y todos los que las características de las ventanas están habilitadas.
espero que ayude a alguien como yo pasé casi 2 días tratando de resolver ese problema con mi aplicación javafx sin decorar.