Formulář s dírou

Použití API funkcí pro formulář

Doc. Dr. Vladimír Homola, Ph.D.

 

Obsah

Funkce API Windows

Formulář s dírou

Funkce API Windows

API, Handle

API (Application Programming Interface) je označení pro definované rozhraní mezi aplikačním programem a hostitelským systémem. Jde o množinu funkcí, podprogramů a jiných konstrukcí (např. jádra operačního systému), které může za svého chodu využívat aplikace psaná programátorem. Pro reálné použití je tedy samozřejmým předpokladem detailní popis chování jednotlivých komponent ve vazbě na parametry předávané volající aplikací volaným komponentám. Aplikační programátor se pak nemusí zajímat o vnitřní implementaci používaných komponent.

Handle (popisovač) je abstraktní odkaz na nějaký zdroj poskytnutý mojí aplikaci jinou aplikací (obvykle operačním systémem). Ten pak moje aplikace může použít ke zpracování tohoto zdroje. Zavedením abstraktního odkazu se docílí skrytí skutečné adresy nějakého zdroje pro přímé použití adresy mou aplikací. To umožňuje (např. operačnímu) systému transparentně reorganizovat fyzickou paměť. Moje aplikace tedy používá adresu popisovače, ve kterém teprve najde volaná aplikace skutečnou adresu paměti. Tuto skutečnou adresu pak tedy může systém libovolně měnit, aniž by to mělo dopad na moji volající aplikaci.

Právě popisovače (handles) jsou velmi často používány jako parametry volaných funkcí API. Programuje-li programátor aplikaci předkládající uživateli na obrazovce formulář, je při chodu aplikace formulář vizuálně reprezentován množinou bodů obrazovky mající za zdroj data ve fyzické paměti. Na základě těchto dat pak operační systém různými svými komponentami zařizuje „rozsvěcení“ příslušných bodů obrazovky. Je zcela nevhodné, aby do oné datové oblasti paměti přímo zasahovala uživatelova aplikace. Proto systém definuje abstraktní grafický region tvořený abstraktními body, a manipulaci s nimi umožňuje aplikacím právě komponentami API. Pro aplikační program je pak grafický region představován jeho popisovačem. Obraz formuláře je pak programátorem aplikace ovlivňován nikoliv pomocí jeho adresy, ale adresy jeho popisovače.

Jednotlivé knihovny API systému Windows jsou programátoru v Basicu zpřístupněny popisem ve tvaru

 

Public Declare Function IdentFunkce Lib "IdentKnihovny" _
      (ByVal Param1 As Typ, ByVal Param2 As Typ, ... , ByVal ParamN As Typ) As Typ
    

Je-li parametrem nebo výsledkem popisovač (handle), je jako Typ uvedeno 4bytové (pro 32bitové systémy) nebo 8bytové (pro 64bitové systémy) celé číslo. V jazyku Basic ve Visual Studiu tomu tedy odpovídají typy Integer a Long.

Tělo funkce se nijak nepopisuje, "prototypová hlavička" funkce se uvádí na úrovni modulu.

CombineRgn - knihovna GDI32

Funkce CombineRgn provádí logickou operaci nad dvěma regiony (jejich handles jsou druhý a třetí parametr - source regions). Výsledkem je upravený handle regionu uvedeného jako první parametr (destination region). Použitá logická operace je dána posledním parametrem.

Popis funkce:

 

Public Declare Function CombineRgn Lib "gdi32" _
         (ByVal hDestRgn As Integer, ByVal hSrcRgn1 As Integer, ByVal hSrcRgn2 As Integer, ByVal nCombineMode As Integer) As Integer

Logické operace:

Ident Hodnota Výsledek v prvním parametru
RGN_AND 1 Průnik druhého a třetího parametru
RGN_COPY 5 Kopie druhého parametru
RGN_DIFF 4 Ta část druhého parametru, která není ve třetím parametru
RGN_OR 2 Sjednocení druhého a třetího parametru
RGN_XOR 3 Sjednocení druhého a třetího parametru kromě jejich společné části

