异常处理,WinRT C ++并发异步任务 [英] Exception handling, WinRT C++ concurrency async tasks
问题描述
我必须在C ++中实现一个异步HTTP GET,我们必须能够将应用程序提交到Windows 8商店。
我的问题如下:
我找到了一个合适的示例代码,它实现了一个HttpRequest类 http://code.msdn.microsoft.com/windowsapps/HttpClient-sample-55700664
此示例工作如果URI是正确的,但如果URI指向无效/不存在的地方(例如:www.google22.com),则会抛出异常。这将是罚款,如果我可以捕获异常,但我不能弄清楚如何或在哪里应该捕获它。
现在一些代码。
这是调用async,concurrency ::任务的方法抛出异常:
try {
...
Web :: HttpRequest httpRequest;
httpRequest.GetAsync(uri,cancellationTokenSource.get_token())
.then([](concurrency :: task< std :: wstring> response)
{
try {
response.get();
}
catch(...){
int i = 1;
}
返回响应;
})
...
} catch(...){
...
}
这是GetAsync方法的相关段(方法的结尾):
//返回在HTTP操作完成时完成的任务。
//我们将回调传递给延续,因为
//回调的生命周期必须超过操作,以确保取消
//正常工作。
return completionTask.then([this,stringCallback](tuple< HRESULT,wstring> resultTuple)
{
//如果GET操作失败,抛出一个异常
CheckHResult std :: get< 0>(resultTuple));
statusCode = stringCallback-> GetStatusCode();
reasonPhrase = stringCallback-> GetReasonPhrase();
return std :: get< 1>(resultTuple);
});
CheckHResult行抛出异常,代码如下:
inline void CheckHResult(HRESULT hResult)
{
if(hResult == E_ABORT)
{
concurrency :: cancel_current_task );
}
else if(FAILED(hResult))
{
throw Platform :: Exception :: CreateException(hResult);
}
}
我有一个try-catch GetAsync调用和我还在.then继续lambda中有一个try-catch。
在相关的Microsoft文档( http://msdn.microsoft.com/en-us/library/windows/apps/hh780559.aspx )it states任务抛出的异常应该可以在链中的下一个任务中捕获,但不知何故,它在我的情况下不工作。此外,即使整个调用的try-catch捕获异常,它只是滑过一切...
任何人有这个问题吗?我认为我已经尝试了官方文档中说明的一切,但它仍然允许异常去疯狂和崩溃的应用程序。我错过了什么?
编辑:
除了异常处理之外什么也不做,它仍然不捕获由.GetAsync中的任务抛出的异常
清理代码:
try
{
Windows :: Foundation :: Uri ^ uri;
uri = ref new Windows :: Foundation :: Uri(uri_string_to_fetch);
concurrency :: cancellation_token_source cancellationTokenSource = concurrency :: cancellation_token_source();
Web :: HttpRequest httpRequest;
OutputDebugString(L开始获取uri ... \\\
);
httpRequest.GetAsync(uri,cancellationTokenSource.get_token())
.then([](concurrency :: task< std :: wstring> response)
{
try {
response.get();
}
catch(...){
OutputDebugString(Lunknown Exception);
}
})
.then([](concurrency :: task< void> t)
{
try {
t.get();
// .get 't throw,所以我们成功了。
}
catch(Platform :: Exception ^ e){
// handle error
OutputDebugString(LPlatform :: Exception);
}
catch(...){
OutputDebugString(Lunknown Exception);
}
});
}
catch(Platform :: Exception ^ ex){
OutputDebugString(LPlatform :: Exception);
errorCallback(-1);
}
catch(...){
OutputDebugString(Lunknown Exception);
errorCallback(-2);
}
这仍然会导致异常消息崩溃:机会异常在0x75644B32在App1.exe:Microsoft C ++异常:Platform :: COMException ^在内存位置0x077EEC28。 HRESULT:0x800C0005
此外,当我在代码中放置一些断点时,它会显示异常在第一个.then被调用之前滑过。我在这些位置(在简化/清理代码中)设置断点:
- 在GetAsync调用之前
- 插入到GetAsync,到 CheckHResult(std :: get< 0>(resultTuple)); 行,将抛出异常
- try&catch case / block
执行顺序,使用断点测试:
<在GetAsync调用[OK]
和打印的调试日志,顺序:
- 开始获取uri ...
- 在App1.exe中的0x75644B32的第一次例外:Microsoft C ++异常:Platform :: COMException ^在内存位置0x082FEEF0。 HRESULT:0x800C0005
- 在App1.exe中0x75644B32的第一次例外:Microsoft C ++异常:[rethrow]在内存位置0x00000000。
- 在App1.exe中0x75644B32的第一次例外:Microsoft C ++异常:Platform :: COMException ^在内存位置0x082FE670。 HRESULT:0x800C0005
- 在App1.exe的0x75644B32的第一次例外:Microsoft C ++异常:Platform :: COMException ^在内存位置0x082FDD88。 HRESULT:0x800C0005
- 未知异常
发生了什么?
在并发运行时,在任务执行期间发生的任何未处理的异常将被推迟以供以后观察。这样,你可以在链接末尾添加一个基于任务的延续,并处理错误。
这样的东西:
httpRequest.GetAsync(uri,cancellationTokenSource.get_token())
.then([](concurrency :: task< std :: wstring> response)
{
try {
response.get();
}
catch(...){
int i = 1;
}
return response;
})
.then([](concurrency :: task< void> t)
{
try {
t.get ();
// .get()没有抛出,所以我们成功了
}
catch(Platform :: Exception :: CreateException ^ e){
// handle error
}
});
调用 .get
会触发任何异常在任务链(如果有)中提出。
有关详细信息,请参阅并发运行时中的异常处理。
I have to implement an async HTTP GET in C++ and we have to be able to submit the app to the Windows 8 Store.
My problem is the following:
I've found a suitable Sample code which implements an HttpRequest class http://code.msdn.microsoft.com/windowsapps/HttpClient-sample-55700664
This example works if the URI is correct but throws an exception if the URI points to an invalid / non existing place (like: www.google22.com). This would be fine if I could catch the exception but I cannot figure it out how or where should I catch it.
Now some code. This is the call to the async, concurrency::task based method which throws the exception:
try {
...
Web::HttpRequest httpRequest;
httpRequest.GetAsync(uri, cancellationTokenSource.get_token())
.then( [] (concurrency::task<std::wstring> response)
{
try {
response.get();
}
catch( ... ) {
int i = 1;
}
return response;
})
...
} catch ( ... ) {
...
}
And this is the relevant segment of the GetAsync method (the end of the method):
// Return a task that completes when the HTTP operation completes.
// We pass the callback to the continuation because the lifetime of the
// callback must exceed the operation to ensure that cancellation
// works correctly.
return completionTask.then([this, stringCallback](tuple<HRESULT, wstring> resultTuple)
{
// If the GET operation failed, throw an Exception.
CheckHResult(std::get<0>(resultTuple));
statusCode = stringCallback->GetStatusCode();
reasonPhrase = stringCallback->GetReasonPhrase();
return std::get<1>(resultTuple);
});
The CheckHResult line throws the exception, it's code:
inline void CheckHResult(HRESULT hResult)
{
if (hResult == E_ABORT)
{
concurrency::cancel_current_task();
}
else if (FAILED(hResult))
{
throw Platform::Exception::CreateException(hResult);
}
}
I have a try-catch around the GetAsync call and I also have a try-catch in the .then continuation lambda.
In the relevant Microsoft documentation ( http://msdn.microsoft.com/en-us/library/windows/apps/hh780559.aspx ) it states that exceptions thrown by a task should be catchable in the next task in the chain but somehow it doesn't work in my case. Additionally not even the try-catch around the whole call catches the exception, it just slips through everything...
Anyone had this problem? I think I've tried everything stated in the official documentations but it still lets the exception go berserk and crash the app. What do I miss?
EDIT:
I've modified the code to do nothing else but exception handling and it still doesn't catch the exception thrown by the task in .GetAsync
Cleaned-up code:
try
{
Windows::Foundation::Uri^ uri;
uri = ref new Windows::Foundation::Uri( uri_string_to_fetch );
concurrency::cancellation_token_source cancellationTokenSource = concurrency::cancellation_token_source();
Web::HttpRequest httpRequest;
OutputDebugString( L"Start to fetch the uri...\n" );
httpRequest.GetAsync(uri, cancellationTokenSource.get_token())
.then([](concurrency::task<std::wstring> response)
{
try {
response.get();
}
catch( ... ) {
OutputDebugString(L"unknown Exception");
}
})
.then([](concurrency::task<void> t)
{
try {
t.get();
// .get() didn't throw, so we succeeded.
}
catch (Platform::Exception^ e) {
// handle error
OutputDebugString(L"Platform::Exception");
}
catch (...) {
OutputDebugString(L"unknown Exception");
}
});
}
catch (Platform::Exception^ ex) {
OutputDebugString(L"Platform::Exception");
errorCallback(-1);
}
catch ( ... ) {
OutputDebugString(L"unknown Exception");
errorCallback(-2);
}
This still gives me a crash with the exception message: First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x077EEC28. HRESULT:0x800C0005
Additionally when I put some breakpoints in the code it shows that the exception slips through everything before the first .then would be called. I've put breakpoints in these locations (in the simplified / cleaned up code):
- before the GetAsync call
- into the GetAsync, to the CheckHResult(std::get<0>(resultTuple)); line which throws the exception
- into every try and catch case / block
Order of execution, tested with breakpoints:
- before the GetAsync call [OK]
- in the GetAsync, the line which will throw the exception [OK]
- now the app crashes, slips through every try-catch, continue
- now the line in the first .then gets called, in it's try block
- another app level exceptions not catched by any catch block
- now the first .then's catch block
- second .then method's try block
- and nothing more, the second .then's catch doesn't even catch any exception
And the printed debug logs, in order: - Start to fetch the uri... - First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x082FEEF0. HRESULT:0x800C0005 - First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000. - First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x082FE670. HRESULT:0x800C0005 - First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x082FDD88. HRESULT:0x800C0005 - unknown Exception
What is happening??
In the Concurrency Runtime any unhandled exception that occurs during the execution of a task is deferred for later observation. In this way, you could add a task based continuation at the end of the chain and handle errors there.
Something like this:
httpRequest.GetAsync(uri, cancellationTokenSource.get_token())
.then([](concurrency::task<std::wstring> response)
{
try {
response.get();
}
catch( ... ) {
int i = 1;
}
return response;
})
.then([](concurrency::task<void> t)
{
try {
t.get();
// .get() didn't throw, so we succeeded.
}
catch (Platform::Exception::CreateException^ e) {
// handle error
}
});
The call to .get
triggers any exceptions that were raised in the task chain (if any).
For more details you can read Exception Handling in the Concurrency Runtime.
这篇关于异常处理,WinRT C ++并发异步任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!