Sdílet prostřednictvím


O procedurách oken

Každé okno je členem konkrétní třídy okna. Třída okna určuje výchozí proceduru okna, kterou jednotlivá okna používá ke zpracování svých zpráv. Všechna okna patřící do stejné třídy používají stejnou výchozí proceduru okna. Systém například definuje proceduru okna pro třídu kombinovaného pole (COMBOBOX); všechna kombinovaná pole pak používají tuto proceduru okna.

Aplikace obvykle registruje alespoň jednu novou třídu okna a její přidruženou proceduru okna. Po registraci třídy může aplikace vytvořit mnoho oken této třídy, z nichž všechny používají stejný postup okna. Protože to znamená, že více zdrojů může současně volat stejnou část kódu, musíte být opatrní při úpravě společných prostředků v proceduře okna. Další informace naleznete v tématu Třídy oken.

Procedury oken pro dialogová okna (nazývané postupy dialogového okna) mají podobnou strukturu a fungují jako běžné procedury okna. Všechny body odkazující na postupy oken v této části platí také pro postupy dialogového okna. Další informace naleznete v tématu Dialogová okna.

Tato část popisuje následující témata.

Struktura procedury okna

Procedura okna je funkce, která má čtyři parametry a vrací podepsanou hodnotu. Parametry se skládají z popisovače okna, identifikátoru zprávy UINT a dva parametry zprávy deklarované pomocí WPARAM a LPARAM datových typů. Další informace naleznete v tématu WindowProc.

Parametry zprávy často obsahují informace v jejich slovech s nízkým pořadím i ve slovech s vysokým pořadím. Aplikace může použít několik maker k extrakci informací z parametrů zprávy. Makro LOWORD například extrahuje slovo s nízkým pořadím (bity 0 až 15) z parametru zprávy. Mezi další makra patří HIWORD, LOBYTEa HIBYTE.

Interpretace návratové hodnoty závisí na konkrétní zprávě. Projděte si popis každé zprávy a určete odpovídající návratovou hodnotu.

Protože je možné volat proceduru okna rekurzivně, je důležité minimalizovat počet místních proměnných, které používá. Při zpracování jednotlivých zpráv by aplikace měla volat funkce mimo proceduru okna, aby se zabránilo nadměrnému použití místních proměnných, což může způsobit přetečení zásobníkové paměti při hluboké úrovni rekurze.

Výchozí procedura okna

Výchozí funkce procedury okna, DefWindowProc definuje určité základní chování sdílené všemi okny. Výchozí procedura okna poskytuje minimální funkce pro okno. Procedura okna definovaná aplikací by měla předat všechny zprávy, které nezpracová, do funkce DefWindowProc pro výchozí zpracování.

Podtřídy procedury okna

Když aplikace vytvoří okno, systém přidělí blok paměti pro ukládání informací specifických pro okno, včetně adresy okna procedury, která zpracovává zprávy pro okno. Když systém potřebuje předat zprávu do okna, vyhledá specifické informace o okně pro adresu procedury okna a předá zprávu této proceduře.

Podtřídění je technika, která umožňuje aplikaci zachytit a zpracovat zprávy odeslané nebo poslané do určitého okna předtím, než je okno má možnost zpracovat. Pokud je okno podtříděno, může aplikace rozšířit, upravit nebo monitorovat jeho chování. Aplikace může podtřídět okno, které patří do globální třídy systému, například ovládací prvek pro úpravy nebo seznam. Aplikace může například podtřídit editační prvek, aby zabránila přijímání určitých znaků. Nemůžete však podtřídit okno nebo třídu, které patří do jiné aplikace. Všechny podtřídy musí být provedeny ve stejném procesu.

Aplikace podtřídí okno tím, že nahradí adresu původní procedury okna adresou nové procedury okna, která se nazývá procedura podtřídy. Následně procedura podtřídy obdrží všechny zprávy odeslané nebo poslané do okna.

Procedura podtřídy může při přijetí zprávy provést tři akce: může předat zprávu do původní procedury okna, upravit zprávu a předat ji do původní procedury okna, nebo zprávu zpracovat a nepředá ji do původní procedury okna. Pokud procedura podtřídy zpracuje zprávu, může ji zpracovat před, po, nebo před i po jejím odeslání do původní procedury okna.

Systém poskytuje dva typy podtřídy: instance a globální. V podtřídě instancenahradí aplikace adresu procedury okna jedné instance okna. Aplikace musí k podtřídě existujícího okna použít podtřídu instance. V globální podtřídynahradí aplikace adresu procedury okna v WNDCLASSEX strukturu třídy okna. Všechna následná okna vytvořená pomocí třídy mají adresu podtřídové procedury, ale stávající okna třídy nejsou ovlivněna.

Podtřídění instancí

Aplikace podtříduje okno pomocí funkce SetWindowLongPtr. Aplikace předá příznak GWL_WNDPROC, popisovač okna pro podtřídu a adresu postupu podtřídy do SetWindowLongPtr. Procedura podtřídy se může nacházet buď ve spustitelném souboru aplikace, nebo v knihovně DLL.

Při předání příznaku GWL_WNDPROC příkaz SetWindowLongPtr vrátí adresu původní procedury okna. Aplikace musí tuto adresu uložit a použít ji v následných voláních funkce CallWindowProc, aby předávala zachycené zprávy do původní procedury okna. Aplikace musí mít také původní adresu procedury okna, aby mohla odebrat podtřídu z okna. Chcete-li odebrat podtřídu, aplikace znovu volá SetWindowLongPtr, přičemž předá adresu původní procedury okna spolu s příznakem GWL_WNDPROC a popisovačem k oknu.

