Kde mohu zobrazit popis funkcí rozhraní Windows API. Co je Windows API. Popis funkčních prototypů v MSDN

FindWindow
GetWindow
GetWindowText
SetWindowText
IsWindow
MoveWindow
IsWindowVisible
EnableWindow
IsWindowEnabled
WindowFromPoint
Ukaž okno
CloseWindow
SetWindowPos
GetClassLong
SetClassLong
GetWindowLong
SetWindowLong
GetDesktopWindow
GetParent

Funkce FindWindow

function FindWindow(className,WindowName: PChar) : HWND;
Funkce vrací popisovač okna, který splňuje požadavek (0, pokud takové okno není nalezeno).

Jméno třídy Název třídy používané k vyhledávání mezi VŠEMI okny systému. Název okna Název okna

Jeden z parametrů může být roven nule, pak se vyhledávání provede pomocí jiného parametru.
Příklad:

Funkce GetWindow

function GetWindow(Wnd: HWND; Param) : HWND
Funkce vrací deskriptor okna, který splňuje požadavek.

Wnd Klika k nějakému úvodnímu oknu Param Nabývá jedné z následujících konstantních hodnot: gw_Owner Popisovač okna předchůdce je vrácen (0, pokud žádný předek neexistuje). gwHWNDFirst Vrátí popisovač do prvního okna (vzhledem k Wnd). gw_HWNDDalší Vrátí handle do dalšího okna (okna se opakují bez opakování, tj. pokud jste nezměnili parametr Wnd funkce, handles se znovu nevracejí) gw_Child Vrátí popisovač do prvního podřízeného okna.

Příklad:

Funkce GetWindowText

function GetWindowText(hWnd: HWND; lpString: PChar; nMaxCount: Integer): Integer;
Funkce vrací text okna. U formuláře to bude název, u tlačítka štítek na tlačítku.

hWnd Deskriptor okna, jehož text chcete získat. lpString Proměnná, do které bude umístěn výsledek nMaxCount

Maximální délka textu, pokud je text delší, je oříznut.


Příklad:

Funkce IsWindow

function IsWindow(hWnd: HWND): BOOL; Vrátí True, pokud okno s daným popisovačem existuje, False jinak.

Hwnd Deskriptor požadovaného okna

Funkce MoveWindow

MoveWindow(hWnd: HWND; X, Y, nWidth, nHeight: Integer; bRepaint: BOOL): BOOL; Přesune okno na novou pozici.

hWnd Klika k přesouvanému oknu. X, Y, nŠířka, nVýška Podle toho: nové souřadnice X,Y; nová šířka, výška. bPřebarvit Booleovská hodnota udávající, zda bude okno překresleno.

Funkce IsWindowVisible

function IsWindowVisible(hWnd: HWND): BOOL;
Vrátí True, pokud je dané okno viditelné.

hWnd Popisovač okna.

Povolit funkci okna

function EnableWindow(hWnd: HWND; bEnable: BOOL): BOOL;
Nastavuje dostupnost okna (okno je nedostupné, pokud nereaguje na události myši, klávesnice atd.). Analog vlastnosti komponent v Delphi. EnableWindow vrátí True, pokud bylo vše úspěšné, a False jinak.

hWnd Popisovač okna. bPovolit Booleovská hodnota udávající, zda je okno dostupné.


Příklad:

Funkce IsWindowEnabled

function IsWindowEnabled(hWnd: HWND): BOOL;
Vrací pro dané okno: True, pokud je okno dostupné, a False v opačném případě.

hWnd Popisovač okna.

Funkce WindowFromPoint

WindowFromPoint(Bod: TPoint): HWND;
Vrátí úchyt do okna umístěného v daném bodě na obrazovce.

Směřovat Typ souřadnic bodu obrazovky TPoint(definice typu viz níže)

Funkce

typ TPoint = Záznam x: Longint; y:Longint; konec;

Funkce ShowWindow

function ShowWindow(hWnd: HWND; nCmdShow: Integer): BOOL; Zobrazí nebo skryje okno.

hWnd Deskriptor požadovaného okna nCmdShow Konstanta, která určuje, co se s oknem udělá: SW_HIDE SW_SHOWNORMAL SW_NORMAL SW_SHOWMINIMIZED SW_SHOWMAXIMIZED SW_MAXIMIZE SW_SHOWNOACTIVATE SW_SHOW SW_MINIMIZE SW_SHOWMINNOACTIVE SW_SHOWNA SW_RESTORE SW_SHOWDEFAULT SW_MAX


Příklad:

Funkce CloseWindow

function CloseWindow(hWnd: HWND): BOOL; stdcall;
Zavře okno.

hWnd Klika k oknu, které se má zavřít.

SetWindowPos

function SetWindowPos(hWnd: HWND; hWndInsertAfter: HWND; X, Y, cx, cy: Integer; uFlags: UINT): BOOL; stdcall;
Nastaví okno do nové polohy

hWnd prodejce oken hWndInsertAfter Deskriptor okna, před kterým je v seznamu Z-Řád vloží se okno hWnd, nebo jednu z následujících konstant: HWND_BOTTOM Umístěte okno na konec seznamu Z-Order HWND_TOP Umístěte okno na začátek seznamu Z-Order X, Y, cx, cy

V souladu s tím nové obzory. , vert. pozice oken ( X, Y), stejně jako nová šířka
a výška ( cx, cy)

uFlags Jeden nebo více (oddělené NEBO) následující konstanty: SWP_NOSIZE Po přesunutí neměňte velikost okna ( cx, cy jsou ignorovány) SWP_NOZORDER Neměňte polohu okna v seznamu Z-Order SWP_SHOWWINDOW Po přesunutí zviditelnit okno SWP_HIDEWINDOW Skrýt okno po přesunutí SWP_NOACTIVATE Po přesunutí nezaměřujte pozornost na okno SWP_NOMOVE Nehýbejte oknem (ignorujte X, Y)

Funkce GetClassLong

function GetClassLong(hWnd: HWND; nIndex: Integer): Integer;
Tato funkce vrací 32bitové celé číslo převzaté z určitého pole v záznamu TWndClassEx zadané okno.

