JNA FindWindow

0

Witam.

Próbuje skorzystać z JNA do pobrania otwartego okna innej aplikacji na win7.

Tworze interfejs:

package winapi;

import com.sun.jna.Native;
import com.sun.jna.PointerType;
import com.sun.jna.win32.*;

public interface User32 extends StdCallLibrary {
    User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);

    PointerType FindWindow(String lpClassName, String lpWindowName);
}

I klasę główną:

package winapi;

import com.sun.jna.Native;
import com.sun.jna.PointerType;

public class FindWindow {
    public static void main(String[] args) {
        PointerType window = User32.INSTANCE.FindWindow(null, null);
    }
}

Wypluwa java.lang.UnsatisfiedLinkError na linii:
"PointerType window = User32.INSTANCE.FindWindow(null, null);"

Zamiast nulli podaje odpowiednie stringi. Jeśli wszystko jest ok, to może te stringi nie - ale jeśli nie znajduje okna nie powinno zwrócić null ? I jakie to stringi powinny być ? Któryś może być null, drugi powinien stanowić nazwę okna. Wypróbowałem wszelkie kombinacje i nic.

Mam podejrzenia co do javowych typów w interfejsie. Nie wiem, czy to może być String.

Zastanawiam się też (zgodnie z radami w opisie użycia FindWindow dla Delphi na tym forum) nad użyciem klasy RegisterClass. Wg niektórych wyjaśnień i przykładów powinno też wystarczyć użycie typu WString zamiast String. I utworzenie go metodą 'new WString("name")'. Ale program nadal nie działa.

0

A mnie działa :P Tzn. sam zrobiłem - szczerze nie patrzyłem do Twojego kodu...


package pl.asseco.amms.common.utils;

import com.sun.jna.platform.win32.W32API.HWND;
import com.sun.jna.win32.StdCallLibrary;

public interface User32 extends StdCallLibrary{

    HWND FindWindowA(String lpClassName, String lpWindowName);

}
package pl.asseco.amms.common.utils;

import com.sun.jna.Native;
import com.sun.jna.platform.win32.W32API.HWND;
import javax.swing.JFrame;

public class Test {

    public static final String TITLE = "MojeOknoTest";

    public static void main(String[] args) {
        JFrame przykladoweOkno = new JFrame(TITLE);
        przykladoweOkno.setVisible(true);
        przykladoweOkno.pack();
        HWND uchytPrzykladoweOkno = new HWND();
        uchytPrzykladoweOkno.setPointer(Native.getWindowPointer(przykladoweOkno));
        System.out.println(uchytPrzykladoweOkno);
        //Szukanie przykladowego okna
        User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);
        HWND uchwyt = INSTANCE.FindWindowA(null, TITLE);
        System.out.println(uchwyt);
        if (uchytPrzykladoweOkno.equals(uchwyt)) {
            System.out.println("Uchwyty sa te same wiec znalazlem to okno!!!");
        }
    }
}

Oczywiście w posobny sposób szukasz innych okien - tylko te podejscie ma jedna wadę - musisz znać dokładnie nazwę okna. I to nie jest już tak oczywiste bo aplikacje maja dopiski itp. Innym podejściem jest skorzystanie z funkcji :

boolean EnumWindows(WndEnumProc wndenumproc, Pointer lParam);

int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount);

a tu interfejsik do callbacku:

public interface WndEnumProc extends StdCallLibrary.StdCallCallback
{
boolean callback (HWND hWnd, int lParam);
}

W skrócie system wysypie Ci po kolei jakie okna ma (w callbacku) a Ty możesz wtedy szukać po kawałku albo coś.

Jak widzisz w funkcji dodaje 'A'. To podejscie wywołuje bezpośrednio taką funkcję. Jakbyś zajrzał w user32.dll to znalazłbys właśnie funkcje FindWindowA i FindWindowW.
Różni się to tym, że A to Stringi w ANSI a W chyba w unicode ale już nie pamiętam.

0

package pl.asseco.amms.common.utils; - widzę, że kolega z Asseco :) - takie podejrzenia wzbudza ten pakiet ;)
Dzięki za zainteresowanie tematem - nie działało, bo nie akceptowało funkcji FindWindow, ale FindWindowA już przeszło. Z FindWindowW też jest jakiś problem.

