Wygaszacz ekranu w WinAPI

adamkow

     1 Co to jest wygaszacz ekranu?
     2 Jak utworzyć wygaszacz ekranu.
     3 Budowa wygaszacza.
     4 Jaki może być wygaszacz i co on będzie robił?
     5 Wygaszacz ekrany i dźwięk.
     6 Na koniec.
     7 Literatura.

Co to jest wygaszacz ekranu?

Wygaszacz ekranu jest specjalnym programem, który uruchamiany jest przez system po stwierdzeniu dłuższego czasu bezczynności użytkownika. Jego podstawowym zadaniem jest zabezpieczanie monitora, a właściwie jego warstwy luminoforu, przed zniszczeniem poprzez długotrwale wyświetlanie tego samego obrazu. Dodatkowo może on pełnić funkcje prostego zabezpieczenia przed wykorzystaniem komputera przez osoby niepowołane.

Z punktu widzenia systemu Windows wygaszacz jest programem, można się o tym przekonać zmieniając rozszerzenie dowolnego programu na scr i odwrotnie. Nie jest to jednak zwykły program. Aby pracował on poprawnie jako wygaszacz ekranu musi spełniać kilka warunków.

Jak utworzyć wygaszacz ekranu.

Najprostszą metodą stworzenia własnego wygaszacza ekranu jest wykorzystanie znajdującej się w systemie Windows biblioteki scrnsave.dll. Biblioteka ta zawiera w sobie kilka funkcji ułatwiających tworzenie wygaszaczy ekranu. Przede wszystkim jest to funkcja main wraz z kodem inicjalizującym użycie wygaszacza. Dba ona o wywoływanie w odpowiednim momencie okna dialogowego, do ustawiania parametrów wygaszacza, lub wywołanie samego wyświetlacza. Dodatkowo sama zamyka wygaszacz po reakcji użytkownika, a przy jego wywoływaniu czyści tło.

Aplikacja powinna zawierać zdefiniowane trzy funkcje: ScreenSaverConfigureDialog, ScreenSaverProc i RegisterDialogClasses. Dodatkowo w zasobach powinno być zdefiniowane okno o dialogowe o identyfikatorze 2003. To okno konfiguracyjne jest wyświetlane wtedy, gdy użytkownik wybierze przycisk Ustawienia z zakładki Wygaszacz ekranu okna Właściwości ekranu.

Aby utworzyć taki wygaszacz potrzeby jest dowolny kompilator języka C, umożliwiający tworzenie aplikacji dla Windows.

