java - tutorial - Usando JNA para obtener/configurar el identificador de la aplicación
java swing tutorial pdf español (3)
Siguiendo con mi pregunta anterior sobre la barra de tareas de Windows 7 , me gustaría diagnosticar por qué Windows no reconoce que mi aplicación es independiente de javaw.exe
. Actualmente tengo el siguiente código JNA para obtener el AppUserModelID
:
public class AppIdTest {
public static void main(String[] args) {
NativeLibrary lib;
try {
lib = NativeLibrary.getInstance("shell32");
} catch (Error e) {
System.err.println("Could not load Shell32 library.");
return;
}
Object[] functionArgs = new Object[1];
String functionName = null;
Function function;
try {
functionArgs[0] = new String("Vendor.MyJavaApplication")
.getBytes("UTF-16");
functionName = "GetCurrentProcessExplicitAppUserModelID";
function = lib.getFunction(functionName);
// Output the current AppId
System.out.println("1: " + function.getString(0));
functionName = "SetCurrentProcessExplicitAppUserModelID";
function = lib.getFunction(functionName);
// Set the new AppId
int ret = function.invokeInt(functionArgs);
if (ret != 0) {
Logger.out.error(function.getName() + " returned error code "
+ ret + ".");
}
functionName = "GetCurrentProcessExplicitAppUserModelID";
function = lib.getFunction(functionName);
// Output the current AppId
System.out.println("2: " + function.getString(0));
// Output the current AppID, converted from UTF-16
System.out.println("3: "
+ new String(function.getByteArray(0, 255), "UTF-16"));
} catch (UnsupportedEncodingException e) {
System.err.println("System does not support UTF-16 encoding.");
} catch (UnsatisfiedLinkError e) {
System.err.println(functionName + " was not found in "
+ lib.getFile().getName() + ".");
}
}
}
La salida de la aplicación es aparentemente tontería:
1: ‹ÿU‹ìƒìL¡¬Ÿv3ʼnEüSV‹uƒ&
2: ‹ÿU‹ìƒìL¡¬Ÿv3ʼnEüSV‹uƒ&
3: ????????????????P???????????
Teniendo en cuenta el hecho de que la salida puede ser UTF-16, en (3) intenté convertir una matriz de bytes de UTF-16. Honestamente, no sé si mi enfoque aquí es correcto como (a) No sé el tamaño de un PWSTR
y (b) No sé si GetCurrentProcessExplicitAppUserModelID
está devolviendo una matriz de bytes o una cadena.
Soy consciente de que JSmooth ejecutará el proceso GUI en un contenedor que simula este efecto. Launch4j pretende hacer lo mismo, pero no parece funcionar. Estoy buscando tener el AppUserModelID
configurado independientemente del envoltorio de Java .
¿Qué está mal aquí?
Aquí hay un ejemplo más simple sobre cómo llamar a SetCurrentProcessExplicitAppUserModelID
través de JNA
:
import com.sun.jna.*;
import com.sun.jna.win32.*;
interface Shell32 extends StdCallLibrary {
Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32", Shell32.class, W32APIOptions.DEFAULT_OPTIONS);
NativeLong SetCurrentProcessExplicitAppUserModelID(WString appID);
}
No había visto tu pregunta antes de lo contrario, habría dado una oportunidad incluso sin una recompensa.
Aquí es lo que se me ocurrió. Tenga en cuenta que, como se indica en el código mismo, no implementé la limpieza adecuada de la memoria con la función CoTaskMemFree
(de Ole32.dll
). Así que te sugiero que tomes solo la implementación de SetCurrentProcessExplicitAppUserModelID()
package com..AppIdTest;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.ptr.PointerByReference;
public class AppIdTest
{
public static void main(String[] args) throws Exception
{
setCurrentProcessExplicitAppUserModelID(AppIdTest.class.getName());
System.out.println(getCurrentProcessExplicitAppUserModelID());
}
// DO NOT DO THIS, IT''S JUST FOR TESTING PURPOSE AS I''M NOT FREEING THE MEMORY
// AS REQUESTED BY THE DOCUMENTATION:
//
// http://msdn.microsoft.com/en-us/library/dd378419%28VS.85%29.aspx
//
// "The caller is responsible for freeing this string with CoTaskMemFree when
// it is no longer needed"
public static String getCurrentProcessExplicitAppUserModelID()
{
final PointerByReference r = new PointerByReference();
if (GetCurrentProcessExplicitAppUserModelID(r).longValue() == 0)
{
final Pointer p = r.getValue();
return p.getString(0, true); // here we leak native memory by lazyness
}
return "N/A";
}
public static void setCurrentProcessExplicitAppUserModelID(final String appID)
{
if (SetCurrentProcessExplicitAppUserModelID(new WString(appID)).longValue() != 0)
throw new RuntimeException("unable to set current process explicit AppUserModelID to: " + appID);
}
private static native NativeLong GetCurrentProcessExplicitAppUserModelID(PointerByReference appID);
private static native NativeLong SetCurrentProcessExplicitAppUserModelID(WString appID);
static
{
Native.register("shell32");
}
}
¿Funciona para ti?
Al menos aquí se imprime correctamente:
com..AppIdTest.AppIdTest
Si solo necesita configurar AppUserModelId, el código JNA anterior es suficiente. Sin embargo, si desea aprovechar las nuevas características de Windows 7 en su aplicación Java, revise J7Goodies una biblioteca de Java que brinda las extensiones de la barra de tareas de Windows 7.
EDITAR : más información de J7Goodies Programmer''s Guide
4.2. Configuración de AppUserModelID
Para utilizar cualquiera de las características de Windows 7, una aplicación debe establecer explícitamente su identificador de proceso: ID de modelo de usuario de la aplicación (
AppUserModelID
). No puede tener más de 128 caracteres y no puede contener espacios. Cada sección debe ser de camello, por ejemplo:
CompanyName.ProductName.SubProduct.VersionInformation
Este identificador debe establecerse antes de que se muestre cualquier GUI (ventana). Se configura llamando
// Remember to set AppUserModelID before creating any UI
AppUserModelId.setCurrentProcessId("StrixCode.J7Goodies.Appname");
4.3. Configuración de las propiedades de la ventana
Una aplicación Java no se puede anclar a la barra de tareas de Windows 7 a menos que se definan sus propiedades de ventana. Las propiedades constan de cuatro campos:
- AppUserModelID: el mismo que se pasó a
AppUserModelId.setCurrentProcessId(String)
- RelaunchDisplayName - nombre de la aplicación
- RelaunchCommand: el comando completo que se utiliza para iniciar la aplicación. En el caso de un programa Java, será:
<path to javaw.exe> -jar <path to application jar>
- RelaunchIcon - ruta al icono de la aplicación
Importante :
RelaunchCommand
yRelaunchDisplayName
siempre se deben establecer juntos. Para establecer estas propiedades, use la clase directa WindowProperties.
WindowProperties props = new WindowProperties(myFrame);
props.setRelaunchCommand("<full path to javaw.exe –arguments>");
props.setRelaunchDisplayName("My Java Application");
props.setRelaunchIcon("<full path to an .ico or .exe file>");
props.setAppUserModelID("StrixCode.J7Goodies.Appname");
props.save();