hWnd Okenní klika nIndex Konstanta definující, co bude vráceno. Musí to být jedna z následujících možností: GCL_MENUNAME Vrátí ukazatel na řetězec obsahující název nabídky třídy definované v souboru prostředků přidruženém k nějakému programu. GCL_HBRBACKGROUND Vrátí úchyt (HBRUSH) štětci na pozadí přidruženému ke třídě GCL_HCURSOR Vrátí popisovač (HCURSOR) kurzoru přidruženému ke třídě GCL_HICON Vrátí úchyt (HICON) na ikonu přidruženou ke třídě GCL_HMODULE Vrátí popisovač procesu (HMODULE), který zaregistroval třídu. GCL_CBWNDEXTRA Vrátí velikost paměti (v bajtech) přidělenou pro ukládání dalších dat pro TOTO OKNO. Popis použití této paměti naleznete v popisu funkce GCL_CBCLSEXTRA Vrátí velikost paměti (v bajtech) přidělenou pro uložení další GIVEN CLASS GCL_WNDPROC Vrátí adresu procedury okna přidružené ke třídě. GCL_STYLE Vrátí styl třídy (přítomnost konkrétního stylu je kontrolována bitovou operací A pomocí konstant jako cs_XXX) GCL_HICONSM

Poznámka: v případě, že funkce vrací ukazatel, je nutné přetypování typu (Integer ->

Funkce SetClassLong

function SetClassLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Integer; Funkce párování. Nastaví požadované pole na příslušnou hodnotu.
Funkce vrátí starou hodnotu pole, takže ji lze později opravit, nebo vrátí nulu, pokud se něco pokazilo.

hWnd Okenní klika nIndex Jedna z konstant GCL_XXX z funkce. V závislosti na hodnotě tohoto pole se požadované pole změní.

Poznámka Ukazatel psát Celé číslo.

Funkce GetWindowLong

function GetWindowLong(hWnd: HWND; nIndex: Integer): Longint; Vrátí informace o okně jako 32bitové celé číslo.

hWnd Okenní klika nIndex Konstanta definující, co bude vráceno. Musí to být jedna z následujících možností:
GWL_WNDPROC Vrátí adresu procedury okna přidružené k tomuto oknu. Výsledná adresa (po vhodném přetypování) může být použita ve funkci CallWindowProc. Tato hodnota se obvykle používá, pokud chtějí nahradit existující proceduru okna svou vlastní, a aby nepřišli o funkčnost okna, obvykle používají CallWindowProc. GWL_HINSTANCE Vrátí popisovač aplikace zadaný při vytvoření okna funkcí CreateWindowEx. GWL_HWNDPARENT Vrátí popisovač (HWND) nadřazeného okna GWL_STYLE Vrátí styl okna. Konkrétní hodnoty stylu se nacházejí pomocí bitové operace A a konstanty WS_XXX GWL_EXSTYLE Vrátí styl rozšířeného okna. Konkrétní hodnoty stylu se nacházejí pomocí bitové operace A a konstanty WS_EX_XXX GWL_USERDATA Vrátí 32bitové celé číslo přidružené k oknu (toto je poslední parametr ve volání CreateWindow nebo CreateWindowEx) GWL_ID Vrátí ID okna (nemá nic společného s popisovačem okna!) zadané parametrem hMenu pro podřízená okna při volání CreateWindow nebo CreateWindowEx

Poznámka: v případě, že funkce vrací ukazatel, je nutné přetypování typu (Integer -> Pointer). Můžete to udělat takto:

Funkce SetWindowLong

function SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: Longint): Longint;
Spárováno s funkcí. Změní atributy konkrétního okna.
Funkce vrátí starou hodnotu vlastnosti, pokud je volání úspěšné, nebo jinak null.

hWnd Okenní klika nIndex Konstanta, která určuje, která vlastnost bude změněna. Musí to být jedna z konstant GWL_XXX z popisu funkce dwNewLong Nová hodnota vlastnosti definované konstantou nIndex

Poznámka: při nastavování polí ukazatele je vyžadováno přetypování Ukazatel psát Celé číslo.

Funkce GetDesktopWindow

funkce GetDesktopWindow: HWND
Funkce vrátí popisovač do okna Plocha. Žádné parametry.

GetParent

function GetParent(hWnd: HWND): HWND;
Vrátí úchyt nadřazeného okna pro okno hWnd.

hWnd Okenní klika

C WinAPI je základní sada programovacích rozhraní (API) společnosti Microsoft dostupná v operačních systémech.Starší verze se nazývala Win32 API.

Úvod

C WinAPI je rozhraní pro programování aplikací, které se používá k vytváření aplikací pro Windows. Chcete-li začít, musí si začínající uživatel stáhnout sadu Windows SDK, dříve známou jako Platform SDK.

Obsahuje hlavičkové soubory, knihovny, ukázky, dokumentaci a nástroje, které se používají k vývoji aplikací. API pro programovací jazyky C a C++. Toto je nejpřímější způsob vytváření aplikací na operačním systému společnosti.

C WinAPI lze rozdělit do několika oblastí:

    základní služby;

    bezpečnost;

  • uživatelské rozhraní;

    multimédia;

    shell Windows;

    síťové služby.

Základní služby poskytují přístup k základním zdrojům. Patří mezi ně funkce C WinAPI, systémy souborů, zařízení, procesy, vlákna, registr a zpracování chyb. Oblast zabezpečení poskytuje rozhraní, objekty a další programovací prvky pro ověřování, autorizaci, kryptografii a další úkoly související se zabezpečením. Grafický subsystém poskytuje funkce pro výstup grafického obsahu na monitory, tiskárny a další výstupní zařízení. Uživatelské rozhraní poskytuje funkce pro vytváření oken a ovládacích prvků.

Multimediální komponenta poskytuje nástroje pro práci s videem, zvukem a vstupními zařízeními. Funkce rozhraní shellu umožňují aplikacím přístup k funkcím poskytovaným shellem operačního systému. Síťové služby poskytují přístup k síťovým možnostem systému Windows.

Komponenty

Při vytváření WinAPI C byste měli zvážit základní možnosti poskytované Windows API, které lze organizovat do sedmi kategorií. Podívejme se na každou z nich podrobněji.

Základní služby poskytují přístup k základním systémovým prostředkům dostupným v systému Windows. Příklady: souborový systém, periferní zařízení, procesy, přístup k registru a systém správy výjimek. Tyto funkce jsou uloženy v souborech kernel.exe, krnl286.exe nebo krnl386.exe pro 16bitové systémy a kernel32.dll a advapi32.dll pro 32bitové systémy.

GUI poskytuje přístup ke zdrojům pro zobrazení na monitorech, tiskárnách a dalších periferních zařízeních. Uloženo v gdi.exe na 16bitových systémech a gdi32.dll na 32bitových systémech.

Uživatelské rozhraní je zodpovědné za prohlížení a ovládání základních prvků, jako jsou tlačítka a posuvníky, získávání informací o klávesnici a myši a souvisejících funkcí. Tyto funkce jsou uloženy v user.exe na 16bitových systémech a user32.dll comctl32.dll na 32bitových systémech. Počínaje XP byly ovládací prvky seskupeny do comctl32.dll.

