gpt4 book ai didi

c++ - 异步模式下的 InternetOpenUrl

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:50:35 27 4
gpt4 key购买 nike

我有一个使用 WinINet 函数异步下载文件的函数。我使用的方法是:

如何等到 InternetOpenUrl 完成后返回的句柄才有效?如果我异步运行 InternetOpenUrl,我无法确定何时收到最后一个 INTERNET_STATUS_RESPONSE_RECEIVED因为可能的重定向。此外,当 InternetOpenUrl 完成后,我想调用 InternetQueryOption使用 INTERNET_OPTION_URL 标志,在所有重定向后获取最终 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;
}
}

还有一些 WinINet 函数将因 ERROR_INTERNET_INCORRECT_HANDLE_STATE 而失败,在回调中,因为 InternetOpenUrl 尚未完成。尽管 InternetQueryOption 会在每个 INTERNET_STATUS_RESPONSE_RECEIVED 处显示 URL。

InternetOpenUrl 将生成以下回调状态序列:

  • INTERNET_STATUS_HANDLE_CREATED
  • INTERNET_STATUS_DETECTING_PROXY
  • INTERNET_STATUS_SENDING_REQUEST
  • INTERNET_STATUS_REQUEST_SENT
  • INTERNET_STATUS_RECEIVING_RESPONSE
  • INTERNET_STATUS_RESPONSE_RECEIVED
  • INTERNET_STATUS_REDIRECT
  • INTERNET_STATUS_DETECTING_PROXY
  • INTERNET_STATUS_RESOLVING_NAME
  • INTERNET_STATUS_NAME_RESOLVED
  • INTERNET_STATUS_CONNECTING_TO_SERVER
  • INTERNET_STATUS_CONNECTED_TO_SERVER
  • INTERNET_STATUS_SENDING_REQUEST
  • INTERNET_STATUS_REQUEST_SENT
  • INTERNET_STATUS_RECEIVING_RESPONSE
  • INTERNET_STATUS_RESPONSE_RECEIVED

我如何知道最后一个 INTERNET_STATUS_RESPONSE_RECEIVED 何时到达(HTTP 状态 200)?

最佳答案

好的,不需要同步运行InternetOpenUrl。问题是我实际上并没有异步运行,因为我忘记在 InternetOpen 中设置 INTERNET_FLAG_ASYNC 标志。

当您异步运行时,会收到一个回调状态,INTERNET_STATUS_REQUEST_COMPLETE,表示异步操作已完成。当您收到此消息时,以递归方式调用 InternetReadFile 是安全的,因为当 InternetReadFile 完成后您将收到另一个 INTERNET_STATUS_REQUEST_COMPLETE,它在turn 将再次调用 InternetReadFile。您这样做直到 INTERNET_ASYNC_RESULTdwResult 为假。

如果有大量缓冲数据,InternetReadFile 也有可能同步运行,此时您必须再次运行 InternetReadFile 直到调用GetLastError(),紧接在 InternetReadFile 之后,不会导致 ERROR_IO_PENDING。之后合上 Handlebars ,大功告成。

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

关于c++ - 异步模式下的 InternetOpenUrl,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29735286/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com