Przykładem mogą być darmowe GCC-MINGWIN i LCC-WIN32.
(http://www.cs.virginia.edu/~lcc-win32/index.html)

A wiec zaczynamy od tego ze tworzymy nowy projekt, ustawiamy jego typ na aplikacje Windows (zazwyczaj nazywa się to Windows App), i pouczamy linkiera aby z naszym projektem linkował biblioteki: scrnsave.lib i comctl32.lib. Oczywiście dodajemy ,o ile jest to konieczne a zazwyczaj jest, zasoby w których zdefiniowane jest okno dialogowe o nazwie 2003

Budowa wygaszacza.

Kod bardzo prostego wygaszacza znajduje się poniżej.

// WygaszaczMig
#include &ltwindows.h&gt
#include &ltcommctrl.h&gt
#include &ltscrnsave.h&gt
#define IlePunktowMax 500
#define NazwaKlucza "SOFTWARE\\\\ProgramyAdama\\\\WygaszaczMiganie"
long IlePunkt; // Liczba punktów wyświetlanych na raz
long predkosc, iSzerokosc, iWysokosc;
UINT uTimer;
void Odczytaj();
void Zapisz();
void RysujWygaszacz(HDC kont);

// Procedura dialogu konfiguracyjnego
BOOL WINAPI ScreenSaverConfigureDialog(HWND dialog,
UINT komunikat, WPARAM wParam, LPARAM lParam)
{
	switch(komunikat)
	{
		case WM_INITDIALOG:
			// Odczytaj ustawienia z rejestru
			Odczytaj();
			// Ustaw zakres paska przesuwnego na 0-20
			SendDlgItemMessage(dialog, 110, TBM_SETRANGE, TRUE, MAKELONG(1,20));
			// Ustaw pozycję suwaka zależnie od prędkości
			SendDlgItemMessage(dialog, 110, TBM_SETPOS, (WPARAM)TRUE, predkosc);
			// Ustaw zakres paska przesuwnego na 5-500
			SendDlgItemMessage(dialog, 111, TBM_SETRANGE, TRUE, MAKELONG(5,500));
			// Ustaw pozycję suwaka zależnie od prędkości
			SendDlgItemMessage(dialog, 111, TBM_SETPOS, (WPARAM)TRUE, IlePunkt);
			return TRUE;
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
				case IDOK:
					predkosc = SendDlgItemMessage(dialog, 110, TBM_GETPOS, 0, 0);
					IlePunkt = SendDlgItemMessage(dialog, 111, TBM_GETPOS, 0, 0);
					// Zapisz ustawienia do rejestru
					Zapisz();
					EndDialog(dialog, TRUE);
				case IDCANCEL:
					EndDialog(dialog, FALSE);
					return TRUE;
				case 112:
					MessageBox(dialog,"Ten program jest prostym wygaszaczem ekranu. \\n Może być 
						w dowolny sposób kopiowany i rozpowszechniany. \\n Autor: Adam Kowalczyk. 
						akowalc1@elka.pw.edu.pl", "O Wygaszaczu...", 0);
					return FALSE;
			}
	}
	return FALSE;
}
 
 
BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
	InitCommonControls();
	return TRUE;
}
 
 
LONG WINAPI ScreenSaverProc(HWND okno, UINT komunikat, WPARAM wParam, LPARAM lParam)
{
	HDC kont;
	switch(komunikat)
	{
		case WM_CREATE:
			Odczytaj();
			/* Włącz zegar generujący komunikaty WM_TIMER co okres czasu = prędkość*1/20 [sek] */
			iSzerokosc = GetSystemMetrics(SM_CXSCREEN);
			iWysokosc = GetSystemMetrics(SM_CYSCREEN);
			uTimer = SetTimer(okno, 1, predkosc*50, NULL);
			break;
		case WM_TIMER:
			kont = GetDC(okno);
			RysujWygaszacz(kont);
			ReleaseDC(okno, kont);
			break;
		case WM_DESTROY:
			if (uTimer) KillTimer(okno, uTimer);
			break;
	}
	return DefScreenSaverProc(okno, komunikat, wParam, lParam);
}
 
 
// Funkcja odczytuje ustawienia wygaszacza z rejestru
void Odczytaj()
{
	HKEY klucz;
	DWORD rozm = 4;
	// Otwórz odpowiedni klucz rejestru
	if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NazwaKlucza, 0,
		KEY_QUERY_VALUE, &klucz) == ERROR_SUCCESS)
	{
		// Odczytaj prędkość
		RegQueryValueEx(klucz, "Prędkość", 0, NULL, (BYTE *)&predkosc, &rozm);
		if(predkosc<0 || predkosc>20) predkosc = 2;
		// Odczytaj liczbe punktow
		RegQueryValueEx(klucz, "LiczbaPunktow", 0, NULL, (LONG *)&IlePunkt, &rozm);
		if (IlePunkt<5) IlePunkt=5;
		if (IlePunkt>IlePunktowMax) IlePunkt=IlePunktowMax;
		// Zamknij otwarty klucz rejestru
		RegCloseKey(klucz);
	}
	else
	{
		// ustawienia domyślne, ważne przy pierwszym uruchomieniu programu
		IlePunkt=20;
		predkosc = 5;
	}
}
 
 
// Funkcja zapisuje parametry wygaszacza do rejestru
void Zapisz()
{
	HKEY klucz;
	DWORD akcja;
	// Otwórz odpowiedni klucz rejestru
	RegCreateKeyEx(HKEY_LOCAL_MACHINE, NazwaKlucza , 0, NULL,
		REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &klucz, &akcja);
	// Zapisz informacje o prędkości
	RegSetValueEx(klucz, "Prędkość", 0, REG_DWORD, (CONST BYTE *)&predkosc, 4);
	// Zapisz informacje o liczbe punktow
	RegSetValueEx(klucz, "LiczbaPunktow", 0, REG_DWORD, (CONST BYTE *)&IlePunkt, 4);
	// Zamknij otwarty klucz rejestru
	RegCloseKey(klucz);
}
 
 
// Funkcja rysuje zawartość ekranu
void RysujWygaszacz(HDC kont)
{
	long i;
	long x,y;
	COLORREF k;
	// wstawianie losowe punktów
	for(i=0; i<IlePunkt; i++)
	{
		// losujemy współrzędne punktu gdzieś na ekranu
		x=rand() % iSzerokosc;
		y=rand() % iWysokosc;
		// losuje kolor
		k = RGB(rand()%256, rand()%256, rand()%256 );
		// wstawiam gwiazdki w danym położeniu
		//*
		// ***
		// *
		SetPixelV(kont,x,y,k);
		SetPixelV(kont,x+1,y,k); SetPixelV(kont,x,y+1,k);
		SetPixelV(kont,x-1,y,k); SetPixelV(kont,x,y-1,k);
	}
}