Obecné dialogy – zobrazují informace pro otevírání a ukládání souborů, výběr barev a fontů. Nachází se v souboru comdlg.dll na 16bitových systémech a comdlg32.dll na 32bitových systémech.

Windows Shell je součást rozhraní WinAPI, která umožňuje aplikacím přístup k funkcím poskytovaným prostředím operačního systému.

Síťové služby poskytují přístup k různým síťovým možnostem operačního systému. Mezi jeho podkomponenty patří NetBIOS, Winsock, RPC. Ve starších verzích - NetDDE.

Verze

Win16, Win32 a Win32s jsou standardní sady komponent, které umožňují aplikačnímu softwaru využívat funkce různých operačních systémů rodiny Windows.

Win32, nástupce Win16, byl představen v roce 1993 v produktech rodiny 32bitových Windows, jako jsou Windows NT, 2000, 95. Toto programovací rozhraní je implementováno třemi softwarovými knihovnami: Kernel32.dll, User32.dll a GDI32.dll2. Stejné funkce Win32 jsou dostupné ve všech produktech Windows a v závislosti na produktu může použití určitých funkcí vést k chybě služby.

Možnosti Win32 zahrnují komunikaci mezi programy, správu procesů, počítačových sítí, souborů, tiskáren, serverů a komunikačních portů.

Specifikace

C WinAPI je abstraktní specifikace programovacího rozhraní pro operační systém Windows. Skládá se z deklarací funkcí, sjednocení, struktur, datových typů, maker, konstant a dalších programovacích prvků. WinAPI je popsáno masterem a nachází se v hlavičkách Windows C. Oficiální implementaci funkcí WinAPI lze nalézt v dynamických knihovnách (DLL): například kernel32.dll, user32.dll, gdi32.dll nebo shell32.dll v systémový adresář. Existují implementace rozhraní Windows API od třetích stran: především projekt Wine a projekt ReactOS.

Windows API je dynamický objekt. Počet funkcí neustále roste s každou novou verzí OS a novými service packy. Mezi serverovou a desktopovou verzí operačního systému jsou také důležité rozdíly. Některé funkce nejsou oficiálně zdokumentovány.

Pelles C

Pelles C je bezplatný program a nejlepší kompilátor jazyka C a integrované vývojové prostředí (IDE) pro programovací jazyk C. Podporuje 32bitové Windows (x86) a 64bitové Windows (x64). Implementuje standardy C99 i C11. Pelles C má vestavěný editor zdrojů, bitmapový, ikonový a kurzorový editor a hex editor výpisů. Je vyvinut švédským vývojářem Pelle Orinius. Překladač je pojmenován po svém autorovi. Dodává se s SDK, takže programátor může okamžitě začít vytvářet aplikace bez další instalace.

Chyba cílové architektury

Chcete-li vytvářet programy Windows API, musíte povolit rozšíření společnosti Microsoft. Ve výchozím nastavení jsou zakázány, což způsobí, že kompilátor zobrazí následující chybovou zprávu, která je příkladem nefunkčního rozhraní C WinAPI: fatální chyba #1014: #error: "Žádná cílová architektura" Chcete-li povolit rozšíření společnosti Microsoft, přejděte do nastavení projektu a vyberte kartu „Kompilátor“. Na této kartě zaškrtněte políčko „Povolit rozšíření společnosti Microsoft“.

MSDN

Je centrálním portálem pro vývoj Windows. Toto je obrovská sbírka materiálů souvisejících s vývojem aplikací pomocí nástrojů společnosti Microsoft. Toto je nejobsáhlejší databáze spolu s dokumentací pro vývoj desktopových aplikací a seznamem Windows API.

Použití knihoven DLL ve WinAPI C

Common Controls Library poskytuje přístup k pokročilým funkcím operačního systému, jako jsou stavové řádky, ukazatele průběhu, panely nástrojů a karty. Tyto příkazy se nacházejí v commctrl.dll na 16bitových systémech a comctl32.dll a jsou seskupeny s uživatelským rozhraním.

DLL je formát souboru dynamicky propojované knihovny používaný k ukládání více kódů a procedur pro programy Windows. Soubory DLL byly vytvořeny tak, aby jejich informace mohlo využívat více programů současně, což pomáhá šetřit paměť. Umožňuje uživateli upravovat kódování několika aplikací najednou bez jejich změny. DLL lze převést na statické pomocí MSIL Disassembler nebo DLL pro Lib 3.00.

WinAPI jako aplikační programovací rozhraní pro Windows nabízí mnoho výkonných funkcí, které umožňují vytvářet vlastní programy, od jednoduchého zpracování souborů až po vytváření grafického rozhraní pro programování nízkoúrovňových ovladačů zařízení.

Než začnete programovat ve WinAPI, musíte nastavit své kódové prostředí ve Windows. Jelikož se nejedná o linuxovou distribuci, nemá vestavěný kompilátor pro tvorbu aplikací. Zvažte následující možnosti kompilace kódu:


Pro Windows je k dispozici vývojová sada, která poskytuje dokumentaci a nástroje umožňující vývojářům vytvářet software pomocí rozhraní API a souvisejících technologií.

Zkratka pro API, Application Programming Interface (API) je prostě nějaká hotová sada funkcí, které mohou vývojáři aplikací používat. Obecně je tento koncept ekvivalentní tomu, co bylo dříve častěji nazýváno knihovnou podprogramů. Nejčastěji však API odkazuje na nějakou speciální kategorii takových knihoven.

Při vývoji téměř jakékoli poměrně složité aplikace (MyApplication) pro koncového uživatele se vytváří sada specifických interních funkcí, které se používají k implementaci tohoto konkrétního programu, který se nazývá MyApplication API. Často se ukazuje, že tyto funkce lze efektivně využít i k vytváření dalších aplikací, včetně jiných programátorů. V tomto případě se autoři na základě strategie propagace svého produktu musí rozhodnout otázku - otevírají přístup k této sadě pro externí uživatele nebo ne? Pokud je odpověď kladná, v popisu softwarového balíčku se jako jeho výhoda objeví věta, že „balíček obsahuje otevřenou sadu funkcí API“.

API tedy nejčastěji označuje sadu funkcí, které jsou součástí jedné aplikace, ale jsou dostupné i pro použití v jiných programech. Například Excel má kromě svého koncového uživatelského rozhraní sadu funkcí Excel API, které lze použít zejména při vytváření aplikací pomocí VB.

V souladu s tím je Windows API souborem funkcí, které jsou součástí samotného operačního systému a zároveň jsou přístupné jakékoli jiné aplikaci. A v tomto ohledu je analogie se sadou přerušení systému BIOS/DOS, což je vlastně DOS API, celkem oprávněná.

