Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A COM HRESULT értékekkel jelzi egy metódus vagy függvényhívás sikerességét vagy sikertelenségét. A különböző SDK-fejlécek különböző HRESULT állandókat határoznak meg. A rendszerszintű kódok közös készletét a WinError.h határozza meg. Az alábbi táblázat néhány ilyen rendszerszintű visszatérési kódot mutat be.
| Konstans | Számérték | Leírás |
|---|---|---|
| Hozzáférés megtagadva | 0x80070005 | Hozzáférés megtagadva. |
| E_FAIL | 0x80004005 | Meghatározatlan hiba. |
| E_INVALIDARG | 0x80070057 | Érvénytelen paraméterérték. |
| E_OUTOFMEMORY | 0x8007000E | Nincs memóriája. |
| E_POINTER | 0x80004003 | NULL helytelenül lett átadva egy mutatóértékhez. |
| E_UNEXPECTED | 0x8000FFFF | Váratlan állapot. |
| S_OK | 0x0 | Sikeres. |
| S_FALSE | 0x1 | Siker. |
A "E_" előtaggal rendelkező összes állandó hibakód. A S_OK és S_FALSE állandók egyaránt sikerkódok. A COM-metódusok 99% valószínűleg sikeres S_OK térnek vissza; de ne hagyja, hogy ez a tény félrevezeti. Egy metódus más sikerkódokat is visszaadhat, ezért mindig tesztelje a hibákat a SIKERES vagy SIKERTELEN makró használatával. Az alábbi példakód a függvényhívás sikerességét tesztelő helytelen és helyes módszert mutatja be.
// Wrong.
HRESULT hr = SomeFunction();
if (hr != S_OK)
{
printf("Error!\n"); // Bad. hr might be another success code.
}
// Right.
HRESULT hr = SomeFunction();
if (FAILED(hr))
{
printf("Error!\n");
}
A sikerkód S_FALSE említést érdemel. Egyes módszerek S_FALSE körülbelül olyan negatív feltételt jelentenek, amely nem számít hibának. Azt is jelezheti, hogy "no-op" – a módszer sikeres volt, de nem volt hatása. A CoInitializeEx függvény például S_FALSE ad vissza, ha ugyanazt a szálat másodszor hívja meg. Ha meg kell különböztetnie a S_OK és a S_FALSE a kódban, közvetlenül tesztelje az értéket, de továbbra is használja a SIKERTELEN vagy SIKERES a fennmaradó esetek kezelésére, ahogyan az az alábbi példakódban látható.
if (hr == S_FALSE)
{
// Handle special case.
}
else if (SUCCEEDED(hr))
{
// Handle general success case.
}
else
{
// Handle errors.
printf("Error!\n");
}
Egyes HRESULT értékek a Windows egy adott funkciójára vagy alrendszerére vonatkoznak. A Direct2D grafikus API például a D2DERR_UNSUPPORTED_PIXEL_FORMAThibakódot határozza meg, ami azt jelenti, hogy a program nem támogatott képpontformátumot használt. A Windows dokumentációja gyakran felsorolja azokat a hibakódokat, amelyeket egy metódus visszaadhat. Ezeket a listákat azonban nem érdemes véglegesnek tekinteni. A metódusok mindig visszaadhatnak egy HRESULT értéket, amely nem szerepel a dokumentációban. Ismét használja a SIKERES és a SIKERTELEN makrókat. Ha egy adott hibakódot tesztel, adjon meg egy alapértelmezett esetet is.
if (hr == D2DERR_UNSUPPORTED_PIXEL_FORMAT)
{
// Handle the specific case of an unsupported pixel format.
}
else if (FAILED(hr))
{
// Handle other errors.
}
Hibakezelési minták
Ez a szakasz a COM-hibák strukturált kezelésére szolgáló néhány mintát mutat be. Minden minta rendelkezik előnyökkel és hátrányokkal. Bizonyos mértékig a választás ízlés kérdése. Ha egy meglévő projekten dolgozik, előfordulhat, hogy már rendelkezik olyan kódolási irányelvvel, amely egy adott stílust ír le. Függetlenül attól, hogy melyik mintát alkalmazza, a robusztus kód betartja a következő szabályokat.
- Minden olyan metódus vagy függvény esetében, amely egy HRESULTad vissza, ellenőrizze a visszatérési értéket a folytatás előtt.
- Erőforrások felszabadítása használat után.
- Ne próbáljon meg hozzáférni érvénytelen vagy nem inicializált erőforrásokhoz, például NULL mutatóihoz.
- A kiadás után ne próbáljon meg erőforrást használni.
Ezeket a szabályokat szem előtt tartva az alábbi négy minta használható a hibák kezelésére.
Beágyazott if-ek
Minden olyan hívás után, amely egy HRESULTad vissza, használjon az if utasítást a sikeresség teszteléséhez. Ezután helyezze a következő metódushívást a hatókörébe, a utasítás esetén. A if utasítások tetszőlegesen mélyen beágyazhatók, szükség szerint. A modul korábbi példakódjai mind ezt a mintát használták, de itt ismét a következő:
HRESULT ShowDialog()
{
IFileOpenDialog *pFileOpen;
HRESULT hr = CoCreateInstance(__uuidof(FileOpenDialog), NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpen));
if (SUCCEEDED(hr))
{
hr = pFileOpen->Show(NULL);
if (SUCCEEDED(hr))
{
IShellItem *pItem;
hr = pFileOpen->GetResult(&pItem);
if (SUCCEEDED(hr))
{
// Use pItem (not shown).
pItem->Release();
}
}
pFileOpen->Release();
}
return hr;
}
Előnye
- A változók minimális hatókörrel deklarálhatók. A pItem például csak akkor deklarálódik, ha használatban van.
- Minden egyes , ha utasításban bizonyos invariánsok igazak: az összes korábbi hívás sikeres volt, és az összes megszerzett erőforrás továbbra is érvényes. Az előző példában, amikor a program eléri a legbelső if utasítást, akkor mind a pItem, mind a pFileOpen ismert, hogy érvényesek.
- Egyértelmű, hogy mikor szabadít fel felületmutatókat és más erőforrásokat. Az erőforrást a végén szabadítja fel, amennyiben a utasítás közvetlenül követi az erőforrást megszerző hívást.
Hátrányai
- Néhány ember számára nehézséget okoz a mélyre ágyazott szerkezetek olvasása.
- A hibakezelés más elágaztatási és hurkolási utasításokkal keveredik. Ez megnehezítheti az általános programlogika követését.
Kaszkádolt ifs
Minden metódushívás után használjon egy , ha utasítást a sikeresség tesztelésére. Ha a metódus sikeres, helyezze a következő metódushívást a blokkba, ha a feltétel teljesül. De ahelyett, hogy további ágyaz be, ha utasításokat, helyezzen minden további SIKERES tesztet az előző után, ha blokkot. Ha bármelyik módszer meghiúsul, a többi SIKERES tesztek egyszerűen meghiúsulnak, amíg el nem éri a függvény alját.
HRESULT ShowDialog()
{
IFileOpenDialog *pFileOpen = NULL;
IShellItem *pItem = NULL;
HRESULT hr = CoCreateInstance(__uuidof(FileOpenDialog), NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpen));
if (SUCCEEDED(hr))
{
hr = pFileOpen->Show(NULL);
}
if (SUCCEEDED(hr))
{
hr = pFileOpen->GetResult(&pItem);
}
if (SUCCEEDED(hr))
{
// Use pItem (not shown).
}
// Clean up.
SafeRelease(&pItem);
SafeRelease(&pFileOpen);
return hr;
}
Ebben a mintában a függvény végén szabadít fel erőforrásokat. Hiba esetén előfordulhat, hogy egyes mutatók érvénytelenek lesznek, amikor a függvény kilép. A kiadási érvénytelen mutatóra hívása összeomlik a program (vagy rosszabb), ezért az összes mutatót inicializálnia kell, hogy NULL, és mielőtt felengedné őket, ellenőrizze, hogy NULL-e. Ez a példa a SafeRelease függvényt használja; az intelligens mutatók szintén jó választásnak számítanak.
Ha ezt a mintát használja, óvatosnak kell lennie a ciklusszerkezetekkel. A cikluson belül szakítsa meg a ciklust, ha bármilyen hívás meghiúsul.
Előnye
- Ez a minta kevesebb beágyazást hoz létre, mint a "beágyazott if feltételek" minta.
- Az általános vezérlési folyamat könnyebben látható.
- Az erőforrások a kód egy pontján jelennek meg.
Hátrányai
- Minden változót deklarálni és inicializálni kell a függvény tetején.
- Ha egy hívás meghiúsul, a függvény több szükségtelen hibaellenőrzést végez ahelyett, hogy azonnal kilépne a függvényből.
- Mivel a vezérlés folyamata egy hiba után is folytatódik a függvényen keresztül, óvatosnak kell lennie a függvény teljes törzsében, hogy ne férjen hozzá érvénytelen erőforrásokhoz.
- A cikluson belüli hibák speciális esetet igényelnek.
Ugrás sikertelenre
Minden metódushívás után ellenőrizze, hogy nem történt-e hiba. Hiba esetén ugorjon egy címkére a függvény alján. A címke után, de a függvényből való kilépés előtt engedje fel az erőforrásokat.
HRESULT ShowDialog()
{
IFileOpenDialog *pFileOpen = NULL;
IShellItem *pItem = NULL;
HRESULT hr = CoCreateInstance(__uuidof(FileOpenDialog), NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpen));
if (FAILED(hr))
{
goto done;
}
hr = pFileOpen->Show(NULL);
if (FAILED(hr))
{
goto done;
}
hr = pFileOpen->GetResult(&pItem);
if (FAILED(hr))
{
goto done;
}
// Use pItem (not shown).
done:
// Clean up.
SafeRelease(&pItem);
SafeRelease(&pFileOpen);
return hr;
}
Előnye
- Az általános vezérlési folyamat könnyen áttekinthető.
- Ha a címkére nem ugrott, akkor garantált, hogy a kód minden pontján a FAILED ellenőrzést követően az összes korábbi hívás sikeres volt.
- Az erőforrások a kódban egy helyen szabadulnak fel.
Hátrányai
- Minden változót deklarálni és inicializálni kell a függvény tetején.
- Egyes programozók nem szeretik goto használni a kódjukban. (Meg kell azonban jegyezni, hogy a goto használata erősen strukturált; a kód soha nem ugrik ki az aktuális függvényhíváson.)
- goto utasítások kihagyják az inicializálókat.
Sikertelen dobás
Ahelyett, hogy egy utalóra ugorjon, kivételt dobhat, ha egy metódus meghibásodik. Ez idiomatikusabb C++ stílust eredményezhet, ha a kivételmentes kód írásához használják.
#include <comdef.h> // Declares _com_error
inline void throw_if_fail(HRESULT hr)
{
if (FAILED(hr))
{
throw _com_error(hr);
}
}
void ShowDialog()
{
try
{
CComPtr<IFileOpenDialog> pFileOpen;
throw_if_fail(CoCreateInstance(__uuidof(FileOpenDialog), NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpen)));
throw_if_fail(pFileOpen->Show(NULL));
CComPtr<IShellItem> pItem;
throw_if_fail(pFileOpen->GetResult(&pItem));
// Use pItem (not shown).
}
catch (_com_error err)
{
// Handle error.
}
}
Figyelje meg, hogy ez a példa a CComPtr osztályt használja a felületmutatók kezeléséhez. Ha a kód kivételeket jelez, általában a RAII (Resource Acquisition is Initialization) mintát kell követnie. Ez azt jelenti, hogy minden erőforrást egy olyan objektumnak kell felügyelnie, amelynek a destruktora garantálja az erőforrás megfelelő kiadását. Kivétel esetén a destruktor meghívása garantált. Ellenkező esetben előfordulhat, hogy a program kiszivárogtatja az erőforrásokat.
Előnye
- Kompatibilis a kivételkezelést használó meglévő kóddal.
- Kompatibilis a kivételeket okozó C++ kódtárakkal, például a standard sablontárral (STL).
Hátrányai
- Az erőforrások, mint például a memória vagy a fájlleírók kezeléséhez C++ objektumokra van szükség.
- A kivételmentes kód írásához alapos ismeretekre van szükség.
Következő