Zbudowałem jednak jeszcze inny program - korzystam z EnumWindows i EnumChildWindows. Potrafię odnaleźć konkretne okno i pobrać jego wszystkie komponenty. Wiem, że poszczególne komponenty mają swoje ID, po którym mogę ustalić, czy dany komponent to button, pole tekstowe, czy coś innego.
GetWindowTextA dla głównych okien pozwala pobrać nazwę okna. Czytałem gdzieś, że w taki sposób można pobrać tekst z pola tekstowego. Ale u mnie pobiera pusty string. Na dole jest kod. Coś jest nie tak ? Cały program ma polegać na tym, że wklejam tekst w jedno pole tekstowe, klikam guzik, wynik pojawia się standardowo na skutek specyfiki działania danej aplikacji desktopowej w drugim polu tekstowym i ja sobie ten przerobiony tekst pobieram. Na razie nie wiem jak wkleić tekst, jak przechwycić ID (gdzieś mi informacja przepadła), jak kliknąć w guzik i pobrać tekst (co pewnie wygląda podobnie do wklejenia tekstu).

Czarnoksiężnicy z Asseco specjalizują się w C++ i trochę w Javie też, więc liczę na pomoc :).

Poniżej kod:

Klasa FindWindow - wykonuje opisany wyżej algorytm


package winapi;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinUser.POINT;
import com.sun.jna.ptr.PointerByReference;
import com.sun.jna.WString;

public class FindWindow {

    public static void main(String[] args) {
        String title = "Nazwa okna";
        //Poprzedni sposób szukania okna
        //HWND window = User32.INSTANCE.FindWindowA(null, title);
        //System.out.println(window.toString());

        WndEnumProc wnd = new WndEnumProc() {
            int count;

            public boolean callback(HWND hWnd, Pointer lParam) {
                byte[] windowText = new byte[512];
                User32.INSTANCE.GetWindowTextA(hWnd, windowText, windowText.length);
                String wText = Native.toString(windowText);
                wText = (wText.isEmpty()) ? "" : "; text: " + wText;

                if (wText.contains("Nazwa")){
                    System.out.println("Found window " + hWnd + ", total " + ++count + wText);

                    WndEnumProc chWnd = new WndEnumProc() {
                    int compCount;
                    public boolean callback(HWND hWnd, Pointer lParam) {

                            byte[] componentText = new byte[1024];
                            User32.INSTANCE.GetWindowTextA(hWnd, componentText, componentText.length);

                            String cText = Native.toString(componentText);
                            cText = (cText.isEmpty()) ? "" : "; text: " + cText;
                            System.out.print("Found component " + hWnd + ", total " + ++compCount + cText);
                            System.out.println("; Is visible: " + User32.INSTANCE.IsWindowVisible(hWnd));
                        return true;
                    }
                    };

                    User32.INSTANCE.EnumChildWindows(hWnd, chWnd, null);    
                }

                return true;
            }
        };

        User32.INSTANCE.EnumWindows(wnd, null);
    }
}

Interfejs User32 - nie wszystkich metod używam w klasie powyżej

package winapi;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.win32.StdCallLibrary;

public interface User32 extends StdCallLibrary {
    User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class);

    HWND FindWindowA(String lpClassName, String lpWindowName);
    boolean IsWindow(HWND hWnd);
    boolean EnumWindows(WndEnumProc wndenumproc, Pointer lParam);
    boolean EnumChildWindows(HWND hWnd, WndEnumProc wndenumproc, Pointer lParam);
    int GetWindowTextA(HWND hWnd, byte[] lpString, int nMaxCount);
    int GetMessageA(MSG lpMsg, HWND hWnd, int wMsgFilterMin, int wMsgFilterMax);

    HWND GetForegroundWindow();
    boolean IsWindowVisible(HWND window);

    public static class MSG extends Structure {
        public WinDef.HWND hWnd;
        public WinDef.LPARAM lParam;
        public int message;
        public POINT pt;
        public int time;
        public WinDef.WPARAM wParam;
    }

    public static class POINT extends Structure {
        public int x, y;
    } 
}

Interfejs WndEnumProc - do stworzenia klasy, której obiekt jest argumentem metod do wyszukiwania okien

package winapi;

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.win32.StdCallLibrary.StdCallCallback;

public interface WndEnumProc extends StdCallCallback {  
    boolean callback(HWND hWnd, Pointer lParam);
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0