Dela via


Undantag (C++/CX)

Felhantering i C++/CX baseras på undantag. På den mest grundläggande nivån rapporterar Windows Runtime-komponenter fel som HRESULT-värden. I C++/CX konverteras dessa värden till starkt skrivna undantag som innehåller ett HRESULT-värde och en strängbeskrivning som du kan komma åt programmatiskt. Undantag implementeras som en ref class som härleds från Platform::Exception. Namnområdet Platform definierar distinkta undantagsklasser för de vanligaste HRESULT-värdena. Alla andra värden rapporteras via Platform::COMException klassen. Alla undantagsklasser har ett Undantag::HResult-fält som du kan använda för att hämta den ursprungliga HRESULT. Du kan också undersöka information om anropsstack för användarkod i felsökningsprogrammet som kan hjälpa dig att hitta den ursprungliga källan till undantaget, även om den har sitt ursprung i kod som har skrivits på ett annat språk än C++.

Exceptions

I C++-programmet kan du utlösa och fånga ett undantag som kommer från en Windows Runtime-åtgärd, ett undantag som härleds från std::exceptioneller en användardefinierad typ. Du behöver bara utlösa ett Windows Runtime-undantag när det kommer att korsa gränsen för program binärt gränssnitt (ABI), till exempel när koden som fångar ditt undantag skrivs i JavaScript. När ett C++-undantag för icke-Windows Runtime når ABI-gränsen översätts undantaget till ett Platform::FailureException undantag som representerar en E_FAIL HRESULT. Mer information om ABI finns i Skapa Windows Runtime-komponenter i C++.

Du kan deklarera en Plattform::Undantag genom att använda en av två konstruktorer som antingen tar en HRESULT-parameter eller en HRESULT-parameter och en Platform::String^-parameter som kan skickas över ABI till alla Windows Runtime-appar som hanterar den. Eller så kan du deklarera ett undantag med hjälp av ett av två undantag::CreateException-metodöverlagringar som tar antingen en HRESULT-parameter eller en HRESULT-parameter och en Platform::String^ parameter.

Standardfel

C++/CX stöder en uppsättning standardfel som representerar typiska HRESULT-fel. Varje standardundantag härleds från Platform::COMException, som i sin tur härleds från Platform::Exception. När du utlöser ett undantag över ABI-gränsen måste du utlösa ett av standardfelen.

Du kan inte härleda din egen undantagstyp från Platform::Exception. Om du vill skapa ett anpassat undantag använder du en användardefinierad HRESULT för att konstruera ett COMException objekt.

I följande tabell visas standardfelen.

Namn Underliggande HRESULT Beskrivning
COMException användardefinierad hresult- Utlöses när en okänd HRESULT returneras från ett COM-metodanrop.
AccessDeniedException E_ACCESSDENIED Genereras när åtkomst nekas till en resurs eller funktion.
ChangedStateException E_TILLSTÅND_FÖRÄNDRAT Utlöses när metoder för en samlingsiterator eller en samlingsvy anropas efter att den överordnade samlingen har ändrats, vilket gör metodens resultat ogiltiga.
ClassNotRegisteredException REGDB_E_CLASSNOTREG Utlöses när en COM-klass inte har registrerats.
DisconnectedException RPC_E_DISCONNECTED Utlöses när ett objekt kopplas från från sina klienter.
FailureException E_FAIL Utlöses när en åtgärd misslyckas.
InvalidArgumentException E_INVALIDARG Utlöses när ett av argumenten som tillhandahålls till en metod inte är giltigt.
InvalidCastException E_NOINTERFACE Utlöses när en typ inte kan kastas till en annan typ.
NotImplementedException E_NOTIMPL Utlöses om en gränssnittsmetod inte har implementerats på en klass.
NullReferenceException E_POINTER Utlöses när det görs ett försök att avreferensen till en null-objektreferens.
ObjectDisposedException RO_E_CLOSED Utlöses när en åtgärd utförs på ett borttaget objekt.
OperationCanceledException E_ABORT Utlöses när en åtgärd avbryts.
OutOfBoundsException E_BOUNDS Utlöses när en åtgärd försöker komma åt data utanför det giltiga intervallet.
OutOfMemoryException E_OUTOFMEMORY Utlöses när det inte finns tillräckligt med minne för att slutföra åtgärden.
WrongThreadException RPC_E_WRONG_THREAD Utlöses när en tråd anropar via en gränssnittspekare som är för ett proxyobjekt som inte tillhör trådens lägenhet.

Egenskaper för HResult och Meddelande

Alla undantag har en HResult-egenskap och en meddelandeegenskap . Egenskapen Exception::HResult hämtar undantagets underliggande numeriska HRESULT-värde. Egenskapen Exception::Message hämtar den systemspecifika strängen som beskriver undantaget. I Windows 8 är meddelandet endast tillgängligt i felsökningsprogrammet och är skrivskyddat. Det innebär att du inte kan ändra det när du ändrar undantaget. I Windows 8.1 kan du komma åt meddelandesträngen programmatiskt och ange ett nytt meddelande om du ändrar undantaget. Bättre samtalstackinformation finns också i felsökningsprogrammet, inklusive anropstackar för asynkrona metodanrop.

Exempel

Det här exemplet visar hur du genererar ett Windows Runtime-undantag för synkrona åtgärder:

String^ Class1::MyMethod(String^ argument)
{
    
    if (argument->Length() == 0) 
    { 
        auto e = ref new Exception(-1, "I'm Zork bringing you this message from across the ABI.");
        //throw ref new InvalidArgumentException();
        throw e;
    }
    
    return MyMethodInternal(argument);
}

I nästa exempel visas hur du fångar undantaget.

void Class2::ProcessString(String^ input)
{
    String^ result = nullptr;    
    auto obj = ref new Class1();

    try 
    {
        result = obj->MyMethod(input);
    }

    catch (/*InvalidArgument*/Exception^ e)
    {
        // Handle the exception in a way that's appropriate 
        // for your particular scenario. Assume
        // here that this string enables graceful
        // recover-and-continue. Why not?
        result = ref new String(L"forty two");
        
        // You can use Exception data for logging purposes.
        Windows::Globalization::Calendar calendar;
        LogMyErrors(calendar.GetDateTime(), e->HResult, e->Message);
    }

    // Execution continues here in both cases.
    //#include <string>
    std::wstring ws(result->Data());
    //...
}

Om du vill fånga undantag som utlöses under en asynkron åtgärd använder du aktivitetsklassen och lägger till en fortsättning för felhantering. Undantag för felhantering av fortsättningsmarskalkar som genereras på andra trådar tillbaka till den anropande tråden så att du kan hantera alla potentiella undantag vid bara en punkt i koden. Mer information finns i Asynkron programmering i C++.

UnhandledErrorDetected-händelse

I Windows 8.1 kan du prenumerera på den statiska händelsen Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected , som ger åtkomst till ohanterade fel som håller på att få ner processen. Oavsett var felet uppstod når den den här hanteraren som ett Windows::ApplicationModel::Core::UnhandledError-objekt som skickas in med händelsen args. När du anropar Propagate objektet skapas och genereras en Platform::*Exception av den typ som motsvarar felkoden. I catch-blocken kan du spara användartillståndet om det behövs och sedan antingen tillåta att processen avslutas genom att anropa throweller göra något för att få programmet tillbaka till ett känt tillstånd. I följande exempel visas det grundläggande mönstret:

I app.xaml.h:

void OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e);

I app.xaml.cpp:

// Subscribe to the event, for example in the app class constructor:
Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected += ref new EventHandler<UnhandledErrorDetectedEventArgs^>(this, &App::OnUnhandledException);

// Event handler implementation:
void App::OnUnhandledException(Platform::Object^ sender, Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs^ e)
{
    auto err = e->UnhandledError;

    if (!err->Handled) //Propagate has not been called on it yet.
{
    try
    {
        err->Propagate();
    }
    // Catch any specific exception types if you know how to handle them
    catch (AccessDeniedException^ ex)
    {
        // TODO: Log error and either take action to recover
        // or else re-throw exception to continue fail-fast
    }
}

Anmärkningar

C++/CX använder finally inte -satsen.

Se även

C++/CX-språkreferens
referens för namnområden