Plik z zasobami do niego:

#include <windows.h> 

ID_APP ICON Wygaszacz.ico
2003 DIALOG 168, 47, 241, 174
EXSTYLE WS_EX_DLGMODALFRAME
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Ustawienia wygaszacza."
FONT 8, "MS Sans Serif" 

{
	CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 16, 144, 50, 14
	CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 160, 144, 50, 14
	CONTROL "Prędkość zmian", 100, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 15, 58, 210, 46
	CONTROL "", 110, "msctls_trackbar32", 0x0 | WS_TABSTOP, 25, 80, 188, 20
	CONTROL "Szybko", 101, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 20, 70, 30, 10
	CONTROL "Wolno", 102, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 191, 70, 20, 10
	CONTROL "Liczba punktów.", 104, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 15, 7, 211, 46
	CONTROL "", 111, "msctls_trackbar32", 0x0 | WS_TABSTOP, 25, 25, 189, 20
	CONTROL "5", 2006, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 20, 15, 30, 10
	CONTROL "500", 2007, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 195, 15, 20, 10
	CONTROL "Autor", 112, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 88, 144, 50, 14, 0
} 

Wygaszacz ten w wersji skompilowanej wraz ze źródłami jest zawarty w spakowanym pliku WygMig.zip.

Działanie przedstawionego powyżej wygaszacza polega na losowym wyświetlaniu na ekranie punktów. Szybkość z jaka się one pojawiają i ich liczbę można regulować w okienku z ustawieniami.

Jego rdzeń stanowią wspomniane wcześniej funkcje ScreenSaverConfigureDialog, ScreenSaverProc i RegisterDialogClasses. Nazwy tych funkcji i ich nagłówki są niezbędne i musza wyglądać dokładnie tak jak to zostało pokazane w przykładzie. Inaczej nie zostaną one zlokalizowane.

Funkcja ScreenSaverConfigureDialog jest odpowiedzialna za obsługę okna dialogowego służącego do konfiguracji wygaszacza. Natomiast funkcja ScreenSaverProc jest właściwą funkcją obsługująca sam wygaszacz podczas pracy. Jej podstawowym zadanie jest obsługą komunikatów przychodzących od systemu. Najważniejsze z nich to: WM_CREATE, WM_TIMER, WM_DESTROY.

Komunikat WM_CREATE jest pierwszym komunikatem jaki otrzymuje program po uruchomieniu.

Jego obsługa powinna zawierać:

  • wczytanie danych konfiguracyjnych z rejestru, (funkcja Odczyt),
  • inicjacje zmiennych i struktur danych programu,
  • inicjacje timera.

Komunikat WM_TIMER przychodzi regularnie do aplikacji po uruchomieniu timera. W jego obsłudze powinna być zawarta cala obsługa animacji związanych z wygaszaczem, a więc przede wszystkim rysowanie zawartości ekranu. Zadanie to wykonuje funkcja RysujWygaszacz.

Komunikat WM_DESTROY jest sygnałem do zakończenia pracy programu. W trakcie jego wykonywania program usuwa zainicjowany wcześniej timer.

Komunikat WM_ERASEBKGND jest wywoływany gdy system zamierza wyczyścić tło przy uruchamianiu wygaszacza. Jest on wywoływany przed wyczyszczeniem tła, w czasie jego obsługi systemowa funkcja obsługi zdarzeń czyści zawartość okna. Dlatego jego przechwytywanie umożliwia operowanie na oryginalnej zawartości ekranu.

