InternetOpenUrl处于异步模式
InternetOpenUrl in asynchronous mode
我有一个使用WinINet函数异步下载文件的函数。我使用的方法是:
- InternetOpen
- Internet设置状态回调
- InternetOpenUrl(同步)
- InternetReadFileEx(异步)
- InternetReadFileEx在回调函数中,直到接收到的缓冲区为0
如何等待InternetOpenUrl
完成,以便返回的句柄有效?如果我运行InternetOpenUrl
异步,由于可能的重定向,我无法判断何时收到最后一个INTERNET_STATUS_RESPONSE_RECEIVED
。此外,当InternetOpenUrl
完成时,我想用INTERNET_OPTION_URL
标志调用InternetQueryOption
,以在所有重定向(如果有的话)后获得最终URL。
std::vector<DOWNLOAD_CONTEXT> contexts;
void Download(TCHAR *url, unsigned int crc32, unsigned int length)
{
HINTERNET hInternet = InternetOpen(_T("Test"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
InternetSetStatusCallback(hInternet, DownloadProgress);
DOWNLOAD_CONTEXT context;
context.hInternet = hInternet;
contexts.push_back(context);
HINTERNET hUrl = InternetOpenUrl(hInternet, url, _T(""), 0, INTERNET_FLAG_RELOAD, DWORD_PTR(&*(contexts.end()-1)));
/* if InternetOpenUrl would have been executed in blocking mode,
here I would have executed the first async InternetReadFileEx,
and InternetQueryOption to get the final URL*/
}
void CALLBACK DownloadProgress(
_In_ HINTERNET hInternet,
_In_ DWORD_PTR dwContext,
_In_ DWORD dwInternetStatus,
_In_ LPVOID lpvStatusInformation,
_In_ DWORD dwStatusInformationLength
)
{
DOWNLOAD_CONTEXT *context = (DOWNLOAD_CONTEXT*)dwContext;
switch (dwInternetStatus)
{
case INTERNET_STATUS_HANDLE_CREATED:
context->hUrl = (HINTERNET)((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult;
break;
case INTERNET_STATUS_RESPONSE_RECEIVED:
size = 0;
InternetQueryOptionA(context->hUrl, INTERNET_OPTION_URL, nullptr, &size);
link = new char[size];
InternetQueryOptionA(context->hUrl, INTERNET_OPTION_URL, link, &size);
MessageBoxA(NULL, link, "", MB_OK);
delete[] link;
/* if this is the last response (the HTTP status code is 200)
we initiate InternetReadFileEx recursion */
break;
...
default:
MessageBoxA(NULL, "Status: Unknown (%d)n", "", MB_OK);
break;
}
}
此外,由于InternetOpenUrl
尚未完成,一些WinINet函数将在回调内使用ERROR_INTERNET_INCORRECT_HANDLE_STATE
失败。尽管CCD_ 9确实在每个CCD_。
InternetOpenUrl
将生成以下回调状态序列:
- INTERNET _STATUS_HANDLE_CREATED
- INTERNET_STATUS_DETECTING_PROXY
- INTERNET_STATUS_SENDING_REQUEST
- INTERNET_STATUS_REQUEstrongENT
- 互联网状态接收响应
- 互联网状态响应接收
- INTERNET_STATUS_REDIRECT
- INTERNET_STATUS_DETECTING_PROXY
- INTERNET状态解析名称
- INTERNET状态名称已解决
- INTERNET_STATUS_CONNECTING_TO_SERVER
- INTERNET_STATUS_CONNECTED_TO_SERVER
- INTERNET_STATUS_SENDING_REQUEST
- INTERNET_STATUS_REQUEstrongENT
- 互联网状态接收响应
- 互联网状态响应接收
如何判断最后一个INTERNET_STATUS_RESPONSE_RECEIVED
何时到达(HTTP状态200)?
好的,不需要同步运行InternetOpenUrl
。问题是我实际上并没有异步运行,因为我忘记在InternetOpen
中设置INTERNET_FLAG_ASYNC
标志。
异步运行时,还会收到一个回调状态INTERNET_STATUS_REQUEST_COMPLETE
,表示异步操作已完成。当您收到此消息时,可以安全地以递归方式调用InternetReadFile
,因为当InternetReadFile
完成时,您将收到另一个INTERNET_STATUS_REQUEST_COMPLETE
,它将再次调用InternetReadFile
。执行此操作直到INTERNET_ASYNC_RESULT
的dwResult
为false。
如果有大量缓冲数据,InternetReadFile
也可能同步运行,此时您必须再次运行InternetReadFile
,直到InternetReadFile
之后对GetLastError()
的调用不会导致ERROR_IO_PENDING
。然后你关上把手,你就完成了。
typedef struct{
HWND hDialog; // Window handle
HINTERNET hUrl; // HINTERNET handle created by InternetOpenUrl
char buffer[512];
DWORD size; // buffer fill size
unsigned int crc32;
unsigned int length; // file length
unsigned int received; // downloaded bytes so far
} DOWNLOAD_CONTEXT;
std::vector<DOWNLOAD_CONTEXT> contexts;
void Download(TCHAR *url, unsigned int crc32, unsigned int length)
{
HINTERNET hInternet = InternetOpen(_T("Test"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, INTERNET_FLAG_ASYNC); // async flag
InternetSetStatusCallback(hInternet, DownloadProgress);
DOWNLOAD_CONTEXT context;
context.hDialog = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hMainWindow, DownloadDlg);
context.length = length;
context.crc32 = crc32;
context.received = 0;
context.size = 0;
contexts.push_back(context);
HINTERNET hUrl = InternetOpenUrl(hInternet, url, _T(""), 0, INTERNET_FLAG_RELOAD, DWORD_PTR(&*(contexts.end()-1)));
}
void CALLBACK DownloadProgress(
_In_ HINTERNET hInternet,
_In_ DWORD_PTR dwContext,
_In_ DWORD dwInternetStatus,
_In_ LPVOID lpvStatusInformation,
_In_ DWORD dwStatusInformationLength
)
{
DOWNLOAD_CONTEXT *context = (DOWNLOAD_CONTEXT*)dwContext;
switch (dwInternetStatus)
{
case INTERNET_STATUS_HANDLE_CREATED:
context->hUrl = (HINTERNET)((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult;
ShowWindow(context->hDialog, SW_SHOW);
break;
case INTERNET_STATUS_HANDLE_CLOSING:
// clean up
break;
case INTERNET_STATUS_RESPONSE_RECEIVED: // don't need to do anything here
break;
case INTERNET_STATUS_REQUEST_COMPLETE:
if ((HINTERNET)((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult == context->hUrl)
{
DWORD size = 0;
char *text;
InternetQueryOptionA(context->hUrl, INTERNET_OPTION_URL, nullptr, &size);
text = new char[size];
InternetQueryOptionA(context->hUrl, INTERNET_OPTION_URL, text, &size);
SetWindowTextA(GetDlgItem(context->hDialog, IDC_EDIT1), text);
delete[] text;
}
if (((LPINTERNET_ASYNC_RESULT)lpvStatusInformation)->dwResult > 0)
{
bool res;
do
{
context->received += context->size;
// proccess first size bytes from buffer
res = InternetReadFile(context->hUrl, context->buffer, 512, &context->size);
} while (res && context->size > 0);
if (GetLastError() != ERROR_IO_PENDING)
{
InternetCloseHandle(hInternet);
InternetCloseHandle(context->hUrl);
}
SetWindowTextA(GetDlgItem(context->hDialog, IDC_STATIC_SIZE), to_string(context->received).c_str());
}
else
{
InternetCloseHandle(hInternet);
InternetCloseHandle(context->hUrl);
}
break;
...
default:
MessageBoxA(NULL, "Status: Unknown (%d)n", "", MB_OK);
break;
}
}
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 为什么在保护模式下继承升级不起作用
- 如何在全屏模式下(在OpenGL中)使背景透明
- 为什么使用__LINE_的代码在发布模式下在MSVC下编译,而不是在调试模式下
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 此模式的C++RegEx
- avrogencpp能为模式中的每种类型生成单独的头文件吗
- 如果 Proactor 设计模式优于异步 I/O,为什么它在 ASIO 中不是默认值?
- QMenu 无模式/异步
- InternetOpenUrl处于异步模式
- 异步模式下使用的WinHttp-ERROR_INTERNET_CANNOT_CONNECT如何干净地关闭连接
- 重复发送http请求,速度更快(异步模式)
- 在 winsock 服务器中使用异步套接字的非阻塞模式C++不同
- 在异步模式下使用ReadFile测试readbytes是否等于toread字节
- 嵌入式系统状态模式:存储与异步事件相关的信息
- 我可以在 boost::asio 异步模式下创建和接受套接字时使用 boost::shared_ptr 吗?
- CPPCMS会话异步.模式
- 在异步模式下使用FtpFindFirstFile unicode版本访问违反
- 在异步模式下使用会话的CPPCMS示例