Windows controller



Pobieranie 178.8 Kb.
Strona1/6
Data02.05.2016
Rozmiar178.8 Kb.
  1   2   3   4   5   6

WINDOWS CONTROLLER


Windows Controller to projekt przeznaczony do monitorowania i kontrolowania różnych zadań w systemie Windows (w wersjach od win2000). Podstawowym zadaniem jest monitorowanie i odczytywanie informacji o oknach i kontrolkach widocznych przez użytkownika. Projekt realizuje także kilka innych zadań.


  1. Struktura projektowa

  2. Ogólne działanie systemu monitorującego

  3. Klasa PSWindowsCtrl

  4. Klasa PSWindow

  5. Klasa PSMenu

  6. Klasa PSControl i jej potomkowie

  7. Klasa PSUIControl

  8. Klasa PSMouseGrid

  9. Klasa PSBitmap

  10. Windows controller od środka

    • Załadowanie i zwolnienie systemu nasłuchującego

    • Zapytanie serwera

    • Zdarzenia zwrotne do serwera

    • Polecenia zarządzające bitmapą

    • Polecenie edycji PSCRich

Struktura projektowa


Projekt w sensie C++ składa się z 4 plików wykonywalnych, więc 4 oddzielnie kompilowanych projektów C++:

  1. Główny projekt składa się z kodu, który ma być częścią docelowego programu, w którym ma działać. W tym projekcie musi być stworzony 1 specjalny wątek tylko na potrzeby serwera Windows Controller, w którym będzie pracował. Zadaniem serwera jest odbieranie powiadomień z innych procesów. Reszta projektu to implementacja docelowego programu, nie związana z Windows Controller. Projekt ten musi być 32 bitową wersją pliku z kodem wykonywalnym.

  2. Projekt „wndctrl_client32” biblioteka DLL(x86), która będzie załadowana do wszystkich procesów do których ma dostęp proces Windows Controller (łącznie z własnym). Jej podstawowymi zadaniami są: monitorowanie zdarzeń, pobieranie informacji i wysyłanie powiadomień o oknach działających w ramach danego procesu. W przypadku systemu 64 bitowego ta biblioteka DLL może zostać załadowana jedynie do 32 bitowych procesów.

  3. Projekt „wndctrl_client64” biblioteka DLL(x64) w wersji 64 bitowej. W systemach Windows 64 bitowych część procesów będzie działać w trybie 64 bitowym, stąd zachodzi konieczność istnienia wersji biblioteki DLL, która będzie mogła zostać załadowana do tych procesów. Jest jedynie 64 bitowym odpowiednikiem wersji 32 bitowej, kompilowana dokładnie z tych samych plików źródłowych co wersja 32 bitowa. W przypadku działania Windows Controller w systemie 32 bitowym, biblioteka ta nie będzie miała zastosowania.

  4. Projekt „wndctrl_loader64” to malutka aplikacja 64 bitowa, której zadaniem będzie sterowanie 64 bitowej biblioteki DLL(wndctrl_client64.dll), gdyż 32 bitowa aplikacja główna nie może załadować i sterować biblioteki 64 bitowej, stąd zachodzi konieczność zarządzania nią przez tę aplikację, która dopiero może być sterowana za pośrednictwem głównej aplikacji.

Ogólne działanie systemu monitorującego


