16. Zpracování výjimek II
  1. Pokud ve své aplikaci používáme komponenty VCL, pak je vhodné se seznámit s mechanismem zpracování výjimek VCL. Tyto výjimky jsou tvořeny mnoha třídami a jsou generovány automaticky, když něco neočekávaného nastane. Pokud výjimku nezpracujeme, pak VCL ji zpracuje implicitním způsobem. Obvykle je zobrazena zpráva popisující typ vzniklé chyby.

  2. Mezi zpracováním výjimek C++ a OVL je několik odchylek: C++ Builder umožňuje zpracovat výjimky generované operačním systémem. Výjimky operačního systému zahrnují numerické chyby, přetečení zásobníku, přerušení Ctrl+C apod. Jsou zpracovány knihovnou běhu programu a převedeny na objekty tříd výjimek VCL před předáním naši aplikaci. Můžeme zapsat např. následující kód:
    try {
      char * p = 0;
      *p = 0;
    }
    catch (const EAccessViolation &e) {
      ShowMessage("Co to děláte?");
    }
  3. C++ Builder obsahuje mnoho zabudovaných tříd výjimek pro automatické zpracování dělení nulou, chyb souborů, chybného přetypování a mnoha dalších chyb. Všechny třídy výjimek VCL jsou odvozeny od třídy Exception. Exception poskytuje základní vlastnosti a metody pro všechny výjimky a poskytuje konzistentní rozhraní pro zpracování výjimek aplikací.

  4. Výjimky můžeme zachytit blokem catch, který předpokládá parametr typu Exception. K zachycení VCL výjimek používáme následující syntaxi:
    catch (const třída_výjimka &proměnná_výjimky)
    Specifikujeme třídu výjimky, kterou chceme zachytit a nabízíme proměnnou, kterou se chceme odkazovat na výjimku. Následující příklad ukazuje, jak generovat VCL výjimku:
    void __fastcall TForm1::ThrowException(TObject *Sender)
    {
      try {
        throw Exception("VCL component");
      }
      catch(const Exception &E) {
        ShowMessage(AnsiString(E.ClassName())+ E.Message);
      }
    }
    Příkaz throw vytváří instanci třídy Exception a volá její konstruktor. Všechny výjimky odvozené od Exception mají zprávu, která může být zobrazena. Zpráva je předána konstruktoru a získávána vlastností Message.
    Nejdůležitější třídy výjimek VCL jsou popsány v následující tabulce:
     
    Třída výjimky Popis
    EAbort Zastavuje sekvenci událostí bez zobrazení dialogového okna chybové zprávy.
    EAccessViolation Nedovolený přístup do paměti.
    EBitsError Nedovolený pokus o přístup do bitového pole.
    EComponentError Signalizuje nedovolený pokus o přejmenování komponenty.
    EConvertError Indikuje chybu konverze.
    EDatabaseError Specifikuje chybu přístupu k databázi.
    EDBEditError Signalizuje nekompatibilní data se specifikovanou maskou.
    EDivByZero Celočíselné dělení nulou.
    EExternalException Signalizuje nepoznanou výjimku.
    EInOutError Reprezentuje chybu vstupu nebo výstupu souboru.
    EIntOverflow Celočíselné přetečení.
    EInvalidCast Nedovolené přetypování.
    EInvalidGraphic Pokus o práci s neznámým grafickým formátem.
    EInvalidOperation Nedovolená operace na komponentě.
    EInvalidPointer Výsledek nedovolené ukazatelové operace.
    EMenuError Signalizuje problém s prvkem nabídky.
    EOleCtrlError Detekuje problém se spojením na ovladač ActiveX.
    EOleError Specifikuje chybu automatizace OLE.
    EPrinterError Signalizuje chybu tisku.
    EPropertyError Neúspěšný pokus o nastavení hodnoty vlastnosti.
    ERangeError Příliš velká celočíselná hodnota.
    ERegistryException Určuje chybu registru.
    EStackOverflow Přeplnění zásobníku.
    EZeroDivide Dělení nulou v pohyblivé řádové čárce.

    Jak vidíme v předchozí tabulce, zabudované třídy VCL výjimek, zpracovávají mnoho výjimek za nás a můžeme tedy zjednodušit náš kód. Pro zpracování dalších výjimečných situací můžeme vytvořit své vlastní výjimky. Můžeme deklarovat nové třídy výjimek odvozením od Exception s mnoha konstruktory (nebo překopírujeme konstruktory z existující třídy v SYSUTILS.HPP). Deklaraci vlastních tříd výjimek uvidíme na příkladu v následující kapitole.

  5. C++ Builder obsahuje několik knihoven běhu aplikace (RTL). Většina z nich je určena pro práci s aplikacemi C++ Builderu, ale jedna z nich (CW32MT.LIB) je normální knihovna běhu aplikace, která nevyužívá VCL. Tato knihovna je poskytnuta pro podporu aplikacím, které jsou částí projektu, ale jsou nezávislé na VCL. Tato RTL nemá podporu pro zachytávání výjimek operačního systému, protože tyto objekty výjimek jsou odvozeny od TObject a to vyžaduje sestavení VCL k naši aplikaci. Plnou podporu zpracování výjimek VCL poskytuje RTL CP32MT.LIB.
  6. Nyní se opět vrátíme k balíčkům. Jak již víme, C++ Builder používá běhové a návrhové balíčky. Běhové balíčky jsou šířeny s aplikacemi C++ Builderu. Poskytují funkčnost spuštěné aplikaci. Pro spuštění aplikace, která používá balíčky, musíme mít EXE soubor aplikace a všechny balíčky (BPL soubory), které aplikace používá. Při šíření aplikace, musíme zajistit, že uživatelé mají správné verze všech vyžadovaných balíčků.

  7. Používání balíčků zadáváme značkou Build with Runtime Packages na stránce Packages dialogového okna zobrazeného po volbě Project | Options. Pod touto značkou je uveden seznam používaných balíčků. Pro přidání balíčku k seznamu, stiskneme tlačítko Add a v zobrazeném dialogovém okně zadáme jméno přidávaného balíčku. Tlačítko Browse je možno použít k nalezení balíčku. Pokud jména balíčků zapisujeme přímo do editačního ovladače, pak do seznamu nezapisujeme přípony souborů a jednotlivá jména oddělujeme středníky. Např.
    VCL30;VCLDB30;VCLDBX30
    Balíčky uvedené zde v seznamu jsou automaticky přidány k naši aplikaci, když ji překládáme. Aplikace sestavená s balíčky, stále musí vkládat hlavičkové soubory pro zabalené používané jednotky. Např. aplikace, která používá databázové ovladače musí obsahovat příkaz
    #include "vcldb.h";
    pokud používá balíček VCLDB30. V generovaných zdrojových souborech C++ Builder vytváří tyto příkazy #include automaticky.
    C++ Builder je dodáván s několika běhovými balíčky, včetně VCL30, která obsahuje základní podporu pro jazyk a komponenty. Balíček VCL30 obsahuje nejčastěji používané komponenty, systémové funkce a prvky rozhraní Windows. V následující tabulce je uveden seznam běhových balíčků dodávaných s C++ Builderem a jednotky, které obsahují.
     
    Balíček Jednotky
    VCL30.BPL  Ax, Buttons, Classes, Clipbrd, Comctrls, Commctrl, Commdlg, Comobj, Comstrs, Consts, Controls, Ddeml, Dialogs, Dlgs, Dsgnintf, Dsgnwnds, Editintf, Exptintf, Extctrls, Extdlgs, Fileintf, Forms, Graphics, Grids, Imm, IniFiles, Isapi, Isapi2, Istreams, Libhelp, Libintf, Lzexpand, Mapi, Mask, Math, Menu, Messages, Mmsystem, Nsapi, Ole2I, Oleconst, Olectnrs, Olectrls, Oledlg, Penwin, Printers, Proxies, Registry, Regstr, Richedit, Shellapi, Shlobj, Stdctrls, Stdvcl, Sysutils, Tlhelp32, Toolintf, Toolwin, Typinfo, Vclcom, Virtintf, Windows, Wininet, Winsock, Winspool, Winsvc
    VCLX30.BPL  Checklst, Colorgrd, Ddeman, Filectrl, Mplayer, Outline, Tabnotbk, Tabs
    VCLDB30.BPL Bde, Bdeconst, Bdeprov, Db, Dbcgrids, Dbclient, Dbcommon, Dbconsts, Dbctrls, Dbgrids, Dbinpreq, Dblogdlg, Dbpwdlg, Dbtables, Dsintf, Provider, SMintf
    VCLDBX30.BPL Dblookup, Report
    DSS30.BPL  Mxarrays, Mxbutton, Mxcommon, Mxconsts, Mxdb, Mxdcube, Mxdssqry, Mxgraph, Mxgrid, Mxpivsrc, Mxqedcom, Mxqparse, Mxqryedt, Mxstore, Mxtables, Mxqvb
    QRPT30.BPL  Qr2const, Qrabout, Qralias, Qrctrls, Qrdatasu, Qrexpbld, Qrextra, Qrprev, Qrprgres, Qrprntr, Qrqred32, Quickrpt
    TEE30.BPL  Arrowcha, Bubblech, Chart, Ganttch, Series, Teeconst, Teefunci, Teengine, Teeprocs, Teeshape
    TEEDB30.BPL Dbchart, Qrtee
    TEEUI30.BPL  Areaedit, Arrowedi, Axisincr, Axmaxmin, Baredit, Brushdlg, Bubbledi, Custedit, Dbeditch, Editchar, Flineedi, Ganttedi, Ieditcha, Pendlg, Pieedit, Shapeedi, Teeabout, Teegally, Teelisb, Teeprevi, Teexport
    VCLSMP30.BPL Sampreg, Smpconst

    Mimo tyto standardní balíčky, můžeme využívat uživatelské balíčky (balíčky, které jsme vytvořili sami nebo balíčky jiných výrobců). Např. jestliže máme statistický balíček nazvaný STATS.BPL a chceme jej používat, pak jej musíme přidat do seznamu používaných balíčků v okně Project Options.

  8. Návrhové balíčky jsou použity k instalování komponent na Paletu komponent a k vytváření speciálních editorů vlastností pro komponenty. V další tabulce jsou uvedeny návrhové balíčky, které jsou předinstalovány v IDE.

  9.  
    Balíček Stránky Palety komponent
    DCLSTD30.BPL  Standard, Additional, System, Win32, Dialogs
    DCLTEE30.BPL  Additional (komponenta TChart)
    DCLDB30.BPL  Data Access, Data Controls
    DCLMID30.BPL  Data Access (MIDAS)
    DCL31W30.BPL  Win 3.1
    DCLNET30.BPL
    NMFAST.BPL 
    Internet
    BCBSMP30.BPL  Samples
    DCLOCX30.BPL  ActiveX
    DCLQRT30.BPL  QReport
    DCLDSS30.BPL  Decision Cube
    IBSMP30.BPL  Samples (komponenta IBEventAlerter)
    DCLINT30.BPL  (International Tools—Resource DLL Wizard)

    Mimo předinstalovaných balíčků, můžeme instalovat své vlastní balíčky komponent nebo balíčky komponent jiných firem. Návrhový balíček DCLUSR30 je poskytnut jako implicitní kontejner pro nové komponenty.

  10. V C++ Builderu jsou všechny komponenty instalované v IDE jako balíčky. Jestliže vytváříme své vlastní komponenty, pak musíme vytvořit a přeložit balíček, který je obsahuje. K instalování nebo odinstalování svých vlastních komponent nebo komponent jiných firem, je potřeba provést následující kroky:
  11. Dokud nezměníme implicitní nastavení, pak nové projekty jsou vytvářeny se všemi dostupnými nainstalovanými balíčky. Současné volby uděláme implicitní pro nové projekty označením značky Default ve spodní části okna.
  12. Vytvoření balíčku znamená specifikovat jméno balíčku, seznam dalších balíčků, na které se balíček odkazuje a seznam jednotek, které mají být obsaženy v balíčku. Balíčky jsou definovány zdrojovým souborem (CPP) a speciálním vytvářecím souborem s příponou BPK. Tyto soubory jsou generovány Správcem projektu.

  13. Při vytváření balíčku postupujeme takto: volbou File | Close All uzavřeme všechny soubory a zvolíme File | New, vybereme ikonu Package a stiskneme OK (jsou vygenerovány soubory CPP a BPK). Uložíme balíček s novým jménem a volbou View | Project Makefile zobrazíme vygenerovaný vytvářecí soubor (BPK). Volbou View | Project Manager otevřeme Správce projektů. Ve správci projektu vidíme pro nový balíček uzly Requires a Contains. K přidání jednotek do seznamu Contains zvolíme Project | Add To Project, v dialogovém okně vybereme CPP soubor a stiskneme Open. Vybraná jednotka je zobrazena pod uzlen Contains ve Správci souborů. Tímto postupem můžeme přidat další jednotky.
    Pro přidání jednotek do seznamu Requires, je nutno editovat soubor CPP vygenerovaný při vytváření balíčku (soubor JménoBalíčku.CPP). Jelikož všechny balíčky vyžadují VCL30, nalezneme zde
    USEPACKAGE("vcl30.bpi");
    K vložení dalších balíčků do tohoto seznamu přidáme další obdobné příkazy do souboru CPP. Např. jestliže vyžadujeme DSS30, pak přidáme řádek
    USEPACKAGE("dss30.bpi");
    Když nyní přeložíme náš projekt, pak tyto nové balíčky jsou přidány k souboru BPK automaticky, ale nezobrazí se ve správci projektů dokud projekt neuzavřeme a opět neotevřeme.
    Dále zvolíme Project | Options a na stránce Description zadáme popis pro náš balíček. Na stejné stránce je ještě nutno určit o jaký typ balíčku se jedná (návrhový, běhový nebo oba). Nyní již lze balíček přeložit. Provedeme to volbou Project | Build.
  14. Editovat existující balíček lze několika způsoby. Např. otevřeme soubor BPK. Když máme otevřen projekt balíčků, pak již můžeme otevřít zdrojové soubory balíčku a provést jejich editaci.

  15. Hlavičkový soubor deklarace komponenty C++ Builderu musí obsahovat předdefinované makro PACKAGE za klíčovým slovem class:
    class PACKAGE MojeKomponenta: .....
    Toto makro je nutno také použít při implementaci funkce Register této komponenty:
    void __fastcall PACKAGE Register()
    Makro PACKAGE je rozvinuto na příkazy, které umožní třídě být importována a exportována ze souboru balíčku.
  16. Jména balíčků musí být unikátní v projektu. Pokud jméno zdrojového souboru balíčku je STATS.CPP, pak Správce projektu generuje vytvářecí soubor nazvaný STATS.BPK a překladem vzniká přeložený balíček, binární obraz a (volitelně) statická knihovna, které se jmenují STATS.BPL, STATS.BPIa STATS.LIB.

  17. Seznam Requires specifikuje další externí balíčky, které jsou použity současným balíčkem. Externí balíčky, které jsou zde uvedeny jsou automaticky sestaveny (při překladu) do aplikace. Pokud soubory jednotek našeho balíčku se odkazují na další zabalené jednotky, pak tyto další balíčky mají být uvedeny v seznamu Requires. Pokud je v seznamu Requires neuvedeme, pak odkazované jednotky jsou zaváděny normálním způsobem (bez souboru BPL). Balíčky nemohou v seznamu Requires obsahovat kruhové odkazy (balíček se nesmí odkazovat sám na sebe v seznamu Requires a řetězec odkazů musí končit bez odkazu na některý balíček v řetězu). Duplicitní odkazy v seznamu Requires jsou překladačem ignorovány.
    Seznam Contains určuje jednotky tvořící balíček. Do tohoto seznamu vkládáme soubory zdrojového kódu (CPP). Balíček se nemůže objevit v tomto seznamu pro jiný balíček. Všechny jednotky vložené přímo do seznamu Containts balíčku nebo nepřímo v těchto jednotkách jsou přeloženy do balíčku. Jednotky obsažené v balíčku (přímo i nepřímo) nemohou být v žádném jiném balíčku uvedeném v seznamu Requires tohoto balíčku.
16. Zpracování výjimek II