异常处理,WinRT c++并发异步任务



我必须在c++中实现异步HTTP GET,我们必须能够将应用程序提交到Windows 8商店。

我的问题如下:

我找到了一个合适的示例代码,实现了一个HttpRequest类http://code.msdn.microsoft.com/windowsapps/HttpClient-sample-55700664

如果URI是正确的,这个例子可以工作,但是如果URI指向无效/不存在的位置(如:www.google22.com),则抛出异常。如果我能捕获异常,这将是很好的,但我不知道如何或在哪里捕获它。

现在一些代码。这是对异步、基于并发::任务的方法的调用,该方法会抛出异常:

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

这是GetAsync方法的相关片段(方法的结尾):

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

CheckHResult行抛出异常,它的代码是:

inline void CheckHResult(HRESULT hResult)
{
if (hResult == E_ABORT)
{
    concurrency::cancel_current_task();
}
else if (FAILED(hResult))
{
    throw Platform::Exception::CreateException(hResult);
}
}

我有一个围绕GetAsync调用的try-catch,我也有一个在.then延续lambda中的try-catch。

在相关的微软文档(http://msdn.microsoft.com/en-us/library/windows/apps/hh780559.aspx)中,它指出任务抛出的异常应该在链中的下一个任务中可捕获,但不知何故它在我的情况下不起作用。此外,甚至整个调用周围的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"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);
}

这仍然给我一个崩溃的异常消息:第一次机会异常在0x75644B32在App1.exe: Microsoft c++异常:平台::COMException ^在内存位置0x077EEC28。HRESULT: 0 x800c0005

另外,当我在代码中放置一些断点时,它显示异常在第一个。then将被调用之前通过所有内容。我在这些位置放置了断点(在简化/清理后的代码中):

    GetAsync调用前的
  • 到GetAsync,到CheckHResult(std::get<0>(resultTuple));行,抛出异常
  • 到每个try and catch case/block

执行顺序,用断点测试:

  1. 在GetAsync调用[OK]之前
  2. 在GetAsync中
  3. ,将抛出异常的行[OK]
  4. 现在应用程序崩溃,滑过每个try-catch,继续
  5. 现在在第一个行。然后被调用,在try块
  6. 另一个未被任何catch块捕获的应用级异常
  7. 现在是第一。然后的catch块
  8. second .then方法的try block
  9. ,仅此而已,第二个。那么的catch甚至没有捕捉到任何异常

和打印的调试日志,依次为:-开始获取uri…- App1.exe中0x75644B32的第一次机会异常:Microsoft c++异常:Platform::COMException ^ at memory location 0x082FEEF0。HRESULT: 0 x800c0005- App1.exe中的0x75644B32第一次机会异常:Microsoft c++异常:[rethrow] at memory location 0x00000000。- App1.exe中的第一次机会异常0x75644B32: Microsoft c++异常:Platform::COMException ^ at memory location 0x082FE670。HRESULT: 0 x800c0005- App1.exe中0x75644B32的第一次机会异常:Microsoft c++异常:Platform::COMException ^ at memory location 0x082FDD88。HRESULT: 0 x800c0005- unknown Exception

发生什么事了?

在并发运行时中,任何在任务执行期间发生的未处理的异常都被延迟以供以后观察。通过这种方式,您可以在链的末尾添加基于任务的延续,并在那里处理错误。

像这样:

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

.get的调用触发任务链中引发的任何异常(如果有的话)。有关详细信息,请参阅并发运行时中的异常处理。

这个相关的线程可能有一个线索:Visual c++非托管代码:使用/EHa或/EHsc处理c++异常?

如果你想捕获所有异步异常,你可以尝试将配置属性-> C/c++ ->代码生成属性设置为"Yes with SEH exceptions (/EHa)"。

最新更新