Vytvoření spořiče obrazovky - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



C/C++

Vytvoření spořiče obrazovky

8. března 2001, 00.00 | Jak vytvořit spořič obrazovky pro Windows v C++ s použitím programovacího prostředí Borland C++ Builder? Důkladný popis s ukázkami najdete v tomto článku!

Spořič obrazovky (soubory *.scr) ve Windows je klasická Win32 spustitelná aplikace s tím, že soubor spořiče má koncovku .scr a musí být umístěn v příslušné systémové složce - ve Windows 2000 je to podsložka "system32" složky, v které jsou Windows 2000 nainstalovány, obvykle tedy WINNT, ve Windows 98 a Me je to pak podsložka "system" složky instalace Windows. Pokud umístíme naši aplikaci do této složky a dáme jí příponu scr, objeví se nám název souboru aplikace v seznamu spořičů obrazovky v nastavení vlastností obrazovky (což jistě znáte).

Jakým způsobem je spořič spouštěn? Spořič může být spuštěn v různých režimech, což řídí systém Windows a podle požadovaného režimu spustí aplikaci s příslušným parametrem příkazové řádky (před parametrem by mohlo být /, - a může být malým nebo velkým písmenem):

  • c nebo bez parametru - je požadován konfigurační dialog (uživatel stiskl tlačítko "nastavení")
  • s, l - je požadováno spuštění spořiče v "normálním" režimu
  • p - požadován "náhled", dalším parametrem pak může být handle na okno "malé obrazovky" v konfiguračním dialogu, v kterém má být zobrazena "miniatura" spořiče.
  • a - parametr použitý pouze ve Windows 95 s balíkem Plus!, má se vyvolat vlastní dialog nastavení hesla, druhým parametrem je pak handle rodičovského okna tohoto dialogu

Dalším specifikem spořiče je ukončení jeho běhu po detekci aktivity uživatele, tj. stisknutím klávesnice nebo nějaké akce myši. Navíc v řadě Windows 95 - Me by měl spořič před svým ukončením otestovat správné zadání hesla, samozřejmě pokud je toto nastaveno ve vlastnostech zobrazení v ovládacích panelech. S tím souvisí (v případě nastavení hesla) zablokování ukončení aplikace pomocí systémového příkazu. To znamená zakázat např. klávesové kombinace Ctrl-TAB, Ctrl-Alt apod.

Ukážeme si na jednoduchém příkladě realizaci těchto kroků, s tím, že jedinou činností spořiče bude vypsání textu uprostřed formuláře. Vytvoření vlastních efektů již spadá pod jiné téma programování, kde se vlastní kreativitě meze nekladou. Pro vytvoření aplikace lze samozřejmě použít jakýkoli vývojový nástroj pro Windows. Já zde použiji C++ Builder s využitím VCl knihovny pro vytvoření okna spořiče. Aplikaci jsem vytvořil pomocí "New - Console Wizard", budeme tedy mít vygenerovanou pouze "klasickou" funkci WinMain. Dále jsem do projektu přidal dva formuláře, TFRun a TFConfig. Formulář FRun bude použit pro spuštění spořiče v normálním režimu a FConfig bude sloužit pro nastavení parametrů spořiče po vyvolání volby nastavení z ovládacích panelů - vlastnosti obrazovky.

Nejdříve musíme zjistit režim, v kterém je spořič aktuálně spuštěn, pomocí analýzy příkazového řádku. Mohl bych samozřejmě použít ParamStr z VCL, ale pro větší univerzálnost kódu v jiných prostředích (Visual C++ ...), jsem použil API funkce GetCommandLine. 

void GetMode()
{
 char* c = GetCommandLine();
 if (*c=='\"')
 {
  c++;
  while ( *c != 0 && *c != '\"') c++;
 }
 else
 {
  while( *c != 0 && *c != ' ')
  c++;
 }
 if ( *c!=0 )  c++;
 while ( *c==' ') c++;
 if ( *c == 0 )
 {
  m_SaverMode = smConfig;
  hwnd = NULL;
 }
 else
 {
  if ( *c=='-' || *c=='/' ) c++;
  if ( *c=='p' || *c=='P' || *c=='l' || *c=='L')
 {
 c++;
 while (*c==' ' || *c==':') c++;
 if ( ( strcmp(c, "scrprev") == 0) || (strcmp(c,"ScrPrev")==0) ||
 (strcmp(c,"SCRPREV")==0))
  hwnd = GetPreviewWindow();
 else
  hwnd = (HWND)atoi(c);
  m_SaverMode = smPreview;
 }
 else
 if ( *c=='s' || *c=='S' )
  m_SaverMode = smRun;
 else
  if ( *c=='c' || *c=='C' )
  {
  c++;
  while (*c==' ' || *c==':') c++;
 if ( *c==0 )
  hwnd = GetForegroundWindow();
 else
  hwnd = (HWND)atoi(c);
 m_SaverMode = smConfig;
 }
 else
  if (*c=='a' || *c=='A')
  {
   c++;
   while (*c==' ' || *c==':') c++;
   hwnd = (HWND)atoi(c);
   m_SaverMode = smPassword;
  }
 }
}

