-
Další aplikace ukazuje jak vytvořit obsluhu pro zprávu Win32. Tento příklad
používá makra mapování zpráv definovaná v SYSDEFS.H k obsloužení
zprávy WM_GETMINMAXINFO. Začneme vývoj nové aplikace. Rozměry formuláře
změníme na 350 x 350. Na formulář umístíme čtyři komponenty Label
(vždy dvě vedle sebe) a změníme texty levých komponent na Šířka
a Výška. Texty pravých komponent změníme na 350. Dále vytvoříme
obsluhu události OnResize formaláře. Obsluha bude obsahovat příkazy:
Label2->Caption =
IntToStr(Width);
Label4->Caption =
IntToStr(Height);
Když nyní aplikaci spustíme a měníme velikost formuláře, pak zobrazené
texty nás informují o rozměrech formuláře. My ale požadujeme, aby
rozměry formuláře bylo možno měnit pouze v nějakém intervalu, např. mezi
300 a 400 body.
Zpráva WM_GETMINMAXINFO je zaslána oknu, když je měněna velikost nebo
pozice okna. Aplikace může použít tuto zprávu k přepsání minimální a maximální
implicitní velikosti a pozice okna. Parametrem zprávy je ukazatel na strukturu
MINMAXINFO,
která obsahuje implicitní hodnoty okna. Tyto implicitní hodnoty můžeme
přepsat. Struktura MINMAXINFO je deklarována takto:
typedef struct tagMINMAXINFO
{
POINT ptReserved;
POINT ptMaxSize;
POINT ptMaxPosition;
POINT ptMinTrackSize;
POINT ptMaxTrackSize;
} MINMAXINFO;
Složky struktury mají tento význam:
Složka |
Význam |
ptReserved |
Rezervováno |
ptMaxSize |
Specifikuje maximalizovanou šířku (point.x) a maximalizovanou
výšku (point.y) okna. |
ptMaxPosition |
Specifikuje pozici levého okraje maximalizovaného okna
(point.x) a pozici horního okraje maximalizovaného okna (point.y). |
ptMinTrackSize |
Specifikuje minimální šířku (point.x) a minimální výšku
(point.y) okna. |
ptMaxTrackSize |
Specifikuje maximální šířku (point.x) a maximální výšku
(point.y) okna. |
Vytvoříme tedy veřejnou virtuální metodu formuláře nazvanou RestrictSize
s následujícím obsahem:
void __fastcall TForm1::RestrictSize(TMessage&
Msg)
{
((POINT far *)Msg.LParam)[3].x = 300;
((POINT far *)Msg.LParam)[3].y = 300;
((POINT far *)Msg.LParam)[4].x = 400;
((POINT far *)Msg.LParam)[4].y = 400;
TForm::Dispatch(&Msg);
}
a budeme se snažit namapovat zprávu WM_GETMINMAXINFO na naši metodu
RestrictSize,
která zajistí, že šířka a výška formuláře se musí pohybovat mezi 300 a
400. Pokud formulář přijme zprávu WM_GETMINMAXINFO, pak naše metoda změní
informace zprávy o maximálním a minimálním rozměru okna a voláním Dispatch
je tato upravená zpráva předána současné obsluze události objektu formuláře.
Následuje výpis deklarace typu formuláře, ve kterém je uvedeno požadované
mapování:
class TForm1 : public
TForm
{
__published: // IDE-managed
Components
TLabel *Label1;
TLabel *Label3;
TLabel *Label2;
TLabel *Label4;
void __fastcall FormResize(TObject *Sender);
private: // User
declarations
public: //
User declarations
virtual __fastcall TForm1(TComponent* Owner);
void virtual __fastcall RestrictSize(TMessage& Msg);
// Toto mapování
mapuje zprávu WM_GETMINMAXINFO na funkci RestrictSize
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_GETMINMAXINFO,TMessage,RestrictSize)
// Zde lze přidat
další mapované zprávy.
END_MESSAGE_MAP(TForm)
};
Nyní, když aplikaci přeložíme a spustíme, vidíme, že velikost okna
lze měnit pouze v zadaných mezích. Obdobně je možno provést mapování dalších
zpráv Windows. K mapování jsou použita makra BEGIN_MESSAGE_MAP,
MESSAGE_HANDLER
a END_MESSAGE_MAP.
-
Další aplikace, se kterou se nyní seznámíme, je aplikace zobrazující seznam
procesů běžících na našem počítači a umožňující zrušení vybraného procesu.
Jedná se opět o hotovou aplikaci. Aplikaci si stáhněte
a vyzkoušejte jak pracuje. Nyní se podíváme jak tato aplikace je vytvořena.
Nejprve začneme jednoduššími činnostmi. Voliče ve spodní části formuláře
pouze určují barvu textu v komponentě ListBox. Obsluha události
OnClick
pro všechny čtyři voliče je tvořena příkazy:
TRadioButton *rbp
=(TRadioButton*) Sender;
ListBox1->Font->Color=rbp->Font->Color;
Obsluhu události OnTimer časovače (pohybuje šipkou na panelu
nástrojů) tvoří (i je globální proměnná deklarovaná na začátku zdrojového
souboru formuláře):
switch(i){
case 0:{
Image1->Picture->Bitmap->LoadFromResourceName(0,
(AnsiString)"BITMAP_5");
Image1->Refresh();
i=1;
return;
}
case 1:{
Image1->Picture->Bitmap->LoadFromResourceName(0,
(AnsiString)"BITMAP_2");
Image1->Refresh();
i=2;
return;
}
case 2:{
Image1->Picture->Bitmap->LoadFromResourceName(0,
(AnsiString)"BITMAP_3");
Image1->Refresh();
i=3;
return;
}
case 3:{
Image1->Picture->Bitmap->LoadFromResourceName(0,
(AnsiString)"BITMAP_4");
Image1->Refresh();
i=4;
return;
}
case 4:{
Image1->Picture->Bitmap->LoadFromResourceName(0,
(AnsiString)"BITMAP_1");
Image1->Refresh();
i=0;
return;
}
}
Obsluha volby File | Exit je tvořena příkazem
PostQuitMessage(0);
Funkce API PostQuitMessage předává Windows požadavek na ukončení.
Parametr funkce určuje ukončující kód aplikace. Funkce zasílá zprávu WM_QUIT
frontě zpráv vlákna. Když vlákno získá zprávu WM_QUIT ze své fronty zpráv,
ukončí svůj cyklus zpráv a vrací řízení Windows.
Volba Help | About zobrazí okno s informacemi o programu. Obsluha
této volby nepotřebuje žádné vysvětlení.
Obsluha stisku levého tlačítka na paletě nástrojů je tvořena příkazy
(tato obsluha je vyvolána i při volbě File | List Pids a File
| Refresh List):
long lp=0;
ListBox1->Enabled=true;
ListBox1->Clear();
EnumWindows((WNDENUMPROC)EnumProc,lp);
SpeedButton2->Enabled=true;
SpeedButton3->Enabled=true;
V této obsluze je volána funkce EnumWindows. Popis této funkce
bude uveden později. Obsluhu stisku druhého tlačítka tvoří (ListBox
je vyprázdněn a zakázána dvě tlačítka):
ListBox1->Clear();
SpeedButton3->Enabled=false;
SpeedButton1->Enabled=false;
Obsluhu stisku třetího tlačítka tvoří příkazy (je zde volána obsluha
stisku prvního tlačítka a poslední tlačítko zakázáno):
SpeedButton4Click(0);
SpeedButton1->Enabled=false;
Obsluha události OnShow formuláře tvoří příkazy (proměnná stat
je statická proměnná s počáteční hodnotou 1; je deklarována na počátku
programové jednotky formuláře):
if(stat){
stat= 0;
ListBox1->Items->Add((AnsiString)"Click
on 'pid' Tool button above");
}
Tato obsluha po prvním zobrazení formuláře zobrazí v ListBox
text Click on 'pid' Tool button above. Nyní se již věnujeme funkci
EnumWindows.
Tato funkce prochází všechna okna nejvyšší úrovně (nezabývá se podřízenými
okny) na obrazovce a předává madlo každého z nich zpětně volané funkci.
EnumWindows
pokračuje až do posledního okna nebo dokud zpětně volaná funkce vrací false.
Funkce má dva parametry. Prvním je ukazatel na zpětně volanou funkci a
druhý určuje hodnotu, která bude předána zpětně volané funkci.
V našem příkladě je funkcí EnumWindows zpětně volána následující
funkce:
bool __stdcall EnumProc(/*HWND*/void
* hWnd,/*LPARAM*/long/*lp*/)
{
unsigned
long* pPid; //LPDWORD
unsigned
long result; //DWORD
void
*hg;
//HGLOBAL
unsigned
long id;
if(hWnd==NULL)
return false;
hg =
GlobalAlloc(GMEM_SHARE,sizeof(unsigned long));
pPid
= (unsigned long *)GlobalLock(hg);
result
= GetWindowThreadProcessId(hWnd,pPid);
if(result){
char title[110];
char className[95];
char totalStr[256];
GetClassName(hWnd,className,95);
GetWindowText(hWnd,title,110);
id=*pPid;
itoa(id,totalStr,10);
strcat(totalStr,"\t");
if(title){
strcat(totalStr,title);
strcat(totalStr,"\t");
}
strcat(totalStr,className);
Form1->ListBox1->Items->Add((AnsiString)totalStr);
}
else{
GlobalUnlock(hg);
GlobalFree(hg);
return false;
}
GlobalUnlock(hg);
GlobalFree(hg);
return
true;
}
Naše funkce vytváří seznam spuštěných procesů. Pokuste se pochopit,
jak tato funkce pracuje. V našem programu zbývá ještě obsluha události
OnClick
okna seznamu, kterou tvoří příkazy:
SpeedButton1->Enabled=true;
StatusBar1->SimpleText=
"Select 'Kill
Selected PID' to terminate the process";
a obsluha stisku posledního tlačítka (zrušení vybraného procesu). Obsluhu
stisku posledního tlačítka tvoří:
AnsiString str;
char *tmp;
int i;
i= ListBox1->ItemIndex;
if( i != -1){
AnsiString
s;
tmp = new
char[100];
s=ListBox1->Items->Strings[i];
strcpy(tmp,(char*)s.c_str());
tmp=strtok(tmp,"\t");
}
int id=atoi(tmp);
delete[] tmp;
HANDLE ps = OpenProcess(1,false,id);
if(ps){
if(!TerminateProcess(ps,-9)){
ShowMessage((AnsiString)"Could not end process specified!");
}
else{
ShowMessage((AnsiString)"Process successfully terminated!");
}
}
else{
ShowMessage((AnsiString)"Could
not open process requested!");
}
Pokuste se pochopit, jak tato obsluha pracuje.