Kreator apletów panelu sterowania W systemach z rodziny Windows 3.x aplety dostępne w Panelu sterowania służyły przede wszystkim do konfigurowania sprzętu. Obecnie w systemach Windows 95, 98 i 2000 ich zastosowania obejmują także definiowanie ustawień oprogramowania, w tym wielu aplikacji. Użycie apletu pozwala skonfigurować aplikację bez konieczności jej uruchamiania i wybierania odpowiednich poleceń z menu. Postępowanie sprowadza się wówczas do wywołania odpowiedniego apletu z Panelu sterowania i zmiany odpowiednich ustawień. Rozwiązanie to pozwala "odchudzić" kod aplikacji poprzez usunięcie z niego elementów konfiguracyjnych, a ponadto umożliwia centralizację zarządzania ustawieniami sprzętu i oprogramowania. Dostępny w C++Builderze 5 kreator apletów znacznie upraszcza tworzenie ich kodu oraz elementów składowych (ikony, formularze i opisy). Podstawy działania apletu Aplet jest niewielkim, wyspecjalizowanym programem narzędziowym umożliwiającym sterowanie zachowaniem danego urządzenia lub programu (i stosowanym tylko w tym celu). Pozwala on zmieniać ustawienia kontrolowanej aplikacji bez konieczności jej uruchamiania. W systemie Windows aplety uruchamiane uruchamiane są z okna Panelu sterowania (zobacz rysunek 8.4). Rysunek 8.4. Panel sterowania systemu Windows 2000 Z technicznego punktu widzenia aplet jest zwykłą biblioteką dynamiczną o rozszerzeniu nazwy .cpl. W chwili uruchomienia, aplikacja zarządzająca apletami ładuje plik .cpl do pamięci i pobiera z niego niezbędne informacje, przekazując doń odpowiednie komunikaty i odbierając dane za pośrednictwem specjalnej funkcji zwrotnej CPlApplet(). Zarządzaniem apletami zajmuje się na ogół Panel sterowania (program control.exe), jednak może to robić dowolna inna aplikacja. W pojedynczym pliku .cpl może mieścić się kilka apletów "logicznych", reprezentowanych np. przez dwie różne ikony, wykorzystujących dwa okna dialogowe (formularze) i służących do konfigurowania dwóch różnych aplikacji. Przykładami mogą tu być aplety System i Dodaj/Usuń sprzęt w systemach Windows 95 i 98. Oba one zawarte są w pliku Windows/System/Sysdm.cpl, jednak wykonują różne zadania i w oknie Panelu sterowania reprezentowane są dwiema różnymi ikonami. Z tego względu, mimo fizycznego połączenia w jedną całość, można traktować je jako logicznie odrębne narzędzia. Komunikacja pomiędzy apletem a zarządzającą nim aplikacją polega na wymianie komunikatów poprzez funkcję CPlApplet(). Aplet odpowiada na komunikaty wysyłane przez aplikację, przesyłając do niej dane, które z kolei pozwalają sterować jego działaniem. Rodzaj danych zwracanych przez aplet określony jest parametrami komunikatów przekazywanych przez aplikację zarządzającą. Istotna jest również kolejność przesyłania komunikatów, co narzuca określone reguły tworzenia kodu apletu. Tabela 8.3 Kolejność i znaczenie komunikatów przesyłanych do apletu Komunikat Znaczenie CPL_INIT (wartość stałej = 1) Przesyłany jako pierwszy, bezpośrednio po załadowaniu kodu apletu do pamięci Komunikat ten służy do inicjalizacji apletu. Parametry lParam1 i lParam2 nie są używane. W przypadku pomyślnej inicjalizacji, funkcja CPlApplet() powinna zwrócić wartość TRUE, sygnalizując możliwość kontynuacji pracy. W przeciwnym razie zwracana jest wartość FALSE, nakazująca zakończenie wymiany danych i usunięcie kodu apletu z pamięci. CPL_GETCOUNT (wartość stałej = 2) Przesyłany po komunikacie CPL_INIT; zwracana wartość powinna być większa od zera W odpowiedzi na ten komunikat funkcja CPlApplet() zwraca liczbę apletów logicznych (okien dialogowych) zawartych w pliku .cpl i reprezentowanych w postaci ikon w Panelu sterowania. Wartość ta powinna być większa od zera. Parametry lParam1 i lParam2 nie są używane. CPL_INQUIRE (wartość stałej = 3) Przesyłany po komunikacie CPL_GETCOUNT, dokładnie raz dla każdego okna dialogowego (apletu logicznego) zawartego w pliku .cpl. Okna liczone są od zera; numer okna przekazywany jest w parametrze lParam1. Komunikat ten nakazuje zwrócenie informacji o poszczególnych apletach logicznych. Parametr lParam1 określa numer apletu, zaś lParam2 zawiera wskaźnik do struktury typu CPLINFO, zawierającej informacje o aplecie (ikona, nazwa, opis). CPL_NEWINQUIRE (wartość stałej = 8) Odpowiednik komunikatu CPL_INQUIRE (aplikacja zarządzająca przesyła oba komunikaty) Znaczenie tego komunikatu jest zbliżone do CPL_INQUIRE, jednak parametr lParam2 wskazuje tym razem na strukturę NEWCPLINFO, zawierającą m.in. dane zależne od stanu systemu. Dla poprawy wydajności w systemach Windows 95, NT i nowszych zaleca się używanie komunikatu CPL_INQUIRE. CPL_DBLCLK (wartość stałej = 5) Sygnalizuje dwukrotne kliknięcie ikony apletu Komunikat ten wysyłany jest po dwukrotnym kliknięciu ikony apletu (czyli jego wywołaniu). Parametr lParam1 zawiera numer wywoływanego apletu logicznego, zaś lParam2 wartość pola lData struktury CPLINFO. Wynikiem przetworzenia komunikatu powinno być wyświetlenie okna dialogowego (formularza) apletu. CPL_STOP (wartość stałej = 6) Przesyłany bezpośrednio przed zakończeniem działania aplikacji zarządzającej, dokładnie jeden raz dla każdego apletu logicznego (numer apletu przekazywany jest w parametrze lParam1) Komunikat ten sygnalizuje zakończenie działania aplikacji zarządzającej i przesyłany jest dokładnie raz do każdego apletu. W ramach jego obsługi aplet powinien zwolnić wykorzystywane zasoby i wykonać inne lokalne operacje "porządkujące". Parametr lParam1 zawiera numer apletu; lParam2 wartość pola lData struktury CPLINFO. CPL_EXIT (wartość stałej = 7) Wysyłany jednokrotnie po przesłaniu wszystkich komunikatów CPL_STOP. Bezpośrednio po jego przetworzeniu wywoływana jest funkcja FreeLibrary(), usuwająca kod pliku .cpl z pamięci. Komunikat ten przesyłany jest przez aplikację zarządzającą bezpośrednio przed wywołaniem funkcji FreeLibrary(), usuwającej z pamięci kod apletów zawartych w pliku .cpl. W ramach jego obsługi należy zwolnić zasoby (pamięć, uchtywy plików itd.) wspólne dla apletów logicznych, tj. używane globalnie dla całego pliku .cpl. Powyższa lista wygląda dość groźnie, ale nie ma się czym przerażać C++Builder automatycznie obsługuje wszystkie komunikaty sterujące działaniem apletu. Do szybkiego utworzenia apletu można wykorzystać dostępny w C++Builderze kreator (Control Panel Applet Wizard), co zademonstrujemy za chwilę. Alternatywną metodę, opartą na wywołaniach funkcji Win32 i nie wykorzystującą kreatora, opiszemy w rozdziale 24. Uwaga W naszym przykładzie nie będziemy zajmować się tworzeniem ikony apletu
zakładamy, że Czytelnik potrafi już tworzyć pliki ICO za pomocą edytora graficznego. Ikonę niezbędną dla konstruowanego w przykładzie apletu można utworzyć samodzielnie lub pobrać z gotowego pliku. A zatem zaczynamy. Uruchom IDE i wybierz polecenie Close All z menu File, zamykając w ten sposób wszystkie otwarte pliki i projekty. Następnie wybierz polecenie File|New. W wyświetlonym na ekranie oknie składnicy obiektów (New Items) kliknij dwukrotnie ikonę Control Panel Application (zobacz rysunek 8.5). Zwróć przy okazji uwagę na znajdującą się obok ikonę Control Panel Module
umożliwia ona dodanie apletu do tworzonego pliku .cpl. Rysunek 8.5. Uruchomienie kreatora apletów panelu sterowania Po uruchomieniu, kreator utworzy szkielet kodu i najważniejsze dane niezbędne do działania apletu. Wyświetlane przezeń okno przypomina nieco kreator modułów danych (Data Module Designer) i zawiera dwie karty Components (komponenty) i Data Diagram (schemat danych), co widać na rysunku 8.6. Wynikiem działania kreatora jest utworzenie klasy TAppletModule1, implementującej aplet. Jej kod można obejrzeć po naciśnięciu klawisza F12. Rysunek 8.6. Okno eksploratora modułów Kod apletu bazuje na module C++Buildera o nazwie CtlPanel, którego kod realizuje większość czynności związanych ze standardową obsługą apletu. Trzy najważniejsze elementy wchodzące w skład modułu CtlPanel to klasa wyjątku EAppletException oraz klasy TAppletApplication i TAppletModule. TAppletApplication to klasa singletonowa (tj. dopuszczająca utworzenie tylko jednego egzemplarza przyp. tłum.) służąca jako pojemnik dla obiektów (modułów) typu TAppletModule. W naszym przykładzie używamy tylko jednego modułu, jednak w razie potrzeby można dołączyć do apletu kolejne obiekty TAppletModule (co odpowiada zdefiniowaniu kolejnych apletów logicznych w ramach danego pliku .cpl). W tym celu należy wydać polecenie New z menu File i w wyświetlonym oknie składnicy obiektów wybrać ikonę Control Panel Module. Utworzony w ten sposób moduł zostanie dołączony do wybranego pliku .cpl (tj. "wstawiony" do odpowiedniego obiektu TAppletApplication). W module CtlPanel zdefiniowano globalną zmienną typu TAppletApplication, reprezentującą aplikację macierzystą dla wszystkich apletów logicznych tworzonych w ramach danego projektu. W chwili utworzenia projektu, w kodzie programu tworzony jest wskaźnik Application, reprezentujący aplikację. W przypadku apletu wskaźnikowi temu przypisywany jest adres obiektu klasy TAppletApplication, zawierającego z kolei moduł TAppletModule, reprezentujący pojedynczy aplet logiczny. Właściwości klasy TAppletModule C++Builder udostępnia szereg właściwości pozwalających kontrolować różne aspekty zachowania apletu (ikona, nazwa, opis). Okno inspektora obiektów prezentujące właściwości klasy TAppletModule pokazano na rysunku 8.7. Rysunek 8.7. Właściwości obiektu AppletModule1 w oknie inspektora obiektów A oto znaczenie poszczególnych właściwości. Właściwość AppletIcon określa ikonę reprezentującą aplet w oknie Panelu sterowania. Dla kolejnych dołączanych do projektu modułów (apletów) używa się na ogól oddzielnych ikon, zawartych w plikach zasobów typu ICO. Dwukrotne kliknięcie pola właściwości powoduje wyświetlenie okna edytora obrazków, umożliwiającego wybór ikony zapisanej w pliku ICO. Wybrana w ten sposób ikona będzie wyświetlana w oknie Panelu sterowania. Właściwość Caption definiuje podpis wyświetlany pod ikoną apletu (tj. jego nazwę). Właściwość Help określa tekst opisu apletu, wyświetlany po jego wybraniu w pasku stanu okna Panelu sterowania (tekst ten zawiera zwykle krótkie objaśnienie przeznaczenia apletu). Właściwość ResidIcon zawiera identyfikator zasobu reprezentującego ikonę apletu. Jej użycie wyklucza możliwość użycia właściwości AppletIcon (i vice versa; ograniczenie to odnosi się również do pozostałych dwóch właściwości). Właściwość ResidInfo to identyfikator zasobu reprezentującego łańcuch opisu apletu. Jej użycie wyklucza możliwość użycia właściwości Help. Właściwość ResidName jest identyfikatorem zasobu reprezentującego łańcuch nazwy apletu. Jej użycie wyklucza możliwość użycia właściwości Caption. W przypadku tworzenia plików zawierających pojedyncze aplety logiczne używa się na ogół właściwości AppletIcon, Caption i Help, ignorując tym samym właściwości ResidIcon, ResidInfo i ResidName. Zdarzenia klasy TAppletModule Zdarzenia zdefiniowane dla klasy TAppletModule pokazano na rysunku 8.8. System pomocy C++Buildera nie zawiera żadnych informacji o tworzeniu apletów panelu sterowania i zaledwie szczątkowe wiadomości o klasie TAppletApplication i module CtlPanel, chociaż pewną rekompensatę stanowi opis zdarzeń klasy TAppletModule. Można go uzyskać, naciskając klawisze Ctrl+F1 po wybraniu pola danego zdarzenia na karcie Events inspektora obiektów. Rysunek 8.8 Zdarzenia obiektu AppletModule1 w oknie inspektora obiektów Większość dostępnych tu zdarzeń nie będzie w naszym przykładzie potrzebna. Jak wiadomo, zdarzenia OnCreate i OnDestroy generowane są odpowiednio w momencie utworzenia i zlikwidowania apletu, a także w chwili otwarcia i zamknięcia okna Panelu sterowania. Należy pamiętać, że Panel sterowania komunikuje się z apletem nie tylko w chwili jego wywołania (dwukrotnego kliknięcia ikony), lecz również w czasie inicjalizacji (pobranie parametrów, jak ikona i opisy) i zamknięcia. Związane są z tym zdarzenia OnInquire, OnNewInquire, OnStop i and OnStartWParms. Nie będziemy ich tutaj używać, jednak warto zdawać sobie sprawę z możliwości ich wykorzystania do wymiany danych. W naszym przykładzie wykorzystamy natomiast zdarzenie OnActivate, generowane w chwili dwukrotnego kliknięcia ikony apletu w oknie Panelu sterowania. Obiekt Sender, przekazywany jako parametr funkcji obsługi zdarzenia, identyfikuje wywoływany moduł (aplet logiczny). Drugi parametr funkcji, Data, zawiera wskaźnik do struktury danych wykorzystywanej w obsłudze zdarzeń OnInquire i OnNewInquire (dodatkowe informacje na temat odpowiednich komunikatów i związanych z nimi struktur danych można znaleźć w rozdziale 24). Projektujemy formularz apletu Powróćmy obecnie do projektowania naszego apletu i zaprojektujmy dla niego prosty formularz, zawierający trzy przyciski. Po wybraniu modułu apletu (AppletModule1) w oknie eksploratora modułów, kliknij dwukrotnie pole właściwości AppletIcon w oknie inspektora obiektów. Na ekranie pojawi się okno edytora obrazków, umożliwiające wybranie ikony reprezentującej aplet w panelu sterowania (można tu użyć ikony zdefiniowanej uprzednio za pomocą edytora graficznego i zapisanej w pliku .ico). W polu właściwości Caption wpisz nazwę apletu (np. "Aplet ćwiczebny"), a w polu właściwości Help opis apletu (np. "To jest aplet przykładowy"). Wybierz polecenie New Form z menu File i ustaw rozmiary nowoutworzonego formularza poprzez przeciąganie krawędzi myszą lub wpisanie odpowiednich wartości do pól Width i Height inspektora obiektów. Następnie wybierz z karty Standard palety komponent TButton i wstaw go do formularza kliknięciem lewego przycisku myszy. Powtórz tę operację trzykrotnie, nadając przyciskom właściwości opisane w tabeli 8.4. Tabela 8.4. Właściwości przycisków dla przykładowego apletu Komponent Właściwość Wartość Button1 Caption Width Pokaż pasek zadań 110 Button2 Caption Width Ukryj pasek zadań 110 Button3 Caption Width Zamknij 110 Utwórz funkcję obsługi zdarzenia OnClick dla przycisku Button1, klikając go dwukrotnie i wpisując w oknie edytora następujący kod: void __fastcall TForm2::Button1Click(TObject *Sender) { // Pokaż pasek zadań. HANDLE Hide_TaskBar; Hide_TaskBar = FindWindow("Shell_traywnd", ""); SetWindowPos(Hide_TaskBar, 0, 0, 0, 0, 0, SWP_SHOWWINDOW); } W analogiczny sposób utwórz funkcję obsługi zdarzenia OnClick dla przycisku Button2. Jej kod powinien wyglądać następująco: void __fastcall TForm2::Button2Click(TObject *Sender) { // Ukryj pasek zadań. HANDLE Hide_TaskBar; Hide_TaskBar = FindWindow("Shell_traywnd", ""); SetWindowPos(Hide_TaskBar, 0, 0, 0, 0, 0, SWP_HIDEWINDOW); } Pozostało nam do obsłużenia zdarzenie OnClick dla przycisku Button3. Odpowiednia funkcja obsługi będzie miała postać void __fastcall TForm2::Button3Click(TObject *Sender) { Close(); } W następnej kolejności trzeba będzie zmodyfikować sposób tworzenia formularza. C++Builder generuje kod automatycznie tworzący formularz w chwili uruchomienia aplikacji (załadowania pliku .cpl do pamięci). Ponieważ nie odpowiada to naszym potrzebom, musimy usunąć domyślny kod i zastąpić go własnym, tworzącym formularz dopiero w chwili wywołania apletu. W tym celu otwórz plik źródłowy Project1.cpp w edytorze kodu, znajdź definicję funkcji DllEntryPoint() i usuń z niej wywołanie Application->CreateForm(__classid(TForm2), &Form2); Następnie wywołaj okno eksploratora modułów (można to zrobić za pomocą polecenia View|Forms lub naciśnięciem klawiszy Shift+F12), wybierz moduł AppletModule1 i kliknij OK. W oknie inspektora obiektów kliknij dwukrotnie w polu zdarzenia OnActivate, tworząc w ten sposób funkcję jego obsługi. Uzupełnij ją następującym kodem: void __fastcall TAppletModule1::AppletModuleActivate(TObject *Sender, int Data) { // Utwórz formularz. if(!Form2) Form2 = new TForm2(this); // Wyświetl formularz jako okno modalne i poczekaj // na jego zamknięcie. Form2->ShowModal(); // Usuń formularz. delete Form2; } Wygląd okien IDE po zakończeniu projektowania pokazano na rysunku 8.9. Rysunek 8.9. Gotowy projekt apletu To już prawie wszystko, zatem pora zapisać nasz projekt. Wybierz polecenie Save All z menu File i zapisz pliki projektu w wybranym przez siebie katalogu. W razie potrzeby można nakazać C++Builderowi automatyczne przemianowanie utworzonego pliku wynikowego i skopiowanie go do właściwego katalogu systemowego. W tym celu wybierz okno eksploratora modułów i kliknij ikonę modułu prawym przyciskiem myszy. Wyświetli to menu kontekstowe widoczne na rysunku 8.10. Zawiera ono trzy opcje: Install Control Panel Applet (zainstaluj aplet), Uninstall Control Panel Applet (odinstaluj aplet) i Launch Control Panel (uruchom Panel sterowania). Wybranie polecenia Install Control Panel Applet spowoduje skompilowanie kodu apletu i skopiowanie go do odpowiedniego katalogu. Po wyświetleniu komunikatu o sukcesie możesz uruchomić Panel sterowania poleceniem Launch Control Panel, co powinno wyświetlić okno zawierającego ikonę naszego apletu. Jej dwukrotne kliknięcię wyświetli formularz zdefiniowany przez nas wcześniej. Do zakończenia działania apletu służy przycisk Zamknij (zobacz rysunek 8.11). Rysunek 8.10 Menu kontekstowe eksploratora modułów umożliwia zainstalowanie lub odinstalowanie apletu oraz uruchomienie Panelu sterowania Rysunek 8.11 Przykładowy aplet w działaniu Aplet można także uruchomić bez pośrednictwa Panelu sterowania, wydając polecenie Uruchom z menu Start i wpisując w oknie Uruchamianie: rundll32 shell32.dll,Control_RunDLL project1.cpl @0 Wartość wpisana po znaku @ jest numerem apletu logicznego (okna dialogowego), który ma być wywołany z załadowanego pliku .cpl. Aplety numerowane są od zera, zatem @0 oznacza pierwszy aplet. W naszym przypadku jest on zarazem jedynym apletem logicznym, toteż zapis @0 można pominąć. Gdyby plik .cpl zawierał dwa aplety logiczne, do wywołania drugiego z nich należałoby użyć polecenia rundll32 shell32.dll,Control_RunDLL mycpl.cpl @1 Użyty tu mechanizm jest dość prosty program rundll32.exe odwołuje się do biblioteki dynamicznej shell32.dll, a konkretnie do zawartej w niej funkcji Control_RunDLL(), obsługującej wywołanie i wymianę danych z określonym apletem logicznym. Metodę tę można wypróbować również dla innych apletów, pamiętając przy tym, że niektóre pliki .cpl zawierają pojedyncze aplety logiczne, inne
kilka apletów (co pociąga za sobą konieczność podania parametru @n). Warto zdawać sobie sprawę z jej istnienia, chociaż jest ona tylko mniej wygodną alternatywą dla użycia Panelu sterowania [1 Warto zwrócić uwagę na brak spacji przed nazwą funkcji Control_RunDLL; w niektórych przypadkach użycie spacji powoduje problemy z wywołaniem funkcji przyp. tłum.]. Aplety panelu sterowania podsumowanie Klasyczna metoda tworzenia apletów Panelu sterowania może być dość uciążliwa, wymaga bowiem każdorazowej zmiany rozszerzenia nazwy pliku i kopiowania go do katalogu System lub System32. Również sam Panel sterowania może niekiedy sprawiać nam kłopoty, blokując plik apletu i nie pozwalając go usunąć. Narzędzia dostępne w C++Builderze, w tym kreator apletów, zwalniają programistę z większości tych obowiązków, znacząco ułatwiając tworzenie i testowanie apletów.