Ačkoliv nám Java nabízí spoustu nástrojů, které můžeme využívat, někdy se přeci jenom musíme „snížit“ a použít nativní volání funkce přímo z operačního systému. Jak na to ve Windows si ukážeme v následujícím článku.

Nedávno jsme potřebovali ve své aplikaci zjistit, zda-li je spuštěna aplikace, na které byla druhá aplikace závislá. Bohužel nebylo možné použít kontrolu procesů ve Windows, protože i druhá aplikace běžela pod procesem java.exe, tudíž by nám její jméno bylo k ničemu. Nakonec jsme přišli na řešení, které vyřešilo náš problém – kontrolu existence okna dané aplikace přes Win API a konkrétně metodu FindWindow z user32.dll. Nalézt postup, jak zavolat nativní funkce z této knihovny nám chvíli trvalo a proto se s vámi chceme o tento postup podělit.

Základem je vytvořit následující dvě rozhraní:


public interface W32API extends StdCallLibrary {

Map UNICODE_OPTIONS = new HashMap() {

{
put(OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
}
};

Map ASCII_OPTIONS = new HashMap() {

{
put(OPTION_TYPE_MAPPER, W32APITypeMapper.ASCII);
put(OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.ASCII);
}
};

Map DEFAULT_OPTIONS = Boolean.getBoolean("w32.ascii") ? ASCII_OPTIONS : UNICODE_OPTIONS;

public static class HANDLE extends PointerType {

public Object fromNative(Object nativeValue, FromNativeContext context) {
Object o = super.fromNative(nativeValue, context);
if (INVALID_HANDLE_VALUE.equals(o))
return INVALID_HANDLE_VALUE;
return o;
}
}

public static class HWND extends HANDLE {}

HANDLE INVALID_HANDLE_VALUE = new HANDLE() {

{
super.setPointer(Pointer.createConstant(-1));
}

public void setPointer(Pointer p) {
throw new UnsupportedOperationException("Immutable reference");
}
};
}

public interface USER32 extends W32API {

USER32 INSTANCE = (USER32)Native.loadLibrary("user32", USER32.class, DEFAULT_OPTIONS);

boolean ShowWindow(HWND hWnd, int nCmdShow);
boolean SetForegroundWindow(HWND hWnd);
HWND FindWindow(String winClass, String title);
}

Tato dvě rozhraní se starají o zprostředkování přístupu k nativním knihovnám Windows (v našem případě k user32.dll). User32 je známá knihovna, která umožňuje práci především s GUI Windows a disponuje mnoha zajímavými funkcemi. Mezi ně patří i námi požadovaná funkce FindWindow, která najde okno dle jeho názvu a vrátí nám hWND. hWND je „window handler“ a jedná se o standardní způsob jak můžou cizí aplikace dostat k danému oknu. Jako parametry má pak winClass což je skupina oken, do kterých hledané okno spadá (např. Shell_TrayWnd – vezme okna pouze z Windows tray apod. – pokud uvedeme null, pak se hledá všude, nezávisle na třídě) a title což je titulek okna.

Další zmíněné metody pak slouží k přenesení okna do popředí (SetForegroundWindow) a k nastavení stavu ona. Obě metody mají v parametrech hWND, který získáme právě z metody FindWindow (jsou samozřejmě i jiné cesty).

Pokud tedy chceme nalézt okno, které se jmenuje Eclipse, poté nám stačí zavolat metodu z našeho rozhraní:


public boolean isEclipseRunning() {
W32API.HWND hwnd = USER32.INSTANCE.FindWindow(null, "Eclipse");
return hwnd != null;
}


Tímto jednoduchým způsobem můžeme ověřit, že daná aplikace je již spuštěna (bohužel nám to neřekne nic o jejím stavu) a reagovat na to v naší aplikaci.

Vybráno z komentářů

JNA?

Dobrý den,

pochopil jsem to dobře, že zde mluvíte o použití knihovny JNA?

Nikde to v celém článku není uvedeno.

Odpověď na JNA

Ano, opravdu se jedná o použití knihovny JNA – omlouvám se, že jsem na to blíže nepoukázal.