Rozdíl je v tom, že skladba funkcí Windows API je na jedné straně mnohem širší ve srovnání s DOSem, na druhé straně neobsahuje mnoho nástrojů pro přímou správu počítačových zdrojů, které měli programátoři k dispozici v předchozím OS. Kromě toho jsou volání Windows API prováděna pomocí běžných procedurálních volání a volání funkcí DOSu jsou prováděna prostřednictvím speciální instrukce procesoru nazvané Interrupt.

Win16 API a Win32 API

Jak víte, změna z Windows 3.x na Windows 95 znamenala přechod z 16bitové architektury operačního systému na 32bitovou. Zároveň bylo 16bitové Windows API (Win16 API) nahrazeno novou 32bitovou verzí (Win32 API). V tomto případě je jen potřeba mít na paměti, že až na výjimky je sada Win32 API stejná pro rodiny Windows 9x a Windows NT.

Při seznamování s Win API zjistíte, že mnoho vestavěných funkcí není nic jiného než volání odpovídajících systémových procedur, ale pouze implementovaných ve formě syntaxe daného jazyka. Vezmeme-li toto v úvahu, nutnost použití API je určena následujícími možnostmi:

Funkce API, které jsou zcela implementovány jako vestavěné funkce. Někdy je však v tomto případě užitečné přejít na použití API, protože to může někdy výrazně zlepšit výkon (zejména kvůli absenci zbytečných transformací předávaných parametrů).

Vestavěné funkce implementují pouze speciální případ odpovídající funkce API. Toto je poměrně častá možnost.

Obrovské množství funkcí API nemá v současné verzi kompilátorů vůbec obdoby. Například nemůžete odstranit adresář pomocí VB - k tomu musíte použít funkci DeleteDirectory.

Je třeba také zdůraznit, že některé funkce API (jejich podíl na Win API je velmi malý) nelze z programů volat kvůli řadě jazykových omezení, například nemožnosti pracovat s adresami paměti. V některých případech však mohou pomoci netriviální programovací techniky (zejména v případě stejných adres).

Win APIADynamic Link Library (DLL)

Sada Win API je implementována ve formě dynamických knihoven DLL.

DLL v tomto případě rozumíme tradiční verzi binárních dynamických knihoven, které poskytují aplikacím přímý přístup k potřebným procedurám - podprogramům nebo funkcím (podobně jako to, co se děje při volání procedur v rámci projektu). Takové knihovny lze vytvořit pomocí různých nástrojů - VC++, Delphi, Fortran, Assembler.

Soubory dynamických knihoven mají obvykle příponu .DLL, ale není to nutné. Pro Win16 se často používala přípona .EXE, ovladače pro externí zařízení jsou označeny pomocí .DRV.

Je obtížné určit přesný počet funkcí Windows API a souborů, které je obsahují (ale všechny jsou umístěny v systémovém adresáři). V tomto ohledu je lepší vyzdvihnout složení knihoven, které tvoří jádro operačního systému, a hlavních knihoven s klíčovými doplňkovými funkcemi.

Knihovny Win32 API jádra operačního systému Windows 95/98:

KERNEL32.DLL: nízkoúrovňové funkce pro správu paměti, úloh a dalších systémových zdrojů;

USER32.DLL: Zde jsou umístěny hlavně ovládací funkce uživatelského rozhraní;

GDI32.DLL: Knihovna Graphics Device Interface - různé funkce pro výstup na externí zařízení;

COMDLG32.DLL: Funkce související s používáním obecných dialogových oken.

Hlavní knihovny s rozšiřujícími funkcemi:

COMCTL32.DLL: Sada dalších ovládacích prvků systému Windows, včetně seznamu stromů a formátovaného textu;

MAPI32.DLL: funkce pro práci s e-mailem;

NETAPI32.DLL: ovládací prvky a síťové funkce;

ODBC32.DLL: funkce této knihovny jsou potřebné pro práci s různými databázemi přes protokol ODBC;

WINMM.DLL: Operace přístupu k systémovému médiu.

Tento článek je určen těm, kteří jako já začínají s programováním v C++ a kteří se náhodou nebo touhou rozhodli naučit WinAPI.
Chci vás hned varovat:
Netvrdím, že jsem guru C++ nebo WinAPI.
Teprve se učím a chci zde uvést několik příkladů a tipů, které mi usnadní osvojení funkcí a mechanismů WinAPI.

V tomto článku předpokládám, že jste se již dostatečně seznámili s C++, abyste mohli vytvářet třídy a přetěžovat pro ně různé operátory, a že jste do třídy již „schovali“ některé své mechanismy.

Vytváření a používání konzole

K ladění aplikace Win32 nebo jen k tomu, abych viděl, jak se to všechno děje uvnitř, vždy používám konzolu.
Protože vytváříte aplikaci GUI a ne konzolovou aplikaci, konzola není připojena. Abychom to mohli nazvat, tento kód byl nalezen v hlubinách internetu

If (AllocConsole())
{



std::ios::sync_with_stdio();
}
Pro pohodlí vám doporučuji zabalit to do funkce. Například:
void CreateConsole()
{
if (AllocConsole())
{
int hCrt = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), 4);
*stdout = *(::_fdopen(hCrt, "w"));
::setvbuf(stdout, NULL, _IONBF, 0);
*stderr = *(::_fdopen(hCrt, "w"));
::setvbuf(stderr, NULL, _IONBF, 0);
std::ios::sync_with_stdio();
}

Volaná konzole funguje pouze ve výstupním režimu a funguje stejně jako v konzolových aplikacích. Výstupní informace jako obvykle - cout/wcout.
Aby tento kód fungoval, musíte do projektu zahrnout následující soubory:
#zahrnout
#zahrnout #zahrnout
a zahrňte jmenný prostor std do globálního jmenného prostoru:
pomocí jmenného prostoru std;
Samozřejmě, pokud to nechcete udělat, pak přidejte std:: ke všem entitám, které jsou v něm.

Dědičnost objektů pro výstup a aritmus. operace

Při vytváření a studiu samotných „oken“ jsem vždy potřeboval vypsat nějakou hodnotu do konzole.
Například:
Velikost klientské oblasti okna získáte pomocí funkce GetClientRect, kde se adresa objektu struktury RECT předá jako parametr pro naplnění tohoto objektu daty. Pokud potřebujete znát velikost přijímané klientské oblasti, můžete ji jednoduše zobrazit v již připojené konzoli

Cout<