Zapis ustawień wygaszacza może być przeprowadzany bezpośrednio w rejestrze systemowym. W tym celu program musi stworzyć własny klucz. Można umieścić go w gałęzi: HKEY_LOCAL_MACHINESOFTWARENazwaFirmyNazwaProgramu.. lub :HKEY_CURRENT_USERsoftwareNazwaFirmyNazwaProgramu.

Pierwsza gałąź służy do zapisu informacji konfiguracyjnych specyficznych dla całego systemu, natomiast druga jest przeznaczona na informacje związane z konkretnym użytkownikiem.

Np. ..JacekiWacekWygaszaczLatajaceSledzie

Przy pierwszym uruchomieniu wygaszacz powinien potrafić się zorientować że jest uruchamiany pierwszy raz i stworzyć odpowiedni klucz.

Trzecią funkcja jaka należy zdefiniować tworząc własny wygaszacz jest: RegisterDialogClasses. Jej zadaniem jest rejestracja przez program własnych obiektów sterujących lub klas dodatkowych okien.

Jaki może być wygaszacz i co on będzie robił?

To już zależy tylko i wyłącznie od wyobrazili jego twórcy czyli twojej. Ja ze swej strony mogę ci tylko troszkę podpowiedzieć

Wygaszacze ekraru podzielił bym na kategorie:

  • punktowo - obiektowe,
  • bitmapowe,
  • obrazowe.

Wygaszacz punktowo-obiektowy to taki w którym obraz na ekranie powstaje z szeregu punktów (lub innych prostych obiektów). Program sam je generuje na podstawie odpowiedniego algorytmu i sam je w odpowiednim momencie usuwa. W ten sposób można zrealizować mnóstwo pomysłów które opierają się na układach prostych elementów (punkty, linie, koła). Tego typu jest zaprezentowany powyżej wygaszacz.

Wygaszacz bitmapowy jest podobny do wspomnianego wyżej z tym ze nie generuje sam całego obrazu ale korzysta z gotowego zestawy bitmap zapisanych w programie. Może on pokazywać przesuwający się obiekt po ekranie, lub ten sam obiekt w rożnych widokach ( każdy z widoków to oddzielna bitmapa).

Wygaszacz obrazowy to taki który nie generuje sam obrazu ale zajmuje się przekształcaniem obrazu widocznego na monitorze w momencie jego wywołania. Może go np. ściemniać, rozmywać lub deformować i inny sposób. Możliwe jest wiele różnych przekształceń.

Oczywiście wszystkie powyższe pomysły można jak najbardziej łączyć ze sobą. Nie ma tu żadnych reguł. Czym ciekawsze i nieoczekiwane będzie zachowanie programu tym lepiej.

Przykładem jest znany mi wygaszacz przedstawiający chodzącego sobie po ekranie stworka, który co jakiś czas wygryza kawałek ekranu. Jest on połączeniem dwóch ostatnich technik. Zachowywana jest dotychczasowa zawartość ekrany na której stworek jest wyświetlany jako animacja.

Wygaszacz ekrany i dźwięk.

W wygaszaczach dźwięk odgrywa pomocnicza role i często nie występuje. Tym niemniej można zastosować proste efekty dźwiękowe. Czasami mogą być one ważnym elementem wygaszacza. Przypomniał mi się tu wygaszacz przedstawiający śpiąca sylwetkę Dino (taki zwierzaczek z kreskówki Flinstonowie) a z głośnika dobiega bardzo realistyczne chrapanie.

Jedna uwaga. UŻYTKOWNIK ZAWSZE MUSI MIEĆ MOŻLIWOŚĆ WYŁĄCZENIA DŹWIĘKU W WYGASZACZU.

Na koniec.

Dziękuję tym wszystkim którzy dotarli do końca tego tekstu i życzę owocnej pracy.
Będę wdzięczny za wszelkie uwagi krytyczne na jego temat. Prosił bym również aby osoby korzystające z niego i dołączonych do niego pochwaliły się swoimi projektami.

Literatura.

Zawarte w niemniejszym dokumencie informacje pochodzą w znacznej części z własnych doświadczeń, część z nich zaś pochodzi z książki:
Janusz Karmiński "Praktyczny kurs programowania w Windows 95.". Helion.

Adam Kowalczyk. akowalc1@elka.pw.edu.pl
12.06.2001

http://home.elka.pw.edu.pl/~akowalc1

0 komentarzy