System monitorujący zdarzenia występujące w oknach należących do innych procesów opiera się na mechanizmie HOOK’ów (http://msdn.microsoft.com/en-us/library/ms644959(v=VS.85).aspx). Mechanizm ten daje możliwość umieszczenia w każdym procesie własnej DLLki, w której będzie zdefiniowana funkcja, która będzie każdorazowo wywoływana przed przetworzeniem jakiegokolwiek zdarzenia okna lub kontrolki w danym procesie.

W przypadku systemu 64 bitowego muszą istnieć 2 wersje bibliotek DLL, odpowiednio dla procesów 32 i 64 bitowych.

Poniższy rysunek przedstawia zależności występujące pomiędzy poszczególnymi procesami po zamontowaniu systemu monitorowania w systemie 64 bitowym (w systemie 32 bitowym podsystem 64 nie istnieje):

Strzałki reprezentują przepływ informacji. Aplikacja główna może wysyłać do dowolnego okna odpowiedni komunikat w celu wykonania określonego polecenia (pobrania zawartości, utworzenia na nim bitmapy/animacji, itd.) w procesie okna, tak samo DLL może wysłać komunikat do serwera celem zawiadomienia o jakimś zdarzeniu. Cała komunikacja opiera się na funkcjach Win32: SendMessage i PostMessage, które wysyłają określone zdarzenie do określonego okna. W przypadku niektórych komunikatów wykorzystywana jest także, pamięć współdzielona (wspólna między procesami) do wymiany większej ilości informacji.


Wszystkie string’i w metodach operujących na tekście są kodowane w formacie UTF-8. Dodatkowo wycinane są wszystkie znaki ‘&’, które w nazwach są zwykle znakami sterującymi, np. jako podkreślenie w menu.
Część metod (oznaczonych w dokumentacji tłem żółtym) wykonuje swoje operacje w przestrzeni innego procesu. W celu uzyskania statusu powodzenia tych operacji w innym procesie, stosowany jest obiekt synchronizacyjny wspólny dla pewnej grupy danych metod, dlatego nie należy dokonywać jednoczesnych wywołań tych metod w różnych wątkach, gdyż dojdzie do konfliktu dostępu do danego obiektu synchronizującego i zwracany status powodzenia może być niepoprawny. Celem rozwiązania tego problemu jest wywoływanie danej grupy metod z tego samego wątku, aby nie dochodziło do równoczesnych wywołań metod lub zastosowanie synchronizacji.

Klasa PSWindowsCtrl


PSWindowsCtrl jest główną klasą w Windows Controller. Obiekt PSWindowsCtrl można tworzyć i niszczyć dowolnym momencie programu, ważne jest jednak, aby nie utworzyć dwóch instancji tego obiektu, gdyż dojdzie do kolizji danych w polach statycznych. Obiekt może istnieć na stosie, stercie lub bloku danych, nie ma to wpływu na jego pracę.

Pierwszą część klasy stanowią prywatne (w większości) pola, używane tylko i wyłącznie wewnętrznie przez klasę, dlatego zostaną omówione w dalszej części dokumentacji.


vector
windows_vec;

Wektor zawierający wskaźniki do obiektów wyliczonych okien. Wektor ten jest uaktualniany tylko podczas wywołania metody getVisibleWindows() i nie może być w tym czasie odczytywany w innym wątku. Nie należy także ręcznie zwalniać obiektów w wektorze. Nie wolno także zachowywać na stałe wskaźników do obiektów z tego wektora, gdyż po wywołaniu getVisibleWindows() obiekty mogą zostać zwolnione.


vector
sub_menus_vec;

Wektor zawierający obiekty typ PSMenu - aktualnie wyświetlanych menu.


bool PSWindowsCtrl::Startup();

Definicja: „windows_controller_server.cpp”

Metoda ta startuje działanie serwera i mechanizm monitorowania zdarzeń w innych procesach. Zwraca false w przypadku napotkanego błędu. W przypadku gdy zostanie wywołana na już pracującym serwerze zostanie zwrócona wartość false.

UWAGA: Metoda musi zostać wywołana w wątku, w którym będzie działał serwer. Wątek taki musi mieć sprawnie działającą systemową kolejkę komunikatów.

Na samym początku definicji tej metody znajduje się ścieżka do 32 bitowej biblioteki DLL, będącej klientem dla serwera. Jeśli biblioteka DLL ma działać z innego folderu niż folder główny, należy tu ustawić tę ścieżkę, względem folderu roboczego aplikacji głównej.

const char* const DLLClientName32 = "wndctrl_client32.dll"; //w windows_controller_server.cpp

Jeśli exe’c ładujący środowisko 64 bitowe ma także znajdować się w innym folderze niż aplikacja główna, na początku definicji metody: bool PSWindowsCtrl::TryMountHook64() (plik: ”windows_controller_server.cpp”) znajduje się ściezka do tego pliku aplikacji:

const char* const App64_Path = "wndctrl_loader64.exe"; //w windows_controller_server.cpp

Następnie w pliku źródłowym aplikacji wndctrl_loader64.exe znajduje się ścieżka do 64 bitowej biblioteki DLL, którą aplikacja ładuje i zarządza. Należy w niej podać miejsce DLL64 względem aplikacji 64 bitowej.

const char* const DLLClientName64 = "wndctrl_client64.dll; //w main.cpp aplikacji 64 bitowej

Jeśli ścieżki nie będą się zgadzać Startup będzie zwracało false.

Jeśli serwer zostanie wystartowany, w przypadku odebrania zdarzeń będą wywoływane funkcje onWindowsChange, onControlsChange, onBitmapInput, maksymalnie co zdefiniowany w polu:

unsigned int timeout;

interwał czasowy. Pole timeout używane jest tylko podczas wywołania Startup, więc zmiana wartości timeout nie spowoduje zmiany interwału w obecnie pracującym serwerze. Dopiero ponowny start serwera będzie działał z nową wartością.

PSWindowsCtrl* cc;

[...]


cc->timeout = 200; //200ms

cc->Startup();


void PSWindowsCtrl::Shutdown();

Definicja: „windows_controller_server.cpp”

Zatrzymuje działanie i zamyka serwer wystartowany metodą Startup. Jeżeli metoda nie ma co zamykać, bo serwer nie został wystartowany - nie robi nic. Metoda tak jak Startup, musi zostać wywołana w wątku serwera. Metoda ta zwalnia także obiekty w „windows_vec”, więc gdy serwer będzie wyłączony wektor ten będzie zawsze pusty.

UWAGA: ponieważ w destruktorze ~PSWindowsCtrl() nie jest wywołania metoda Shutdown, dlatego przed zwolnieniem obiektu PSWindowsCtrl, musi być pewność, że serwer został wyłączony metodą Shutdown – jeśli działał, w przeciwnym wypadku dojdzie do wycieków pamięci.
bool PSWindowsCtrl::getVisibleWindows();

Definicja: „windows_controller_get_data.cpp”

Metoda pobiera aktualny stan okien i kontrolek do wektora „windows_vec”. Może być wywoływana z dowolnego wątku. Metoda zawsze zwraca true. W przypadku wystąpienia problemów z poszczególnymi danymi, dane błędne zostaną zignorowane i po prostu nie zostaną uwzględnione w „windows_vec”.

W zwykłych okolicznościach metoda ta wylicza jedynie okna główne i ich właściwości (obiekty PSWindow), W przypadku zdefiniowania flagi: #define ENUM_ALL_WINDOWS_CONTROLS w „windows_controller.h”, oraz kompilacji w takim ustawieniu bibliotek DLL, metoda getVisibleWindows będzie wyliczać kontrolki dla wszystkich okien.

Metoda ta wylicza także ewentualnie znalezione okna otwartych menu - do wektora:

vector
sub_menus_vec;

Wywołanie metody zakończy się dopiero po całkowitym wypełnieniu danych wektorów.


bool PSWindowsCtrl::getWindowsControls(PSWindow* window);

Metoda ta uaktualnia informacje na temat danego okna, włączając w to wszystkie pola obiektu PSWindow, w szczególności wektory:

vector
controls_vec

vector
child_windows_vec;

aktualnym stanem okien potomnych dla podanego obiektu typu PSWindow w parametrze metody.

Równie jak metoda getVisibleWindows zawsze zwraca true, a w przypadku błędu dla jakiejś danej nie zostanie ona uwzględniona w wyniku działania metody. Metodę można także wywoływać w dowolnego wątku. Metoda będzie się wykonywać, aż w całości nie zostaną pobrane zawartości wektorów.


bool PSWindowsCtrl::showDesktop();

Metoda wykonuje polecenie powłoki expolrer’a „pokaż pulpit” (polecenie nr 407). Jeżeli pasek explorer’a nie zostanie znaleziony (prawdopodobnie proces „explorer.exe” nie działa) funkcja zwróci false, natomiast true w przypadku znalezienia okna i wysłania do niego polecenia. Metoda nie czeka aż Explorer wykona polecenie, jedynie wysyła do niego wykonanie polecenia i przekazuje sterowanie dalej do programu.


bool PSWindowsCtrl::getScreenResolution(int& width, int& height);

Metoda pobiera aktualne wymiary ekranu w pixelach. Parametrami są zmienne, w których zostaną umieszczone informacje o szerokości i wysokości. Zwraca true w przypadku powodzenia. Jeżeli wystąpi z niewiadomych przyczyn błąd, funkcja zwraca false, a zmiennym parametrowym mogą zostać przypisane wartości 0 (co najmniej jedna zmienna z parametru będzie miała na pewno wartość 0).


bool PSWindowsCtrl::copyToClipboard(string text);

Metoda kopiuje do systemowego schowa tekst podany w parametrze. Jeśli tekst zostanie umieszczony w schowku zwraca true, w przypadku błędu zwraca false.


bool PSWindowsCtrl::getTextFromClipboad(string& text);

Metoda pobiera ze schowka tekst i umieszcza go do string’a podanego w parametrze. Metoda używa przypisania, więc jeśli string przechowywał tekst - zostanie nadpisany. Jeśli nie wystąpi żaden błąd, funkcja zwróci true, natomiast jeżeli wystąpi jakiegoś rodzaju błąd lub po prostu w schowku nie będzie tekstu do pobrania metoda zwróci false, a string z parametru nie zostanie zmodyfikowany.


bool PSWindowsCtrl::copyToClipboard(unsigned long long handle);

Metoda dokonuje operacji kopiowania do schowka z okna PSWindowsCtrl::Windows_vec posiadającego fokus. Ponieważ nie ma uniwersalnej metody kopiowania, kopiowanie zaimplementowane jest dla okien aplikacji „explorer.exe” oraz „mspaint.exe”. Jeżeli okno nie należy do tych aplikacji, metoda wysyła komunikat WM_COPY (http://msdn.microsoft.com/en-us/library/ms649022(VS.85).aspx) do kontrolki posiadającej fokus klawiaturowy. Komunikat ten obsługują systemowe kontrolki działające na tekście.


bool PSWindowsCtrl::cutToClipboard(unsigned long long handle);

Metoda dokonuje operacji wycinania do schowka z okna PSWindowsCtrl::Windows_vec posiadającego fokus. Ponieważ nie ma uniwersalnej metody wycinania, wycinanie zaimplementowane jest dla okien aplikacji „explorer.exe” oraz „mspaint.exe”. Jeżeli okno nie należy do tych aplikacji, metoda wysyła komunikat WM_CUT (http://msdn.microsoft.com/en-us/library/ms649023(v=VS.85).aspx) do kontrolki posiadającej fokus klawiaturowy. Komunikat ten obsługują systemowe kontrolki działające na tekście. W razie błędu zwraca false.


bool PSWindowsCtrl::pasteFromClipboard(unsigned long long handle);

Metoda dokonuje operacji wklejania ze schowka do okna PSWindowsCtrl::Windows_vec posiadającego fokus. Ponieważ nie ma uniwersalnej metody wklejania, wklejanie zaimplementowane jest dla okien aplikacji „explorer.exe” oraz „mspaint.exe”. Jeżeli okno nie należy do tych aplikacji, metoda wysyła komunikat WM_PASTE (http://msdn.microsoft.com/en-us/library/ms649028(v=VS.85).aspx) do kontrolki posiadającej fokus klawiaturowy. Komunikat ten obsługują systemowe kontrolki działające na tekście. W razie błędu zwraca false.


bool PSWindowsCtrl::setCursorPosition(int x, int y);

Metoda ustawia kursor systemowy w nowych współrzędnych, mapowanych względem lewego-górnego rogu ekranu i rosnących od lewej do prawej i od góry do dołu. Jeśli przesunięcie kursora się powiedzie zwracana jest wartość true, false w przeciwnym wypadku. Jeśli podane współrzędne będą zbyt wysokie lub zbyt niskie zostaną dostosowane do maksymalnego wychylenia (maksymalnego skrajnego punktu), a metoda nadal zwróci powodzenie.

W przypadku systemu Windows Vista, aby przesunąć kursor proces musi posiadać uprawnienia typu: WINSTA_WRITEATTRIBUTES (http://msdn.microsoft.com/en-us/library/ms687391(VS.85).aspx).
bool PSWindowsCtrl::mouseDownLeft();

bool PSWindowsCtrl::mouseUpLeft();

bool PSWindowsCtrl::mouseClickLeft();

bool PSWindowsCtrl::mouseDoubleClickLeft();

bool PSWindowsCtrl::mouseDownRight();

bool PSWindowsCtrl::mouseUpRight();

bool PSWindowsCtrl::mouseClickRigth();

Metody te emulują w systemie zdarzenie wejścia (naciśnięcie i/lub zwolnienie) odpowiedniego przycisku myszki. W przypadku niepowodzenia zwracają false. Mogą być wywoływane z dowolnego wątku.


bool PSWindowsCtrl::keyDown(int key_code);

bool PSWindowsCtrl::keyUp(int key_code);

bool PSWindowsCtrl::keyPress(int key_code);

Metody te emulują zdarzenie wejścia (naciśnięcie i/lub zwolnienie) przycisku na klawiaturze. Parametr metody określa wirtualny klawisz, dla którego zostanie wygenerowane zdarzenie. Wartości wirtualnych klawiszy są zgodne z wartościami wirtualnych kodów klawiszy w systemie Windows (http://msdn.microsoft.com/en-us/library/dd375731(VS.85).aspx). W przypadku niepowodzenia metoda zwraca false. Mogą być wywoływane z dowolnego wątku.

Metoda PSWindowsCtrl::keyPress jest dobrym sposobem emulacji pisania na klawiaturze.
enum onWindowsChangeEvents {

wcePosition = 0x01,

wceFocusedPosition = 0x02,

wceActivate = 0x04,

wceTextChange = 0x08

};

void onWindowsChange(unsigned long events);



Funkcja onWindowsChange reprezentuje zdarzenie związane z jednym z okien głównych. Jej implementacja powinna znajdować się w programie docelowym. Funkcja jest wywoływana przez serwer w wątku, w którym pracuje serwer Windows Controller, jeśli minie interwał czasowy timeout, a w tym czasie w systemie pojawi się zdarzenie na, które reaguje mechanizm nasłuchiwania.

W parametrze events pojawia się informacja o zdarzeniach jakie wystąpiły od ostatniego wywołania funkcji. Informacje te są zapisane na poszczególnych bitach opisanych przez typ enum onWindowsChangeEvents:



  • wcePosition – ten bit oznacza, że wystąpiło zdarzenie zmiany pozycji lub wymiarów pierwszo planowanego okna, ale bez zmiany samego okna pierwszoplanowego.

  • wceFocusedPosition – ten bit oznacza, że wystąpiło zdarzenie zmiany okna pierwszoplanowego, z ewentualną zmianą pozycji lub szerokości.

  • wceActivate – ten bit oznacza wystąpienie zdarzenia aktywacji lub dezaktywacji widoczności jednego z okien. Zdarzenie to może występować w przypadku utworzenia nowego lub zniszczenia istniejącego okna, oraz schowanie/pokazanie, minimalizację/przywrócenie istniejącego okna.

  • wceTextChange – Zdarzenie to oznacza, że tytuł jednego z okien głównych uległ zmianie.

Nie może dojść do sytuacji w której wartość events wynosiła by 0 (zawsze musi być co najmniej 1 bit zapalony, reprezentujący zdarzenie), a także bity, które nie są uwzględnione w typie enum onWindowsChangeEvents zawsze będą miały wartość 0.
void onControlsChange(const vector& handles);

Funkcja onControlsChange reprezentuje zdarzenie związane z kontrolką utworzoną na głównym oknie pierwszoplanowym. Funkcja jest wywoływana tylko w przypadku, gdy w interwale czasowym timeout nie wystąpiło zdarzenie generujące onWindowsChange, oraz wystąpiło zdarzenie mogące wpłynąć na właściwości jednej z kontrolek głównego okna pierwszoplanowego. Funkcja jest wywoływana przez serwer w wątku, w którym pracuje serwer Windows Controller.

Parametrem funkcji jest stały wektor, który zawiera listę uchwytów kontrolek okna pierwszoplanowego, w których od ostatniego wywołania onWindowsChange lub onControlsChange wykryto zdarzenia, na które czuły jest mechanizm monitorowania zdarzeń. Nie wszystkie uchwyty w wektorze handles, mogą istnieć jako kontrolki typu PSControl w wektorze PSWindow::controls_vec. W wektorze tym są także uchwyty dla poszczególnych obiektów PSUIItem. Wektor handles istnieje na stałe, nie tylko podczas wywołania funkcji onControlsChange, ale nie zaleca się pobrania referencji lub wskaźników do niego, w celu późniejszego odczytywania go w innym wątku, ze względu na to, że jedynie podczas wywołania onControlsChange jest pewność, że do wektora nic nie będzie dopisywane - wątek serwera w innym przypadku może w dowolnym momencie dodawać do niego nowe elementy uchwytów.
UWAGA: Metody PSWindowsCtrl::getVisibleWindows i PSWindowsCtrl::getWindowControls powinny być wywoływane tylko w ramach wątku, który będzie odczytywał dane z wektorów PSWindowsCtrl::windows_vec i PSWindows::sub_menus_vec i ich obiektów, aby nie mógł odczytywać równolegle podczas uaktualniania danych w wektorach. Bezpośrednie wywołanie metod PSWindowsCtrl::getVisibleWindows lub PSWindowsCtrl::getWindowControls w funkcjach onWindowsChange lub onControlsChange nie jest zalecane, w uwagi na brak metod synchronizacji, co było założeniem projektowym. W funkcjach tych powinna znaleźć się jedynie akcja poinformowania wątku odczytującego wektory o konieczności aktualizacji ich danych.




  1   2   3   4   5   6


©absta.pl 2019
wyślij wiadomość

    Strona główna