Ale dělat to pokaždé (zvláště pokud musíte často něco takového dělat) je velmi nepohodlné.
Zde nám na pomoc přichází dědictví.
Vytvořte třídu, která otevřeně dědí ze struktury RECT a přetíží výstupní operátor<< так, как вам угодно.
Například:

Třída newrect:public RECT
{
veřejnost:
přítel ostream & operátor<<(ostream &strm,newrect &rect)
{
strm<<"Prtint RECT object:\n";
strm<return strm;
}
};

Nyní vytiskněte objekt pomocí cout/wcout:

Cout<

A vše se vám zobrazí v pohodlné podobě, jak požadujete.
Totéž můžete udělat s libovolnými operátory, které potřebujete.
Pokud například potřebujete porovnat nebo přiřadit struktury (například RECT nebo POINT), přetížte operátory ==() a operátor=().
Pokud chcete implementovat operátor menší než< что бы быстро сравнивать размеры окна и т.д. перегрузите operator<().
Předpokládám, že to můžete udělat s téměř jakoukoli strukturou a nejdůležitější je, že všechny funkce, které pracují s běžným objektem struktury RECT, budou fungovat stejně dobře s jeho dědicem.
A také doporučuji celou tuto krásu vložit do samostatného přiloženého souboru a v případě potřeby použít.

Tvoje třída

Nevím jak ostatní, ale jelikož jsem úplně zelený, rozhodl jsem se vytvořit nový projekt pro každou funkci, kterou jsem studoval, nebo pro každou kapitolu/podkapitolu knihy, aby bylo vše na policích a já mohl jsem se kdykoli vrátit a osvěžit si paměť na potřebné body.
Vzhledem k tomu, že ve WinAPI je i pro vytvoření toho nejjednoduššího okna potřeba vyplnit strukturu třídy, zaregistrovat ji a napsat triviální proceduru okna, po třetím nebo čtvrtém projektu jsem si vzpomněl, že jsem stále psal v C++.
Nakonec jsem vše schoval do jednoduché učebny. Popisovač okna, jeho název, název třídy, adresa procedury okna, třída okna (WNDCLASS) jsou všechny skryté v soukromé části třídy.
K jejich získání stačí popsat jednoduché metody Get, například:
HWND GetHWND()
LPCTSTR GetClsName() atd.
Vyplnění a registrace třídy okna, vytvoření samotného okna a jeho zobrazení se provádí v konstruktoru.
Pro pohodlí můžete přetížit konstruktor a skrýt plnění a registraci třídy okna v samostatné funkci soukromé třídy a volat ji v každém z konstruktorů. Výhodou přetěžování je, že někdy potřebuji vytvořit velmi jednoduché okno a zavolám konstruktor se dvěma parametry – názvem okna a nápovědou aplikace.
Jindy potřebuji vytvořit okno se speciální velikostí, ne s výchozí procedurou okna a s nějakým jiným specifickým stylem - zavolám konstruktor s doprovodnými parametry.
Tuto třídu mám definovanou v samostatném souboru začlenění, který se nachází ve složce include v IDE.
Šablona pro tuto třídu:
třídy BaseWindow
{
WNDCLASSEX_wcex;
TCHAR_className;
TCHAR_windowName;
HWND_hwnd;
bool _WindowCreation();
veřejnost:
BaseWindow(název okna LPCTSTR,hInstance HINSTANCE,styl DWORD,UINT x,UINT y,výška UINT,šířka UINT);
BaseWIndow(LPCTSTR windowName,HINSTANCE hInstance);
const HWND GetHWND()const(návrat HWND;)
LPCTSTR GetWndName()const(return _windowName;)
};

Jakmile si takovou třídu důkladně promyslíte a napíšete, usnadníte si život a strávíte více času učením a zdokonalováním svých dovedností, než psaním pokaždé to samé. Navíc si myslím, že je velmi užitečné si takovou třídu vytvořit sami a podle potřeby ji doplnit.

P.S.

Vše popsané platí pro:
Platforma - Windows 7 32 bit
IDE - Visual Studio 2010
Možná tyto tipy u některých vyvolají smích a ironii, ale stejně jsme všichni byli kdysi v něčem začátečníci/cvičenci/junioři.
Berte prosím tento příspěvek s pochopením. Konstruktivní kritika je samozřejmě vítána.

Zřeknutí se odpovědnosti

Zdálo by se, že WinAPI se stává minulostí. Meziplatformních frameworků je už dlouhou dobu obrovské množství, Windows nejsou jen na desktopech a Microsoft sám do svého obchodu nevítá aplikace, které toto monstrum využívají. Kromě toho existují tisíce článků o tom, jak vytvořit okna pomocí WinAPI, a to nejen zde, ale na celém internetu, na úrovni od předškoláků a výše. Celý tento proces se již ani nerozkládá na atomy, ale na subatomární částice. Co by mohlo být jednodušší a přehlednější? A tady jsem...

Ale ne všechno je tak jednoduché, jak se zdá.

Proč teď WinAPI?

V jednu chvíli, když jsem studoval vnitřnosti jedné z velmi dobrých her, jsem si pomyslel: Zdá se, že je to dobrá emulze, ale debugger nemá tak jednoduchou věc, jako je procházení tlačítek klávesnice, která je k dispozici v jakémkoli normálním debuggeru.

o čem to mluvím? A tady je kousek kódu:

Případ WM_KEYDOWN: MessageBox(hwndDlg,"Zemři!","Jsem mrtvý!",MB_YESNO|MB_ICONINFORMATION);
Autoři tedy chtěli přidat podporu klávesnice, ale tvrdá realita hlubin architektury dialogových oken ve Windows takovou iniciativu tvrdě potlačila. Viděl někdy někdo, kdo používal emulátor a debugger v něm, tuto zprávu?
Co je za problém?

Odpověď zní: To nemůžete!

A vraťme se k původní otázce o WinAPI: mnoho populárních a ne tak populárních projektů jej v současné době nadále používá, protože Mnoho věcí nelze udělat lépe než pomocí čistého API (zde můžete donekonečna dávat analogie, jako je porovnávání jazyků na vysoké úrovni a jazyka symbolických instrukcí, ale o tom to teď není). A kdo ví proč? Prostě to použijí a je to.

O problému

Dialogová okna usnadňují práci s GUI a zároveň nás připravují o možnost udělat něco sami. Například zprávy WM_KEYDOWN/WM_KEYUP přicházející do procedury okna jsou „sežrány“ v hloubce DefDlgProc, přičemž přebírají takové věci, jako jsou: navigace pomocí karet, zpracování kláves Esc, Enter atd. Dialogy navíc není nutné vytvářet ručně: je koneckonců jednodušší načrtnout tlačítka, seznamy v editoru zdrojů, zavolat CreateDialog/DialogBox ve WinMain a máte hotovo.