Když máme takto zjištěný režim spořiče, do funkce WinMain můžeme přidat přepínač

 

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 GetMode();
 switch ( m_SaverMode )
 {
  case smRun:
   FRun = new TFRun(NULL);
   FRun->ShowModal();
   delete FRun;
   break;
  case smPreview:
   ShowMessage("Náhled v okně dialogu Vlastnosti obrazovky\nJeho realizaci si můžeme ukázat přístě");
   break;
  case smConfig:
   FConfig = new TFConfig(NULL);
   if ( FConfig->ShowModal() == mrOk )
    ShowMessage("Zde zapíšeme nové nastavení - nejlépe do registru");
   else
    ShowMessage("Nastavení beze změn - stornováno");
   delete FConfig;
   break;
  case smPassword:
   ShowMessage("Nastavení hesla - pouze pro Win95 s Plus!");
   break;
 }
 return 0;
}
V případě, že spořič má být spuštěn v "normálním" režimu, je vytvořen a modálně zobrazen formulář FRun. Ve vlastnostech (property) formuláře je potřeba nastavit (v ObjectInspectoru nebo až v kódu nejlépe v konstruktoru) BorderIcons všechny položky false, dále BorderStyle na bsNone. Tím dosáhneme toho, že formulář celou svoji oblast barvou nastavenou v property Color. Tuto oblast, tedy velikost formuláře musíme nastavit na celou plochu obrazovky. To uděláme nejlépe v konstruktoru, kde zjistíme pomocí API funkce GetSystemMetrics rozměry (v pixelech samozřejmě) obrazovky a na tyto hodnoty nastavíme Width a Height formuláře:

Left = 0;
Top = 0;
Width = GetSystemMetrics(SM_CXSCREEN);
Height = GetSystemMetrics(SM_CYSCREEN);

Dále musíme nastavit formulář tak, aby se zobrazoval "na vrcholu", tj. přes všechna existující okna. Ve vhodném místě použijeme funkci

  SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);

Nyní musíme zajistit správné ukončování běhu spořiče po detekci činnosti uživatele. Musíme proto nějakým způsobem zachytávat příslušné zprávy Windows a podle toho ukončit běh spořiče. V případě běhu pod Windows řady 95 - Me musíme dále otestovat, zda v případě, že je nastavena ochrana spořiče heslem, bylo před ukončením spořiče zadáno správné heslo.

Zachytávání zpráv v C++ Builderu můžeme řešit různými způsoby. Bylo by možné vytvořit mapu zpráv pomocí maker BEGIN_MESSAGE_MAP a END_MESSAGE_MAP s příslušnými handlery. V našem případě je jednodušší vytvořit vlastní proceduru okna, na kterou přesměrujeme proceduru okna našeho formuláře. Já jsem použil funkci CreateWindowHandle, v které po zavolání této metody předka (TForm) máme možnost doplnit vlastní kód okamžitě po vytvoření platného handle okna formuláře. Obecně pokud chceme některý kód provést "co nejdříve" po vytvoření handle okna formuláře, nejvhodnější je právě tato funkce. Proto jsem také právě zde umístil výše zmíněnou funkci SetWindowPos, dále zjištění výchozí polohy kurzoru myši (pro pozdější detekci pohybu myši), skrytí kurzoru (funkce ShowCursor(false)) a zmíněné přesměrování procedury okna. Kód této funkce a nové procedury okna formuláře může pak vypadat třeba takto:

 

void __fastcall TFRun::CreateWindowHandle(const Controls::TCreateParams &Params)
{
 TForm::CreateWindowHandle(Params);
 SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
 WindowProc = FormWndProc;
 GetCursorPos(&m_oldPos);
 ShowCursor(false);
 UINT ui;
 SystemParametersInfo(SPI_SCREENSAVERRUNNING, 1, &ui, 0);
}

void __fastcall TFRun::FormWndProc(TMessage& Msg)
{
 POINTS pts;
 switch ( Msg.Msg )
 {
  case WM_SYSCOMMAND:
   if ( Msg.WParam == SC_CLOSE )
   {
    TryClose();
    break;
   }
   if ( Msg.WParam == SC_SCREENSAVE )
   {
    Msg.Result = 0;
    return;
   }
   break;
  case WM_MOUSEMOVE:
   pts = MAKEPOINTS(Msg.LParam);
   if ( abs(pts.x - m_oldPos.x) > _MouseThreshold )
    TryClose();
   if ( abs(pts.y - m_oldPos.y) > _MouseThreshold )
    TryClose();
   break;
  case WM_RBUTTONDOWN:
  case WM_MBUTTONDOWN:
  case WM_LBUTTONDOWN:
  case WM_XBUTTONDOWN:
  case WM_KEYDOWN:
  case WM_MOUSEWHEEL:
   TryClose();
   break;
 }
 WndProc(Msg);
}
V posledním řádku funkce CreateWindowHandle je volána funkce 

