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.
Poslední komentáře