Obejít takové drobné potíže je snadné. Existují minimálně dva zcela legální způsoby:

  1. Vytvořte si vlastní třídu přes RegisterClassEx a uchopte WM_KEYDOWN v proceduře zpracování třídy a přesměrujte ji na samotnou proceduru zpracování dialogu. Ano ano! Můžete vytvářet dialogy s vlastní třídou a vestavěný editor VS vám dokonce umožňuje zadat název třídy pro dialog. Ale kdo o tom ví a používá to?
    Nevýhoda je zřejmá: Potřebujete zaregistrovat ještě jednu třídu, mít ještě 1 proceduru CALLBACK, jejíž podstatou bude pouze odvysílání pár zpráv. Navíc se to nedozvíme Kde vysílejte je a budete se muset ohradit o berlích.
  2. Použijte vestavěný urychlovací mechanismus. A nemusíme ani měnit kód procedury dialogu! No, možná přidejte jeden řádek pro přepínač/případ, ale o tom níže.

Tutoriály?

Nebojím se to říct Všechno návody na vytváření oken přes WinAPI začínají tak jednoduchým kódem a označují jej jako „smyčku zpracování zpráv“ (vynechám detaily přípravy třídy okna a dalších vazeb):

Zatímco (GetMessage(&msg, nullptr, 0, 0)) ( TranslateMessage(&msg); DispatchMessage(&msg); )
Tady je to opravdu jednoduché:

  1. GetMessage() vezme další zprávu z fronty a klíčový moment: Blokuje vlákno, pokud je fronta prázdná.
  2. TranslateMessage() z WM_KEYDOWN/WM_KEYUP generuje zprávy WM_CHAR/WM_SYSCHAR (jsou potřeba, pokud si někdo chce vytvořit vlastní textový editor).
  3. DispatchMessage() odešle zprávu do procedury okna (pokud existuje).
Začněme tím, že použití tohoto kódu je nebezpečné, a zde je důvod. Vezměte prosím na vědomí poznámku pod čarou:
Protože návratová hodnota může být nenulová, nulová nebo -1, vyhněte se kódu, jako je tento:
while (GetMessage(lpMsg, hWnd, 0, 0)) ...
A níže je příklad správné smyčky.

Stojí za to říci, že ve VS šablonách pro aplikace Win32 je to přesně to, co je napsáno špatně cyklus. A to je velmi smutné. Ostatně málokdo se bude vrtat v tom, co dělali samotní autoři, protože to je a priori správně. A nesprávný kód se množí spolu s chybami, které je velmi obtížné zachytit.

Po tomto fragmentu kódu zpravidla následuje příběh o akcelerátorech a je přidáno několik nových řádků (s ohledem na poznámku v MSDN doporučuji okamžitě napsat správný cyklus):

HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); BOOL bRet = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(msg.hwnd, hAccel, &msg)) ( TranslateMessage(&msg); DispatchMessage(&msg) ;))
Tuto možnost jsem viděl nejčastěji. A on ( ta-dam) je opět špatně!

Nejprve o tom, co se změnilo (pak o problémech s tímto kódem):

V prvním řádku se ze zdrojů načte tabulka klíčů, po stisknutí se vygeneruje zpráva WM_COMMAND s odpovídajícím id příkazu.

TranslateAccelerator ve skutečnosti dělá toto: pokud vidí WM_KEYDOWN a kód klíče, které jsou v tomto seznamu, pak (opět klíčový bod) vygeneruje zprávu WM_COMMAND (MAKEWPARAM(id, 1)) a odešle ji na odpovídající handle okna zadaný v prvním argumentu, procedura zpracování.

Myslím, že z poslední fráze bylo jasné, jaký byl problém s předchozím kódem.
Dovolte mi vysvětlit: GetMessage zachytí zprávy pro VŠECHNY objekty typu „okna“ (které zahrnují děti: tlačítka, seznamy atd.) a TranslateAccelerator odešle vygenerovaný WM_COMMAND kam? Správně: zpět na tlačítko/seznam atd. Ale my zpracováváme WM_COMMAND v našem postupu, což znamená, že máme zájem ho v něm přijímat.

Je jasné, že pro námi vytvořené okno musí být volán TranslateAccelerator:

HWND hMainWnd = CreateWindow(...); HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); BOOL bRet = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(hMainWnd, hAccel, &msg)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) )
A vše se nyní zdá být dobré a úžasné: vše jsme podrobně analyzovali a vše by mělo fungovat perfektně.

A zase ne. :-) To bude fungovat správně, pokud budeme mít právě jedno okno - naše. Jakmile se objeví nemodální nové okno (dialog), všechny klávesy, které jsou v něm stisknuty, budou přeloženy do WM_COMMAND a odeslány kam? A opět správně: v našem hlavním okně.

V této fázi navrhuji nepoužívat berličky k řešení této slepé uličky, ale navrhuji zvážit věci, které jsou již v tutoriálech méně běžné (nebo se téměř nikdy nenacházejí).

IsDialogMessage

Soudě podle názvu této funkce si můžete myslet, že z nějakého důvodu určuje, zda daná zpráva patří do dialogu či nikoli. Ale především, proč to potřebujeme vědět? A za druhé, co bychom s těmito informacemi měli dělat dál?

Ve skutečnosti toho dělá trochu víc, než napovídá jeho název. A to:

  • Prochází podřízenými ovládacími prvky pomocí tlačítek Tab/Shift+Tab/nahoru/dolů/doprava/doleva. Plus ještě jedna věc, ale to nám stačí
  • Stisknutím ESC vygeneruje WM_COMMAND(IDCANCEL)
  • Stiskem Enter vygeneruje WM_COMMAND(IDOK) nebo kliknutím na aktuální tlačítko ve výchozím nastavení
  • Přepíná výchozí tlačítka (rámeček těchto tlačítek je o něco jasnější než u ostatních)
  • No a různé další věci, které uživateli usnadňují práci s dialogem
co nám to dává? Za prvé, nemusíme myslet na navigaci v okně. Stejně za nás udělají všechno. Mimochodem, navigaci na kartě lze provést přidáním stylu WS_EX_CONTROLPARENT do našeho hlavního okna, ale to je neohrabané a ne tak funkční.

Zadruhé nám to usnadní život ve všech ostatních bodech uvedených na seznamu (a ještě o něco více).

Obecně se používá někde v hloubi Windows k zajištění práce modální dialogová okna, a je dán programátorům, aby jej nazývali pro nemodální dialogy. Můžeme jej však použít kdekoli:

Přestože je funkce IsDialogMessage určena pro nemodální dialogová okna, můžete ji použít s jakýmkoli oknem obsahujícím ovládací prvky, což umožňuje oknům poskytovat stejný výběr klávesnice, jaký se používá v dialogovém okně.
Tito. nyní, když navrhneme smyčku takto:

HWND hMainWnd = CreateWindow(...); HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); BOOL bRet = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(hMainWnd, hAccel, &msg)) ( if (!IsDialogMessage(hMainWnd, &msg)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) ) )
Pak bude naše okno mít navigaci, jako v nativním dialogu Windows. Ale teď máme dvě nevýhody:

  1. Tento kód bude také fungovat pouze dobře s jedním (nemodálním) oknem;
  2. Po obdržení všech výhod dialogu navigace jsme připraveni o kouzla ve formě zpráv WM_KEYDOWN/WM_KEYUP (pouze pro okno samotné, nikoli pro podřízené ovládací prvky);
A v této fázi obecně všechny tutoriály končí a začínají otázky: Jak zacházet s událostmi klávesnice ve standardním dialogu winapi?
Toto je první odkaz na Googlu, ale věřte mi: jsou jich tisíce. O navrhovaných řešeních (nejlepší z nich je vytvořit si vlastní třídu dialogů, o které jsem psal výše, před podtřídou a RegisterHotKey. Někde jsem dokonce viděl „nejlepší“ cestu: použít Windows Hooks).

Je čas mluvit o tom, co není v tutoriálech a odpovědích.

Zpravidla (pravidlem! Pokud někdo chce více, můžete si zaregistrovat svou třídu pro dialogy a pracovat takto. A pokud to někoho zajímá, mohu to přidat do článku) chtějí WM_KEYDOWN, když chtějí zpracovat kliknutí na klávesu, která bude vykonávat funkci bez ohledu na zvolený ovládací prvek v okně - tzn. nějakou obecnou funkci pro celý tento konkrétní dialog. A pokud ano, tak proč nevyužít bohatých možností, které nám samotné WinAPI nabízí: TranslateAccelerator.

Používá se všude přesně jeden tabulku akcelerátoru a pouze pro hlavní okno. No, opravdu: existuje jeden cyklus GetMessage-loop, což znamená, že existuje jedna tabulka. Kam jinam by měli jít?

Ve skutečnosti mohou být smyčky GetMessage vnořený. Podívejme se znovu na popis PostQuitMessage:

Funkce PostQuitMessage odešle zprávu WM_QUIT do fronty zpráv vlákna a okamžitě se vrátí; funkce jednoduše indikuje systému, že vlákno požaduje někdy v budoucnu ukončit.
A GetMessage:
Pokud funkce načte zprávu WM_QUIT, vrácená hodnota je nula.
GetMessage-loop se tedy ukončí, pokud v proceduře okna zavoláme PostQuitMessage. Co to znamená?

Můžeme za každý nemodální okna v našem programu vytvářejí vlastní podobnou smyčku. V tomto případě pro nás není DialogBoxParam vhodný, protože roztáčí svůj vlastní koloběh a my to nemůžeme ovlivnit. Pokud však vytvoříme dialog přes CreateDialogBoxParam nebo okno přes CreateWindow, pak můžeme roztočit další smyčku. Zároveň v každý V takovém okně a dialogu musíme zavolat PostQuitMessage:

HWND hMainWnd = CreateWindow(...); HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); BOOL bRet = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(hMainWnd, hAccel, &msg)) ( if (!IsDialogMessage(hMainWnd, &msg)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) ) ) // .... LRESULT CALLBACK WndProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam) ( switch(umsg) ( případ WM_MYMESSAGE: ( HWND hDlg = CreateD hInstance, MAKEINTRESOURCE(IDD_MYDIALOG), hwnd, MyDialogBoxProc); HACCEL hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR_FOR_MY_DIALOG)); BOOL bRet = 0, fSavedWindowEnhowState (h); ALSE); // deaktivace nadřazeného okna, as dialogové okno je modální while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!TranslateAccelerator(hDlg, hAccel, &msg)) ( if (!IsDialogMessage(hDlg , &msg)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) ) ) EnableWindow(hwnd, fSavedEnabledState); // povolení nadřazeného okna. Dialog byl zavřen přerušení; ) ) ) INT_PTR CALLBACK MyDlgProc(HWNDumsg, UINT VOLÁNÍ wparam, LPARAM lparam) ( switch(umsg) ( case WM_CLOSE: ( // EndDialog(hwnd, 0); --NEDĚLEJ TO! // EndDialog je platný POUZE pro modální dialogy vytvořené pomocí DialogBox(Param) DestroyWindow(hwnd); přestávka; ) case WM_DESTROY: ( PostQuitMessage(0); break; ) // .... ) return 0; )
Poznámka: nyní pro každé nové okno v našem programu můžeme přidat ke zpracování vlastní tabulka akcelerátoru. WM_QUIT vytrhne GetMessage ze smyčky pro dialog a vnější smyčka ji ani neuvidí. Proč se tohle děje?

Faktem je, že vnější smyčka se „zastavila“ při volání DispatchMessage, která zavolala naši proceduru, která roztočí vlastní interiér Smyčka GetMessage se stejnou zprávou DispatchMessage. Klasické vnořené volání (v tomto případě DispatchMessage). Vnější smyčka proto nebude přijímat WM_QUIT a nebude v této fázi ukončena. Všechno bude fungovat hladce.

Ale má to i své nevýhody:
Každá taková smyčka zpracuje zprávy pouze pro „vaše“ okno. O ostatních tady nevíme. To znamená, že pokud se někde objeví další cyklus, pak všechna ostatní okna nedostanou potřebné zpracování svých zpráv párem TranslateAccelerator/IsDialogMessage.

No, je čas vzít všechny tyto komentáře v úvahu a konečně napsat správné zpracování všech zpráv ze všech oken našeho programu. Rád bych poznamenal, že níže uvažujeme případ pro jedno vlákno. Protože Každé vlákno má svou vlastní frontu zpráv, pak pro každé vlákno budete muset vytvořit své vlastní struktury. To se provádí velmi triviálními změnami v kódu.

Děláme to krásně

Protože správná formulace problému je polovinou řešení, pak musíte nejprve správně položit tento problém.

Za prvé by bylo logické, že pouze aktivní okno přijímá zprávy. Tito. U neaktivního okna nebudeme vysílat akcelerátory a předávat zprávy IsDialogMessage.

Za druhé, pokud pro okno není specifikována tabulka akcelerátorů, pak není co vysílat, jednoduše zprávu odešleme do IsDialogMessage.

Vytvořme jednoduchý std::map, který bude mapovat deskriptor okna na deskriptor tabulky akcelerátoru. Takhle:

Std::map l_mAccelTable;
A jak se budou vytvářet okna, přidáme do nich nová okna s deskriptorem do naší oblíbené tabulky (nebo nulou, pokud takové zpracování není vyžadováno).

BOOL AddAccelerators(HWND hWnd, HACCEL hAccel) ( if (IsWindow(hWnd)) ( l_mAccelTable[ hWnd ] = hAccel; return TRUE; ) return FALSE; ) BOOL AddAccelerators(HWND hWnd, LPCTSTRA AddhAccelerators return) (LPCTSTR AddhAcceler hInstance, accel)); ) BOOL AddAccelerators(HWND hWnd, int accel) ( return AddAccelerators(hWnd, MAKEINTRESOURCE(accel)); ) BOOL AddAccelerators(HWND hWnd) ( return AddAccelerators(hWnd, HACCEL))(NULL));
Po zavření okna to smažte. Takhle:

Void DelAccel(HWND hWnd) ( std::map ::iterator me = l_mAccelTable.find(hWnd); if (me != l_mAccelTable.end()) ( if (já->sekunda) ( DestroyAcceleratorTable(já->sekunda); ) l_mAccelTable.erase(me); ) )
Nyní, když vytváříme nové dialogové okno/okno, zavolejte AddAccelerators(hNewDialog, IDR_MY_ACCEL_TABLE). Jak zavřít: DelAccel(hNewDialog).

Máme seznam oken s potřebnými deskriptory. Pojďme trochu upravit naši hlavní smyčku zpracování zpráv:

// ... HWND hMainWnd = CreateWindow(...); AddAccelerators(hMainWnd, IDR_ACCELERATOR); BOOL bRet = 0; while (bRet = GetMessage(&msg, nullptr, 0, 0)) ( if (-1 == bRet) break; if (!HandleAccelArray(GetActiveWindow(), msg)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) ) //...
Mnohem lepší! Co je v HandleAccelArray a proč je tam GetActiveWindow()?

Trocha teorie:

Existují dvě funkce, které vracejí popisovač do aktivního okna: GetForegroundWindow a GetActiveWindow. Rozdíl mezi prvním a druhým je zcela jasně popsán v popisu druhého:

Vrácená hodnota je popisovač aktivního okna připojený k frontě zpráv volajícího vlákna. Jinak je vrácená hodnota NULL.
Pokud první vrátí popisovač do libovolného okna v systému, vrátí se pouze to druhé který používá frontu zpráv našeho vlákna. Protože Zajímají nás pouze okna našeho vlákna (a tedy ta, která skončí v naší frontě zpráv), takže vezmeme to druhé.

HandleAccelArray, vedený deskriptorem, který mu byl předán pro aktivní okno, tedy hledá právě toto okno v naší mapě, a pokud tam je, odešle tuto zprávu k vysílání do TranslateAccelerator, a pak (pokud první neviděl pravý) na IsDialogMessage. Pokud druhý nezpracoval zprávu, vrátíme FALSE, abychom prošli standardní procedurou TranslateMessage/DispatchMessage.

Vypadá to takto:

BOOL HandleAccelWindow(std::map ::const_iterator mh, MSG & msg) ( const HWND & hWnd = mh->first; const HACCEL & hAccel = mh->second; if (!TranslateAccelerator(hWnd, hAccel, &msg)) ( // zpráva není pro TranslateAc Zkuste to s IsDialogMessage if (!IsDialogMessage(hWnd, &msg)) ( // tak, proveďte výchozí nastavení return FALSE; ) ) // ok, zpráva přeložena. Řekněte to message-loop, aby další zpráva vrátila TRUE; ) BOOL HandleAccelArray (HWND hActive, MSG & msg) ( if (!hActive) vrátí FALSE; // žádné aktivní okno. Nic dělat std::map ::const_iterator mh = l_mAccelTable.find(hActive); if (mh != l_mAccelTable.end()) ( // Rozumím! Zkuste přeložit tuto zprávu pro aktivní okno return HandleAccelWindow(mh, msg); ) return FALSE; )
Nyní má každé podřízené okno právo přidat svou oblíbenou akcelerační tabulku a klidně chytit a zpracovat WM_COMMAND s potřebným kódem.

A co ještě jeden řádek v kódu obslužné rutiny WM_COMMAND?

Popis v TranslateAccelerator zní:
Aby se odlišila zpráva, kterou tato funkce odesílá, od zpráv odeslaných nabídkami nebo ovládacími prvky, obsahuje slovo nejvyššího řádu parametru wParam zprávy WM_COMMAND nebo WM_SYSCOMMAND hodnotu 1.
Kód zpracování WM_COMMAND obvykle vypadá takto:

Switch(HIWORD(wParam)) ( case BN_CLICKED: // příkaz z tlačítek/menu ( switch(LOWORD(wParam)) ( case IDC_BUTTON1: DoButton1Stuff(); break; case IDC_BUTTON2: DoButton2Stuff(); break; // ... ) přestávka; ) )
Nyní můžete psát takto:

Switch(HIWORD(wParam)) ( case 1: // případ akcelerátoru BN_CLICKED: // příkaz z tlačítek/nabídky ( switch(LOWORD(wParam)) ( case IDC_BUTTON1: DoButton1Stuff(); break; case IDC_BUTTON2: DoButton2Stuff(); break ; // ... ) přestávka; ) )
A teď se vracím ke stejnému fceux a dodávám jen jeden řádek do kódu pro zpracování příkazů z tlačítek dostaneme to, co chceme: ovládat debugger z klávesnice. Stačí přidat malý obal kolem hlavní smyčky zpráv a novou tabulku akcelerátoru s potřebnými shodami VK_KEY => IDC_DEBUGGER_BUTTON.

P.S.: Málokdo ví, ale můžete si vytvořit vlastní tabulku akcelerátorů a nyní ji aplikovat za běhu.

P.P.S.: Protože DialogBox/DialogBoxParam točí vlastní smyčku, pak při vyvolání dialogu přes ně nebudou fungovat akcelerátory a naše smyčka (nebo smyčky) budou „nečinné“.

P.P.P.S.: Po zavolání HandleAccelWindow se může mapa l_mAccelTable změnit, protože TranslateAccelerator nebo IsDialogMessage volá DispatchMessage a tam se v našich obslužných programech můžeme setkat s AddAccelerators nebo DelAccel! Po této funkci se jej proto raději nedotýkejte.

Můžete cítit kód. Jako základ byl vzat kód vygenerovaný ze standardní šablony MS VS 2017.

Štítky: Přidat štítky