Я должен реализовать асинхронный HTTP GET в C ++, и мы должны иметь возможность отправить приложение в Windows 8 Store.
Моя проблема заключается в следующем:
Я нашел подходящий пример кода, который реализует класс HttpRequest http://code.msdn.microsoft.com/windowsapps/HttpClient-sample-55700664
Этот пример работает, если URI правильный, но выдает исключение, если URI указывает на недопустимое / несуществующее место (например, www.google22.com). Это было бы хорошо, если бы я мог поймать исключение, но я не могу понять, как или где я должен его поймать.
Теперь немного кода.
Это вызов асинхронного метода concurrency :: task, который выдает исключение:
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);
}
}
У меня есть try-catch вокруг вызова GetAsync, и у меня также есть try-catch в лягбда-продолжении .then.
В соответствующей документации Microsoft ( http://msdn.microsoft.com/en-us/library/windows/apps/hh780559.aspx ) в нем говорится, что исключения, сгенерированные задачей, должны быть отслеживаемыми в следующей задаче в цепочке, но как-то это не работает в моем случае. Кроме того, даже попытка перехватить весь вызов не ловит исключение, она просто проскальзывает через все …
У кого-нибудь была эта проблема? Я думаю, что перепробовал все, что указано в официальной документации, но это все еще позволяет исключению сходить с ума и вылетать из приложения. Что мне не хватает?
РЕДАКТИРОВАТЬ:
Я изменил код, чтобы ничего не делать, кроме обработки исключений, и он все еще не перехватывает исключение, выданное задачей в .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: 0x800C0005
Кроме того, когда я ставлю некоторые точки останова в коде, это показывает, что исключение проскальзывает через все, прежде чем будет вызван первый .hen. Я установил точки останова в этих местах (в упрощенном / очищенном коде):
Порядок исполнения, проверенный с контрольными точками:
И распечатаны журналы отладки, по порядку:
— Начни получать ури …
— Исключение первого шанса в 0x75644B32 в App1.exe: исключение Microsoft C ++: платформа :: COMException ^ в ячейке памяти 0x082FEEF0. HRESULT: 0x800C0005
— Исключение первого шанса в 0x75644B32 в App1.exe: исключение Microsoft C ++: [rethrow] в расположении памяти 0x00000000.
— Исключение первого шанса в 0x75644B32 в App1.exe: исключение Microsoft C ++: платформа :: COMException ^ в ячейке памяти 0x082FE670. HRESULT: 0x800C0005
— Исключение первого шанса в 0x75644B32 в App1.exe: исключение Microsoft C ++: платформа :: 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() didn't throw, so we succeeded.
}
catch (Platform::Exception::CreateException^ e) {
// handle error
}
});
Призыв к .get
запускает любые исключения, которые возникли в цепочке задач (если есть).
Для более подробной информации вы можете прочитать Обработка исключений в параллельной среде выполнения.
Эта связанная тема может иметь подсказку:
Неуправляемый код Visual C ++: использовать исключения / EHa или / EHsc для C ++?
Если вы хотите перехватить все асинхронные исключения, вы можете попытаться установить для свойства «Свойства конфигурации» -> C / C ++ -> Code Generation значение «Да с исключениями SEH (/ EHa)»