Návratová hodnota:

Ident Hodnota Popis výsledku v prvním parametru
NULLREGION 1 Region je prázdný
SIMPLEREGION 2 Region je jediný obdélník
COMPLEXREGION 3 Region je tvořen z více než jedním obdélníkem
ERROR 0 Žádný region nebyl vytvořen

Poznámky:

Tři regiony uvedené jako parametry nemusí být nutně různé. Je-li např. první parametr roven druhému, pak výsledek se objeví v druhém regionu.

CreateRectRgn - knihovna GDI32

Funkce CreateRectRgn vytvoří obdélníkový region určený souřadnicemi [X1, Y1] levého horního rohu a souřadnicemi [X2, Y2] pravého dolního rohu.

Popis funkce:

 

Public Declare Function CreateRectRgn Lib "gdi32" _
      (ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer

Návratová hodnota:

Návratovou hodnotou je buď handle vytvořeného regionu (v případě úspěchu) nebo hodnota 0 = nula (v případě neúspěchu).

Poznámky:

Odstranění takto vytvořeného a již nepotřebného regionu zajistí volání funkce DeleteObject.

Poznámka podle MSDN: The region will be exclusive of the bottom and right edges, doslova přeloženo: Oblast bude bez spodního a pravého okraje (?).

CreateEllipticRgn - knihovna GDI32

Funkce CreateEllipticRgn vytvoří eliptický region určený souřadnicemi [X1, Y1] levého horního rohu a souřadnicemi [X2, Y2] pravého dolního rohu obdélníku, jemuž je elipsa vepsána.

Popis funkce:

 

Public Declare Function CreateEllipticRgn Lib "gdi32" _
      (ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer

Návratová hodnota:

Návratovou hodnotou je buď handle vytvořeného regionu (v případě úspěchu) nebo hodnota 0 = nula (v případě neúspěchu).

Poznámky:

Odstranění takto vytvořeného a již nepotřebného regionu zajistí volání funkce DeleteObject.

Obdélník opsaný elipse určuje velikost, tvar a orientaci elipsy. Jeho delší strana definuje délku hlavní osy (= dvojnásobek hlavní poloosy), kratší strana definuje délku vedlejší osy (= dvojnásobek vedlejší poloosy), střed obdélníku je středem elipsy.

SetWindowRgn - knihovna USER32

Funkce SetWindowRgn nastavuje region okna. Region okna určuje oblast v okně, kde systém umožňuje kreslení. Systém nezobrazuje žádnou část okna, ležící mimo region okna.

Popis funkce:

 

Public Declare Function SetWindowRgn Lib "user32" _
      (ByVal hWnd As Integer, ByVal hRgn As Integer, ByVal bRedraw As Boolean) As Integer

Parametry:

hWnd - handle (popisovač) okna, jehož region je nastavován.

hRgn - handle (popisovač) regionu. Funkce nastaví region okna na tento region.

bRedraw - určuje, zda systém překreslí (hodnota True) nebo nepřekreslí (hodnota False) po nastavení regionu okno. Je-li okno viditelné (Visible), je logické (ale ne nutné) nastavit parametr na True.

Návratová hodnota:

Návratovou hodnotou je buď nenula (v případě úspěchu) nebo hodnota 0 = nula (v případě neúspěchu).

Poznámky:

Když je tato funkce volána, systém odešle do okna zprávy WM_WINDOWPOSCHANGING a WM_WINDOWPOSCHANGED. Pro formulář to znamená, že vzniknou události na tyto zprávy reagující.

Souřadnice region okna jsou relativní k levému hornímu rohu okna, nikoli k klientské oblasti okna.

Po úspěšném volání SetWindowRgn systém vlastní region určený popisovačem regionu hRgn. Systém nevytvoří kopii regionu. Proto by námi vytvářená aplikace s tímto popisovačem regionu neměla provádět žádná další volání funkcí. Zejména by neměla odstraňovat tento popisovač regionu. Systém sám odstraní popisovač regionu, když již není potřeba.

Chce-li aplikace získat region okna, použije funkci GetWindowRgn.

DeleteObject - knihovna GDI32

Funkce DeleteObject odstraní logické pero (pen), štětec (brush), písmo (font), bitmapu, region nebo paletu a uvolní všechny systémové prostředky přidružené k objektu. Po odstranění objektu již zadaný popisovač není platný.

Popis funkce:

 

Public Declare Function DeleteObject Lib "gdi32" _
      (ByVal hObject As Integer) As Integer

Parametry:

hObject - handle objektu k odstranění.

Návratová hodnota:

Návratovou hodnotou je buď nenula (v případě úspěchu) nebo hodnota 0 = nula (v případě neúspěchu).

Poznámky:

Neúspěchem skončí funkce tehdy, jde-li o neplatný popisovač, nebo pokud je objektem pero nebo štětec a je používán v nějakém „Kontextu Zařízení“ (DC - Device Context).

Device Context je struktura, která definuje sadu grafických objektů a jejich přidružených atributů, stejně jako grafické režimy, které ovlivňují výstup. Mezi grafické objekty patří pero pro kreslení čar, štětec pro malování a vyplňování, bitmapa pro kopírování nebo posouvání částí obrazovky, paleta pro definování sady dostupných barev, oblast pro ořezávání a další operace a cesta pro malířské a kreslicí operace.

Formulář s dírou - funkce API Windows

V programech psaných v jazyku Basic lze využívat funkce dynamických knihoven Windows (viz výše API). Pro označením souboru s dynamickou knihovnou (pro knihovny např. User32, Kernel32 a GDI32 není nutno zapisovat cestu ani příponu). Níže uvedený program sestává z jednoho modulu (jeho úplný text je uveden níže) a jednoho formuláře jménem frĎoura o rozměrech 500 x 400 bodů. Program aktivuje formulář tak, že je v něm nejdříve "vyříznuta" díra (= eliptický region = shape oval).

' ===============================================================
' Formulář s dírou - funkce API
' ===============================================================


Imports swf = System.Windows.Forms


Module mdBasDoura


' ----------------------------------------------------------------
' Deklarace funkcí a konstant Windows API:
' ----------------------------------------------------------------

   Public Const RGN_DIFF As Integer = 4

   Public Declare Function CreateRectRgn Lib "gdi32" _
      (ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer

   Public Declare Function CreateEllipticRgn Lib "gdi32" _
      (ByVal X1 As Integer, ByVal Y1 As Integer, ByVal X2 As Integer, ByVal Y2 As Integer) As Integer

   Public Declare Function CombineRgn Lib "gdi32" _
      (ByVal hDestRgn As Integer, ByVal hSrcRgn1 As Integer, ByVal hSrcRgn2 As Integer, ByVal nCombineMode As Integer) As Integer

   Public Declare Function SetWindowRgn Lib "user32" _
      (ByVal hWnd As Integer, ByVal hRgn As Integer, ByVal bRedraw As Boolean) As Integer

   Public Declare Function DeleteObject Lib "gdi32" _
      (ByVal hObject As Integer) As Integer


' ----------------------------------------------------------------
' Hlavní program:
' ----------------------------------------------------------------

   Sub Main()

      ' Deklarace formuláře třídy frDOURA (má rozměry 500 x 400):
      Dim lFormular As New frDOURA

      ' Vyříznutí elispy se středem [340, 270] a rozměrech 250 x 160:
      DerujFormular(lFormular, 340, 270, 250, 160)
      
      ' Zobrazení formuláře:
      lFormular.ShowDialog()

   End Sub


' ----------------------------------------------------------------
' Podprogram pro vyříznutí elipsy z formuláře:
' ----------------------------------------------------------------

   Public Sub DerujFormular(qF As swf.Form, qX As Integer, qY As Integer, qW As Integer, qH As Integer)

      ' Vytvoří ve formuláři qF průhledný eliptický region. Elipsa má střed [qX, qY]
      ' a šířku x výšku = qW x qH.

      Dim lIntPtr As IntPtr           ' Pointer na Handler
      Dim lHwnd As Integer            ' Handler formuláře

      Dim lRegionFormulare As Integer ' Region formuláře
      Dim lRegionElipsy As Integer    ' Region elipsy

      Dim lSirkaFormulare As Integer  ' Šířka formuláře
      Dim lVyskaFormulare As Integer  ' Výška formuláře

      Dim lStredFormulareX As Integer ' Souřadnice X středu formuláře
      Dim lStredFormulareY As Integer ' Souřadnice Y středu formuláře

      Dim lSirkaElipsy As Integer     ' Šířka elipsy
      Dim lVyskaElipsy As Integer     ' Výška elipsy

      Dim lStredElipsyX As Integer    ' Souřadnice X středu elipsy
      Dim lStredElipsyY As Integer    ' Souřadnice Y středu elipsy

      Dim lLHRelipsyX As Integer      ' Souřadnice X levého horního rohu elipsy
      Dim lLHRelipsyY As Integer      ' Souřadnice Y levého horního rohu elipsy

      Dim lPDRelipsyX As Integer      ' Souřadnice X pravého dolního rohu elipsy
      Dim lPDRelipsyY As Integer      ' Souřadnice Y pravého dolního rohu elipsy

      With qF

         ' Vnitřní rozměry formuláře:
         lSirkaFormulare = .Width
         lVyskaFormulare = .Height

         ' Střed formuláře
         lStredFormulareX = lSirkaFormulare \ 2
         lStredFormulareY = lVyskaFormulare \ 2

         ' Umístění elipsy :
         lStredElipsyX = qX
         lStredElipsyY = qY

         ' Rozměry elipsy:
         lSirkaElipsy = qW
         lVyskaElipsy = qH

         ' Levý horní roh elipsy:
         lLHRelipsyX = lStredElipsyX - lSirkaElipsy \ 2
         lLHRelipsyY = lStredElipsyY - lVyskaElipsy \ 2

         ' Pravý dolní roh elipsy:
         lPDRelipsyX = lStredElipsyX + lSirkaElipsy \ 2
         lPDRelipsyY = lStredElipsyY + lVyskaElipsy \ 2

         ' Regiony:
         lRegionFormulare = CreateRectRgn(0, 0, lSirkaFormulare, lVyskaFormulare)
         lRegionElipsy = CreateEllipticRgn(lLHRelipsyX, lLHRelipsyY, lPDRelipsyX, lPDRelipsyY)

         ' Logické operace s regiony:
         CombineRgn(lRegionFormulare, lRegionFormulare, lRegionElipsy, RGN_DIFF)

         ' Handler formuláře:
         lIntPtr = .Handle
         lHwnd = lIntPtr.ToInt32
         SetWindowRgn(lHwnd, lRegionFormulare, True)

         ' Odstranění zobrazování regionu elipsy:
         DeleteObject(lRegionElipsy)

      End With

   End Sub

End Module

Přeložený a sestavený program je možno zde vyzkoušet: DOURA.EXE. Po spuštění nezapomeňte formulář přesouvat, aby v oválu byl vidět obsah toho, co je "pod formulářem".

Kompletní zdrojové řešení (Solution) pro Visual Studio 2019 je možno stáhnout zde. Po rozbalení do jakéhokoliv prázdného adresáře se jako obvykle ve Studiu otevírá soubor s příponou .sln (=soultion).

 

 

 

 

Rev. 01 / 2021