예외(C++/CX)

C++/CX의 오류 처리는 예외를 기반으로 합니다. 가장 기본적인 수준에서 Windows 런타임 구성 요소는 오류를 HRESULT 값으로 보고합니다. C++/CX에서 이러한 값은 HRESULT 값과 프로그래밍 방식으로 액세스할 수 있는 문자열 설명을 포함하는 강력한 형식의 예외로 변환됩니다. 예외는 ref class 에서 파생된 Platform::Exception로 구현됩니다. Platform 네임스페이스는 가장 일반적인 HRESULT 값에 대한 고유한 예외 클래스를 정의합니다. 다른 모든 값은 Platform::COMException 클래스를 통해 보고됩니다. 모든 예외 클래스에는 원래 HRESULT를 검색하는 데 사용할 수 있는 Exception::HResult 필드가 있습니다. 또한 C++가 아닌 언어로 작성된 코드에서 발생하더라도 예외의 원래 원본을 정확히 파악하는 데 도움이 되는 디버거의 사용자 코드에 대한 호출 스택 정보를 검사할 수 있습니다.

예외

C++ 프로그램에서는 Windows 런타임 작업, 파생된 예외 또는 사용자 정의 형식에서 std::exception발생하는 예외를 throw하고 catch할 수 있습니다. 예외를 catch하는 코드가 JavaScript로 작성된 경우와 같이 ABI(애플리케이션 이진 인터페이스) 경계를 넘을 때만 Windows 런타임 예외를 throw해야 합니다. 비 Windows 런타임 C++ 예외가 ABI 경계에 도달하면 예외가 예외로 Platform::FailureException 변환되어 E_FAIL HRESULT를 나타냅니다. ABI에 대한 자세한 내용은 Creating Windows Runtime Components in C++를 참조하세요.

HRESULT 매개 변수를 사용하는 두 생성자 중 하나 또는 HRESULT 매개 변수와 ABI를 통해 이를 처리하는 Windows 런타임 앱에 전달할 수 있는 Platform::String^ 매개 변수 중 하나를 사용하여 Platform::Exception을 선언할 수 있습니다. HRESULT 매개 변수 또는 HRESULT 매개 변수와 매개 변수를 사용하는 두 Exception::CreateException 메서드 Platform::String^ 오버로드 중 하나를 사용하여 예외를 선언할 수도 있습니다.

표준 예외

C++/CX는 일반적인 HRESULT 오류를 나타내는 표준 예외 집합을 지원합니다. 각 표준 예외는 Platform::COMException에서 파생되고, 이는 Platform::Exception에서 파생됩니다. ABI 경계를 넘어 예외를 throw할 경우 표준 예외 중 하나를 throw해야 합니다.

사용자 고유의 예외 형식은 Platform::Exception에서 파생할 수 없습니다. 사용자 지정 예외를 throw하려면 사용자 정의 HRESULT를 사용하여 COMException 개체를 생성하세요.

다음 표에서는 표준 예외를 보여 줍니다.

이름 내부 HRESULT 설명
COMException 사용자 정의 hresult COM 메서드 호출에서 인식할 수 없는 HRESULT가 반환되는 경우에 throw됩니다.
AccessDeniedException E_ACCESSDENIED 리소스 또는 기능에 대한 액세스가 거부된 경우 throw됩니다.
ChangedStateException E_CHANGED_STATE 부모 컬렉션이 변경된 후 컬렉션 반복기 또는 컬렉션 뷰의 메서드가 호출되어 메서드 결과가 무효화되면 throw됩니다.
ClassNotRegisteredException REGDB_E_CLASSNOTREG COM 클래스가 등록되지 않은 경우 throw됩니다.
DisconnectedException RPC_E_DISCONNECTED 개체와 클라이언트의 연결이 끊기면 throw됩니다.
FailureException E_FAIL 작업이 실패하면 throw됩니다.
InvalidArgumentException E_INVALIDARG 메서드에 제공된 인수 중 하나가 유효하지 않을 때 throw됩니다.
InvalidCastException E_NOINTERFACE 형식이 다른 형식에 대한 캐스트가 될 수 없는 경우 throw됩니다.
NotImplementedException E_NOTIMPL 클래스에 인터페이스 메서드가 구현되어 있지 않은 경우 throw됩니다.
NullReferenceException E_POINTER null 개체 참조를 역참조하려고 할 때 throw됩니다.
ObjectDisposedException RO_E_CLOSED 삭제된 개체에서 연산이 수행될 때 throw됩니다.
OperationCanceledException E_ABORT 작업이 중단되면 throw됩니다.
OutOfBoundsException E_BOUNDS 작업이 유효한 범위를 벗어난 데이터에 액세스하려고 하면 throw됩니다.
OutOfMemoryException E_OUTOFMEMORY 메모리가 부족하여 작업을 완료할 수 없는 경우 throw됩니다.
WrongThreadException RPC_E_WRONG_THREAD 프록시 개체용 인터페이스 포인터를 통해 스레드의 아파트에 속하지 않는 스레드가 호출될 경우 throw됩니다.

HResult 및 Message 속성

모든 예외에는 HResult 속성과 Message 속성이 있습니다. Exception::HResult 속성은 예외의 내부 숫자 HRESULT 값을 가져옵니다. Exception::Message 속성은 예외를 설명하는 시스템 제공 문자열을 가져옵니다. Windows 8에서 메시지는 디버거에서만 사용할 수 있으며 읽기 전용입니다. 즉, 예외를 다시 throw할 때 변경할 수 없습니다. Windows 8.1에서 이 메시지 문자열을 프로그래밍 방식으로 액세스하고 해당 예외를 다시 throw하는 경우 새 메시지를 제공할 수 있습니다. 비동기 메서드 호출에 대한 호출 스택을 포함하여 디버거에서 보다 나은 호출 스택 정보를 사용할 수 있습니다.

예제

이 예제에서는 동기 작업에 대한 Windows 런타임 예외를 throw하는 방법을 보여 줍니다.

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);
}

다음 예제에서는 예외를 catch하는 방법을 보여 줍니다.

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());
    //...
}

비동기 작업 중에 throw되는 예외를 catch하려면 작업 클래스를 사용하고 오류 처리 연속 작업을 추가합니다. 오류 처리 연속은 다른 스레드에서 throw된 예외를 다시 호출 스레드로 마샬링하므로 모든 잠재적 예외를 코드의 한 지점에서 처리할 수 있습니다. 자세한 내용은 C++의 비동기 프로그래밍을 참조하세요.

UnhandledErrorDetected 이벤트

Windows 8.1에서는 프로세스를 중단하려는 처리되지 않은 오류에 대한 액세스를 제공하는 Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected 정적 이벤트를 구독할 수 있습니다. 오류가 발생한 위치와 관계없이 이벤트 인수와 함께 전달되는 Windows::ApplicationModel::Core::UnhandledError 개체로 이 처리기에 수신됩니다. 개체에서 Propagate 를 호출하면 해당 개체가 오류 코드에 해당하는 형식의 Platform::*Exception 을 만들고 throw합니다. Catch 블록에서는 필요한 경우 사용자 상태를 저장할 수 있으며, 그런 다음 throw를 호출하여 프로세스가 종료되도록 허용하거나 프로그램을 알려진 상태로 되돌리기 위한 작업을 수행합니다. 다음 예제에서는 기본 패턴을 보여 줍니다.

app.xaml.h에서:

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

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
    }
}

설명

C++/CX는 절을 finally 사용하지 않습니다.

참고 항목

C++/CX 언어 참조
네임스페이스 참조