Systém vlastní globální třídy systému a aspekty ovládacích prvků se můžou změnit z jedné verze systému na další. Pokud aplikace musí zdědit okno, které patří do globální třídy systému, může být potřeba, aby vývojář aplikaci aktualizoval při vydání nové verze systému.

Vzhledem k tomu, že podtřída instance nastane po vytvoření okna, není možné do okna přidat žádné další bajty. Aplikace, které podtřídí okno, by měly použít seznam vlastností okna k uložení všech dat potřebných pro instanci podtříděného okna. Další informace naleznete v tématu Vlastnosti okna.

Když aplikace používá podtřídu s oknem, které je samo podtřídou, musí odstranit tyto podtřídy v pořadí obráceném k tomu, v jakém byly vytvořeny. Pokud pořadí odebrání není obrácené, může dojít k neopravitelné systémové chybě.

Globální podtřídy

Aby byla třída okna globálně podtříděna, aplikace musí mít popisovač okna této třídy. Aplikace také potřebuje ovládací prvek k odebrání podtřídy. Pro získání popisovače aplikace obvykle vytvoří skryté okno třídy, které má být podtříděno. Po získání popisovače aplikace volá funkci SetClassLongPtr s uvedením popisovače, příznaku GCL_WNDPROC a adresy procedury podtřídy. SetClassLongPtr vrátí adresu původní procedury okna třídy.

Původní adresa procedury okna se používá u globálního podtřídění stejně jako u podtřídění instance. Procedura podtřídy předává zprávy původní proceduře okna, když zavolá CallWindowProc. Aplikace odebere podtřídu z druhu okna voláním SetClassLongPtr znovu, při specifikaci adresy původní procedury okna, příznaku GCL_WNDPROC a popisovače okna podtřídy. Aplikace, která globálně podtříduje třídu ovládacího prvku, musí při ukončení aplikace odebrat podtřídu; v opačném případě může dojít k neopravitelné systémové chybě.

Globální podtřídy mají stejná omezení jako podtřídy instancí a navíc některá další omezení. Aplikace by neměla používat nadbytečné bajty pro třídu nebo instanci okna, aniž by věděla, jak je původní procedura okna používá. Pokud aplikace musí přidružit data k oknem, měla by používat vlastnosti okna.

Supertřídění procedury okna

Superklasování je technika, která umožňuje aplikaci vytvořit novou třídu okna se základními funkcionalitami aktuální třídy a vylepšeními poskytovanými aplikací. Supertřída je založena na existující třídě okna, která se nazývá základní třídy. Základní třída je často systémovou globální třídou okna, jako je například ovládací prvek pro úpravy, ale může to být libovolná třída okna.

Supertřída má vlastní proceduru okna, která se nazývá procedura supertřídy. Procedura nadtřídy může provést tři akce při přijetí zprávy: Může předat zprávu do původní procedury okna, upravit zprávu a předat ji původnímu postupu okna nebo zprávu zpracovat a nepředá ji do původní procedury okna. Pokud nadtřídní procedura zpracuje zprávu, může to udělat před, po, nebo jak před, tak i po jejím předání původní oknové proceduře.

Na rozdíl od procedury podtřídy může procedura supertřídy zpracovávat zprávy vytváření oken (WM_NCCREATE, WM_CREATEatd.), ale musí je také předat původní procedurě okna základní třídy, aby procedura okna základní třídy mohl provést její inicializační proceduru.

Pokud chce aplikace vytvořit nadtřídu z třídy okna, nejprve volá funkci GetClassInfoEx k načtení informací o základní třídě. GetClassInfoEx vyplní strukturu WNDCLASSEX hodnotami ze struktury WNDCLASSEX základní třídy. Dále aplikace zkopíruje svůj vlastní popisovač instance do člena hInstance struktury WNDCLASSEX a zkopíruje název supertřídy do člena lpszClassName. Pokud základní třída obsahuje nabídku, aplikace musí zajistit novou nabídku se stejnými identifikátory nabídky a zkopírovat název nabídky do členu lpszMenuName. Pokud procedura supertřídy zpracuje zprávu WM_COMMAND a nepředá ji do okna procedury základní třídy, nabídka nemusí mít odpovídající identifikátory. GetClassInfoEx nevrací lpszMenuName, lpszClassNamenebo hInstance člen WNDCLASSEX struktury.

Aplikace musí také nastavit člen lpfnWndProc ve struktuře WNDCLASSEX. Funkce GetClassInfoEx vyplní tohoto člena adresou původní procedury okna třídy. Aplikace musí tuto adresu uložit pro předání zpráv do původní procedury okna a poté zkopírovat adresu procedury supertřídy do členu lpfnWndProc. Aplikace může v případě potřeby upravit všechny ostatní členy struktury WNDCLASSEX. Jakmile aplikační program vyplní strukturu WNDCLASSEX, zaregistruje nadtřídu tak, že předá adresu této struktury funkci RegisterClassEx. Supertřídu pak můžete použít k vytvoření oken.

Vzhledem k tomu, že přetěžování registruje novou třídu okna, může aplikace přidat jak dodatečné bajty třídy, tak i dodatečné bajty okna. Nadřazená třída nesmí používat původní nadbytečné bajty pro základní třídu nebo okno ze stejných důvodů jako podtřída instance nebo globální podtřída. Pokud aplikace přidá další bajty pro své použití do třídy nebo instance okna, musí odkazovat na nadbytečné bajty vzhledem k počtu nadbytečných bajtů používaných původní základní třídou. Vzhledem k tomu, že počet bajtů používaných základní třídou se může lišit od jedné verze základní třídy k dalšímu, počáteční posun pro vlastní nadbytečné bajty supertřídy se také může lišit od jedné verze základní třídy k další.