例外狀況 (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
的例外狀況或使用者定義型別。 只有當例外狀況跨越應用程式二進位介面 (ABI) 界限時,您才必須擲回 Windows 執行階段 例外狀況,例如,當攔截例外狀況的程序代碼是以 JavaScript 撰寫時。 當非 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 界限的例外狀況時,您必須擲回其中一個標準例外狀況。
您無法從 Platform::Exception
衍生您自己的例外狀況型別。 若要擲回自訂例外狀況,請透過使用者定義的 HRESULT 來建構 COMException
物件。
下表列出標準例外狀況。
名稱 | 基礎 HRESULT | 描述 |
---|---|---|
COMException | 使用者定義的 HRESULT | 在 COM 方法呼叫傳回無法辨認的 HRESULT 時擲回。 |
AccessDeniedException | E_ACCESSDENIED | 在存取資源或功能遭拒時擲回。 |
ChangedStateException | E_CHANGED_STATE | 在父集合變更後呼叫集合迭代器或集合檢視的方法時擲回,藉以讓該方法的結果失效。 |
ClassNotRegisteredException | REGDB_E_CLASSNOTREG | 在 COM 類別未登錄時擲回。 |
DisconnectedException | RPC_E_DISCONNECTED | 在物件與用戶端的連接中斷時擲回。 |
FailureException | E_FAIL | 在作業失敗時擲回。 |
InvalidArgumentException | E_INVALIDARG | 在其中一個提供給方法的引數無效時擲回。 |
InvalidCastException | E_NOINTERFACE | 在類型無法轉換成另一種類型時擲回。 |
NotImplementedException | E_NOTIMPL | 在介面方法未於類別上實作時擲回。 |
NullReferenceException | E_POINTER | 在嘗試解除 Null 物件的參考時擲回。 |
ObjectDisposedException | RO_E_CLOSED | 在已處置的物件上執行作業時擲回。 |
OperationCanceledException | E_ABORT | 在作業中止時擲回。 |
OutOfBoundsException | E_BOUNDS | 在作業嘗試存取有效範圍以外的資料時擲回。 |
OutOfMemoryException | E_OUTOFMEMORY | 在沒有足夠的記憶體可完成作業時擲回。 |
WrongThreadException | RPC_E_WRONG_THREAD | 在執行緒透過不屬於其 Apartment 之 Proxy 物件的介面指標進行呼叫時擲回。 |
HResult 屬性與 Message 屬性
所有例外狀況都有 HResult 屬性和 Message 屬性。 Exception::HResult 屬性會取得例外狀況的基礎數值 HRESULT 值。 Exception::Message 屬性會取得系統提供用以說明例外狀況的字串。 在 Windows 8 中,訊息只能在調試程式中使用,而且是唯讀的。 這表示當您重新擲回例外狀況時,無法加以變更。 在 Windows 8.1 中,如果重新擲回例外狀況,可以透過程式設計方式存取訊息字串並提供新的訊息。 偵錯工具中也提供更好的呼叫堆疊資訊,包括非同步方法呼叫的呼叫堆疊。
範例
此範例示範如何擲回同步作業的 Windows 執行階段 例外狀況:
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);
}
下一個範例說明如何攔截例外狀況。
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());
//...
}
若要攔截異步操作期間擲回的例外狀況,請使用工作類別並新增錯誤處理接續。 錯誤處理接續工作會將其他執行緒上擲回的例外狀況封送回呼叫端執行緒,讓您在程式碼中的單一位置上即可處理所有可能的例外狀況。 如需詳細資訊,請參閱 使用 C++ 進行非同步程式設計。
UnhandledErrorDetected 事件
在 Windows 8.1 中,您可以訂閱 Windows::ApplicationModel::Core::CoreApplication::UnhandledErrorDetected 靜態事件,以存取即將關閉進程的未處理錯誤。 不論錯誤源自何處,它都會以透過事件引數傳入的 Windows::ApplicationModel::Core::UnhandledError 物件形式,到達這個處理常式。 當您針對物件呼叫 Propagate
時,它會建立及擲回對應至錯誤代碼類型的 Platform::*Exception
。 在 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
子句。