SystemParametersInfo(SPI_SCREENSAVERRUNNING, 1, &ui, 0); 

Druhý parametr (1) zakazuje systémové klávesové kombinace jako Alt-TAB a podobně. Tím znemožníme obejít (v řadě Win95) ochranu heslem přepnutím do jiné aplikace.

Podívejme se na kód funkce, která realizuje ochranu heslem ve Windows řady 95:

bool __fastcall TFRun::VerifyPassword()
{
 OSVERSIONINFO osv;
 ZeroMemory(&osv, sizeof(OSVERSIONINFO));
 osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
 if ( !GetVersionEx(&osv) ) return true;
 if ( osv.dwPlatformId == VER_PLATFORM_WIN32_NT ) return true;
 HINSTANCE hPsw = LoadLibrary("password.cpl");
 if ( hPsw == NULL ) return true;
 typedef BOOL (WINAPI *VERIFYSCREENSAVEPWD)(HWND hwnd);
 VERIFYSCREENSAVEPWD VerifyScreenSavePwd;
 VerifyScreenSavePwd = (VERIFYSCREENSAVEPWD)
 GetProcAddress(hPsw,"VerifyScreenSavePwd");
 if ( VerifyScreenSavePwd == NULL )
 {
  FreeLibrary(hPsw);
  return true;
 }
 bool bRes = VerifyScreenSavePwd(Handle);
 FreeLibrary(hPsw);
 return bRes;
}
 Nejdříve zjištujeme verzi operačního systému (pomocí API funkce GetVersionEx). V případě, že detekujeme řadu NT, vrátíme true, neboť ochrana heslem je v řadě NT realizována přímo systémem, který po spuštění spořiče zamkne počítač. V opačném případě použijeme funkci VerifyScreenSavePwd ze systémové dynamické knihovny passeord.cpl. Tato funkce sama nejprve zjistí, zda je nastavena ochrana heslem a pokud tomu tak je vyvolá známý dialog zadání hesla. Jinak vrátí true. Samozřejmě musíme vrátit true také v případě jakékoli jiné chyby při načítání této funkce z knihovny, jinak bychom mohli zablokovat systém.

Do kódu formuláře FRun musíme ještě přidat, nejlépe v události OnClose (tj. při zavření formuláře a tedy následném ukončení programu, kód, který opět zobrazí kurzor a povolí systémové klávesy, které jsem při spuštění zakázali:

void __fastcall TFRun::FormClose(TObject *Sender, TCloseAction &Action)
{
 ShowCursor(true);
 UINT ui;
 SystemParametersInfo(SPI_SCREENSAVERRUNNING, 0, &ui, 0);
}
Samozřejmě že bychom mohli do této události (OnClose) také přemístit kód funkce VerifyPassword a pomocí parametru Action pak zakázat nebo povolit zavření formuláře. Podobných variant umístění kódu by se samozřejmě našlo více. Zde však jde o to ukázat princip tvorby spořiče obrazovky a konkrétní realizace je již věcí "rukopisu" každého programátora.

Když se podíváte do kódu přiloženého ukázkového příkladu, v modulu SaverMain.cpp najdete ještě funkci, pro zjištění handle okna pro náhled spořiče. Jedná se malou "obrazovku" v dialogu nastavení vlastností spořiče obrazovky, v které většina spořičů (i když to v zásadě není nutné), zobrazuje svůj náhled. V tomto příkladě jsem se nezabýval konkrétní realizací tohoto náhledu. Šlo by v podstatě o to, spustit okno aplikace jako "dětské okno" tohoto okna, jehož handle získáme.

Poslední věcí, o které se zde zmíním, je použití mutexu ve funkci WinMain, kterým zjišťuji, zda již běží jedna instance tohoto spořiče, abych zabránil vícenásobnému spuštění, ke kterému by pravděpodobně docházelo v pravidelných intervalech daných nastavenou časovou prodlevou spořiče. K tomu ještě poznamenám, že ve Windows 98 a vyšších a Windows 2000  a vyšších lze zjistit, zda běží nějaký spořič pomocí již zmíněné funkce SystemParametersInfo s použitím parametru SPI_GETSCREENSAVERRUNNING (podrobnosti jistě najdete v dokumentaci).

Zde si můžete stáhnout ukázkový projekt

Screen saver

Tématické zařazení:

 » Rubriky  » C/C++  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: