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).
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.
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.
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 oknaFunkce 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é.
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.
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ě.
Funkce WindowFromPoint
WindowFromPoint(Bod: TPoint): HWND;
Vrátí úchyt do okna umístěného v daném bodě na obrazovce.
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.
SetWindowPos
function SetWindowPos(hWnd: HWND; hWndInsertAfter: HWND; X, Y, cx, cy: Integer; uFlags: UINT): BOOL; stdcall;
Nastaví okno do nové polohy
V souladu s tím nové obzory. , vert. pozice oken ( X, Y), stejně jako nová šířka
a výška ( cx, cy)
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.
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.
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.
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.
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í:
uživatelské rozhraní;
multimédia;
shell Windows;
síťové služby.
základní služby;
bezpečnost;
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é. Třída newrect:public RECT Nyní vytiskněte objekt pomocí cout/wcout: Cout< A vše se vám zobrazí v pohodlné podobě, jak požadujete. 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. 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á. 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); 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. Obejít takové drobné potíže je snadné. Existují minimálně dva zcela legální způsoby: Zatímco (GetMessage(&msg, nullptr, 0, 0)) ( TranslateMessage(&msg); DispatchMessage(&msg); ) 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) ;)) 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. 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 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í). Ve skutečnosti toho dělá trochu víc, než napovídá jeho název. A to: 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: 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); ) ) ) 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: 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; ) 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: 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. 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 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)); Void DelAccel(HWND hWnd) ( std::map 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); ) ) //... 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: 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 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; ) ) 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; ) ) 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
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:
{
veřejnost:
přítel ostream & operátor<<(ostream &strm,newrect &rect)
{
strm<<"Prtint RECT object:\n";
strm<
}
};
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;)
}; 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. 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.
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?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.
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.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):
Tady je to opravdu jednoduché:
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:
A níže je příklad správné smyčky.
while (GetMessage(lpMsg, hWnd, 0, 0)) ...
Tuto možnost jsem viděl nejčastěji. A on ( ta-dam) je opět špatně!
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.
A vše se nyní zdá být dobré a úžasné: vše jsme podrobně analyzovali a vše by mělo fungovat perfektně.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?
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í.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:
Pak bude naše okno mít navigaci, jako v nativním dialogu Windows. Ale teď máme dvě nevýhody:
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). 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á?
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?
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.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.
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).
Po zavření okna to smažte. Takhle:
Nyní, když vytváříme nové dialogové okno/okno, zavolejte AddAccelerators(hNewDialog, IDR_MY_ACCEL_TABLE). Jak zavřít: DelAccel(hNewDialog).
Mnohem lepší! Co je v HandleAccelArray a proč je tam GetActiveWindow()?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é.
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:
Nyní můžete psát takto:
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.