C++ winhttp 实现文件下载器
Posted 1_bit
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ winhttp 实现文件下载器相关的知识,希望对你有一定的参考价值。
本篇内容讲述 C++ winHttp 实现下载器的简单 demo,使用了 WinHttpOpen、WinHttpConnect、WinHttpOpenRequest、WinHttpSendRequest、WinHttpReceiveResponse、WinHttpQueryDataAvailable、WinHttpReadData、WinHttpCloseHandle 等函数。
版权声明:本文为CSDN博主「1_bit」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/A757291228/article/details/129974019
文章参考 Microsoft doc WinHttp:https://learn.microsoft.com/zh-cn/windows/win32/WinHttp/winhttp-start-page
本机环境:VisualStudio 2022 、 Windows10
想要完整代码请到文章末尾
一、WinHttp
WinHttp 是 Windows 提供的可创建网络请求的一组 API,包括 http、https、代理等;WinHttp 的 Microsoft doc 链接为 https://learn.microsoft.com/zh-cn/windows/win32/WinHttp/winhttp-start-page,若需要查看详细的文档说明,可进入 Microsoft doc 进行查看。
二、WinHttp 的使用
本篇文章只简单的介绍如何使用 WinHttp,并不涉及其原理,包括 http、https 协议不再讲解。关于不讲解的原因为思考后,发现即使不会协议,也能很好的使用 WinHttp,当然可能对于某些“复杂”的业务逻辑或特殊需求并不好处理,可能也会对于某些错误信息无法判断,若出现这种情况,建议读者再去了解 http、https 等协议,当然本人之后也会出相关的协议讲解的文章,但在本篇,我们只讨论如何使用 C++ WinHttp 进行网络请求。
在 Microsoft doc 中,有介绍 C++ WinHttp 的使用流程,可以根据这个 流程图 学习接下来的知识点:
2.1 WinHttp 的 http 一般使用流程
使用 C++ WinHttp 发送一个 Http 请求,需要经过以下流程 :WinHttpOpen->WinHttpConnect->WinHttpOpenRequest->WinHttpSendRequest->WinHttpReceiveResponse->WinHttpQueryDataAvailable->WinHttpReadData->WinHttpCloseHandle
以上所述内容只需要先有一个印象,接下来会对其进行详细说明。
对于以上流程用中文的进行解释为:WinHttpOpen (初始化 WinHttp )
->WinHttpConnect (指定 Http 请求的初始目标服务器 )
->WinHttpOpenRequest (创建 HTTP 请求句柄)
->WinHttpSendRequest (指定请求发送到 Http 服务器)
->WinHttpReceiveResponse (等待 WinHttpSendRequest 发起的 HTTP 请求的响应)
->WinHttpQueryDataAvailable (读取数据大小)
->WinHttpReadData**(读取数据)
** ->WinHttpCloseHandle (关闭连接)
2.2 VisualStduio 环境准备
本机环境使用的 VS 版本为2022,打开后点击创建项目:
选择控制台程序:
接下来编写完项目名称点击下一步即可:
接下来在 右侧解决方案资源管理器 下的 SourceFiles 中找到 main.cpp 进行代码编写即可:
2.3 WinHttpOpen 初始化 WinHttp
在了解了 WinHttp 的一般步骤后,首先开始读 WinHttp 的初始化操作。一个 WinHttp 的函数圆形如下:
WINHTTPAPI HINTERNET WinHttpOpen(
[in, optional] LPCWSTR pszAgentW,
[in] DWORD dwAccessType,
[in] LPCWSTR pszProxyW,
[in] LPCWSTR pszProxyBypassW,
[in] DWORD dwFlags
);
WinHttpOpen 接收 5 个参数,分别是 pszAgentW、dwAccessType、pszProxyW、pszProxyBypassW、dwFlags,其中:
- pszAgentW:表示代理名称 agent name
- dwAccessType:表示如何http(假定)如何进行请求 可选
- pszProxyW:表示若使用代理则在此处填写对应的代理服务器和端口号 可选
- pszProxyBypassW:表示绕过的代理服务器主机名
- dwFlags:表示使用某些特定的组合选项
在以上的解释中,对于网络知识薄弱的同学可能会感到一头雾水,在此使用一个示例进行说明:
hSession = WinHttpOpen(
L"My User Agent Name",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
以上是一个 WinHttpOpen 的代码示例,其中参数:
- pszAgentW 设置为了
"My User Agent Name"
,这就是我们的代理名称为"My User Agent Name"
,或者你想用其他名称也行。 - dwAccessType 设置为了
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
表示使用默认代理设置,也就是说当前本机的默认网络代理设置是什么就是什么,或者说咱们没有什么特殊的代理需求时,设置为WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
即可。 - pszProxyW 设置为了
WINHTTP_NO_PROXY_NAME
表示当前的请求不使用代理。毕竟在上一个设置时咱们设置了使用默认代理,那么理应设置成不适用代理(当然,你可能当前本机是有代理,默认了,那么也是走那个默认的代理去请求的)。 - pszProxyBypassW 设置为了
WINHTTP_NO_PROXY_BYPASS
则表示不绕过任何的主机,则使用当前的默认代理进行访问。 - dwFlags 设置为
0
表示打开会话时不使用特定的选项,该怎样就怎样。
以上设置中 dwAccessType 还可以设置成 WINHTTP_ACCESS_TYPE_NO_PROXY
与 WINHTTP_ACCESS_TYPE_NAMED_PROXY
,其中:
WINHTTP_ACCESS_TYPE_NO_PROXY
表示直接链接到目标服务器不使用代理WINHTTP_ACCESS_TYPE_NAMED_PROXY
表示使用目标代理
接下来在 VS 2022 中添加 WinHttp 头文件对其引入:
#include <Winhttp.h>
并且需要添加对应的编译指示器,指定库文件链接:
#pragma comment(lib, "winhttp.lib")
为了方便接下来的操作,咱们顺势将其他头文件引入:
#include <Windows.h>
#include <iostream>
接着创建一个 HINTERNET 句柄对象用于接收 WinHttp 初始化后的句柄:
HINTERNET hSession = NULL;
此时还可以在之后进行判断,是否初始化成功:
if (!hSession)
std::cerr << "WinHttp 打开错误 \\n";
return 1;
接着就可以复制以上示例代码到 main.cpp 文件中了,此时的 main.cpp 文件代码如下:
#include "pch.h"
#include <Windows.h>
#include <iostream>
#include <Winhttp.h>
#pragma comment(lib, "winhttp.lib")
using namespace winrt;
using namespace Windows::Foundation;
int main()
HINTERNET hSession = NULL;
hSession = WinHttpOpen(
L"My User Agent",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
if (!hSession)
std::cerr << "WinHttp 打开错误 \\n";
return 1;
2.3 WinHttpConnect 指定 Http 请求的初始目标服务器
完成了 WinHttp 初始化后,使用 WinHttpConnect 指定 Http 的目标服务器,WinHttpConnect 函数原型如下:
WINHTTPAPI HINTERNET WinHttpConnect(
[in] HINTERNET hSession,
[in] LPCWSTR pswzServerName,
[in] INTERNET_PORT nServerPort,
[in] DWORD dwReserved
);
WinHttpConnect 接收 4 个参数:
- hSession:为 WinHttp 初始化后的句柄
- pswzServerName:为目标服务器名,域名或IP
- nServerPort: 为指定的端口,如果是 HTTP 就是80,若是 HTTPS 就是 443
- dwReserved:保留参数,设置为 0 即可,不用管,文档也是这样写的
以上参数中 nServerPort 可以设置为:
INTERNET_DEFAULT_HTTP_PORT
:使用 HTTP 服务器的默认端口 (端口 80)INTERNET_DEFAULT_HTTPS_PORT
:使用 HTTPS 服务器的默认端口 (端口 443) 。
此时该函数可编写为:
HINTERNET hConnect = NULL;
hConnect = WinHttpConnect(
hSession,
L"demo.com",//此处填写你要进行 http 请求的 hostname 或 ip
80,
0
);
2.4 WinHttpOpenRequest 创建 HTTP 请求句柄
WinHttpOpenRequest 创建 HTTP 请求句柄,函数原型如下:
WINHTTPAPI HINTERNET WinHttpOpenRequest(
[in] HINTERNET hConnect,
[in] LPCWSTR pwszVerb,
[in] LPCWSTR pwszObjectName,
[in] LPCWSTR pwszVersion,
[in] LPCWSTR pwszReferrer,
[in] LPCWSTR *ppwszAcceptTypes,
[in] DWORD dwFlags
);
- hConnect 为 WinHttpConnect 返回的 HINTERNET 句柄。
- pwszVerb 请求类型参数,例如
GET
,需要大写 - pwszObjectName url 请求参数
- pwszVersion 指定 HTTP 版本,默认为
NULL
,使用 HTTP/1.1 - pwszReferrer 表示请求的来源地址,如果没有其他页面跳转到目标请求,那么设置为
NULL
,也可以使用WINHTTP_NO_REFERER
代替 - ppwszAcceptTypes 表示 HTTP 请求可接受的 MIME 类型,例如 “application/json”、“text/html”,设置为
WINHTTP_DEFAULT_ACCEPT_TYPES
表示使用 WinHTTP 默认的 MIME 类型设置 - dwFlags 若不需要设置任何特殊标志和选项那么设置为
0
即可
dwFlags 参数还可以设置为 WINHTTP_FLAG_SECURE
、WINHTTP_FLAG_ESCAPE_PERCENT
、WINHTTP_FLAG_NULL_CODEPAGE
、WINHTTP_FLAG_BYPASS_PROXY_CACHE
:
WINHTTP_FLAG_SECURE
表示使用 HTTPS 链接,默认情况下 winHttp 使用 HTTPWINHTTP_FLAG_ESCAPE_PERCENT
表示在请求之前对 URL 中的 % 进行转义WINHTTP_FLAG_NULL_CODEPAGE
表示无需为响应的 Unicode 字符串指定代码页WINHTTP_FLAG_BYPASS_PROXY_CACHE
表示绕过服务器缓存直接请求服务器内容
那么以上函数可写成:
HINTERNET hRequest = NULL;
hRequest = WinHttpOpenRequest(
hConnect, L"GET",
L"disk.exe",
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);
if (!hRequest)
std::cerr << "WinHttpOpenRequest 错误 \\n";
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
2.5 WinHttpSendRequest 指定请求发送到 Http 服务器
函数原型如下:
WINHTTPAPI BOOL WinHttpSendRequest(
[in] HINTERNET hRequest,
[in, optional] LPCWSTR lpszHeaders,
[in] DWORD dwHeadersLength,
[in, optional] LPVOID lpOptional,
[in] DWORD dwOptionalLength,
[in] DWORD dwTotalLength,
[in] DWORD_PTR dwContext
);
参数说明:
- hRequest: Request WinHTTP 请求句柄
- pwszHeaders:如果没有要添加的标头,则为
NULL
或者为WINHTTP_NO_ADDITIONAL_HEADERS
- dwHeadersLength:pwszHeaders 参数以字节为单位的长度,若 pwszHeaders 为 NULL,则此参数为
0
- lpOptional:要发送到服务器的数据,如果没有要发送的数据,则为
NULL
或WINHTTP_NO_REQUEST_DATA
- dwOptionalLength:lpOptional 以字节为单位的长度,lpOptional 为
NULL
,则此参数为0
- dwTotalLength:请求的总长度,没有标头也没有数据,则为
0
。 - dwContext:用于指定调用方自定义的上下文值,在请求完成后可以通过回调函数获取该值,不需要设置回调则为
0
此时代码可以编写为如下:
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
if (!bResults)
std::cerr << "WinHttpSendRequest 错误 \\n";
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
2.6 WinHttpReceiveResponse 等待 WinHttpSendRequest 发起的 HTTP 请求的响应
函数原型如下:
WINHTTPAPI BOOL WinHttpReceiveResponse(
[in] HINTERNET hRequest,
[in] LPVOID lpReserved
);
- hRequest :已通过 WinHttpSendRequest 函数发送请求并返回的 WinHTTP 请求句柄。
等待 WinHttpSendRequest 完成此句柄,然后再调用 WinHttpReceiveResponse。 - lpReserved:保留参数设置为
NULL
。
此时代码如下:
bResults = WinHttpReceiveResponse(hRequest, NULL);
if (!bResults)
std::cerr << "WinHttpReceiveResponse 错误 \\n";
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
2.7 WinHttpQueryDataAvailable 读取数据大小
接下来使用 WinHttpQueryDataAvailable 读取数据大小,方便接下来读取数据到某一个 buf 之中。
WinHttpQueryDataAvailable 函数原型如下:
WINHTTPAPI BOOL WinHttpQueryDataAvailable(
[in] HINTERNET hRequest,
[out] LPDWORD lpdwNumberOfBytesAvailable
);
hRequest:WinHttpSendRequest 的 WinHTTP 句柄
lpdwNumberOfBytesAvailable:尚未读取的响应数据的大小
此时代码如下:
DWORD dwSize = 0;
LPSTR pszOutBuffer = NULL;
dwSize = 0;
WinHttpQueryDataAvailable(hRequest, &dwSize);
pszOutBuffer = new char[dwSize + 1];
ZeroMemory(pszOutBuffer, dwSize + 1);//清空 pszOutBuffer
2.8 WinHttpReadData 读取数据
WinHttpReadData 函数将会读取还没有读取的数据,函数原型如下:
WINHTTPAPI BOOL WinHttpReadData(
[in] HINTERNET hRequest,
[out] LPVOID lpBuffer,
[in] DWORD dwNumberOfBytesToRead,
[out] LPDWORD lpdwNumberOfBytesRead
);
- hRequest:WinHttpSendRequest 的 WinHTTP 句柄
- lpBuffer:buf 指针 存储读取数据
- dwNumberOfBytesToRead:读取数据的字节数大小
- lpdwNumberOfBytesRead:此时实际读取数据的字节数
由于此时 WinHttpReadData 返回的是 BOOL,那么直接 while
进行读取即可,当然,也可以 lpdwNumberOfBytesRead 为 0 时 break
:
while (WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded))
if (dwDownloaded == 0)
break;
此时读取的是 exe 二进制流数据,咱们可以直接 cout 输出,代码如下:
std::cout << pszOutBuffer;
delete[] pszOutBuffer;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
结果如下:
下载器输出完整代码
该部分完整代码如下:
#include "pch.h"
#include <Windows.h>
#include <iostream>
#include <Winhttp.h>
#pragma comment(lib, "winhttp.lib")
using namespace winrt;
using namespace Windows::Foundation;
int main()
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
DWORD dwSize = 0;
LPSTR pszOutBuffer = NULL;
DWORD dwDownloaded = 0;
bool bResults = false;
hSession = WinHttpOpen(
L"My User Agent",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
if (!hSession)
std::cerr << "WinHttp 打开错误 \\n";
return 1;
hConnect = WinHttpConnect(
hSession,
L"hostname or ip",
80,
0);
if (!hConnect)
std::cerr << "WinHttpConnect 错误 \\n";
WinHttpCloseHandle(hSession);
return 1;
hRequest = WinHttpOpenRequest(
hConnect, L"GET",
L"disk.exe",
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);
if (!hRequest)
std::cerr << "WinHttpOpenRequest 错误 \\n";
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
if (!bResults)
std::cerr << "WinHttpSendRequest 错误 \\n";
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
bResults = WinHttpReceiveResponse(hRequest, NULL);
if (!bResults)
std::cerr << "WinHttpReceiveResponse 错误 \\n";
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
dwSize = 0;
WinHttpQueryDataAvailable(hRequest, &dwSize);
pszOutBuffer = new char[dwSize + 1];
ZeroMemory(pszOutBuffer, dwSize + 1);
while (WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded))
if (dwDownloaded == 0)
break;
std::cout << pszOutBuffer;
delete[] pszOutBuffer;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
三、代码更改成下载程序并保存
想要更改以上示例下载文件保存到磁盘步骤简单,首先引入 fstream 头文件:
#include <fstream>
接在在下图所示处开始添加代码:
此时添加的代码如下:
std::ofstream outfile("C:\\\\demo.exe", std::ios::binary);
此时表示输出内容到 C:\\\\demo.exe
下保存,当然 demo.exe 是你的文件名。
接着创建一个 BYTE 对象为缓冲区:
BYTE buffer[1024];
修改原有的 while
循环读取如下:
while (WinHttpReadData(hRequest, buffer, sizeof(buffer), &dwDownloaded))
outfile.write(reinterpret_cast<const char*>(buffer), dwDownloaded);
if (dwDownloaded == 0)
break;
outfile.close();
此时读取到的缓冲区变成了 buffer
,并且在读取后,在 使用 outfile.write
写入数据(不会的可以查一下文档,这个很简单)。
最后关闭 文件操作 即可。
运行程序完毕后,已下载内容到磁盘中:
下载器完整代码
此时修改过的完整下载器代码如下:
#include "pch.h"
#include <Windows.h>
#include <iostream>
#include <Winhttp.h>
#include <fstream>
#pragma comment(lib, "winhttp.lib")
using namespace winrt;
using namespace Windows::Foundation;
int main()
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
DWORD dwSize = 0;
LPSTR pszOutBuffer = NULL;
DWORD dwDownloaded = 0;
bool bResults = false;
hSession = WinHttpOpen(
L"My User Agent",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
if (!hSession)
std::cerr << "WinHttp 打开错误 \\n";
return 1;
hConnect = WinHttpConnect(
hSession,
L"hostname",
80,
0);
if (!hConnect)
std::cerr << "WinHttpConnect 错误 \\n";
WinHttpCloseHandle(hSession);
return 1;
hRequest = WinHttpOpenRequest(
hConnect, L"GET",
L"disk.exe",
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);
if (!hRequest)
std::cerr << "WinHttpOpenRequest 错误 \\n";
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
if (!bResults)
std::cerr << "WinHttpSendRequest 错误 \\n";
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
bResults = WinHttpReceiveResponse(hRequest, NULL);
if (!bResults)
std::cerr << "WinHttpReceiveResponse 错误 \\n";
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
//dwSize = 0;
//WinHttpQueryDataAvailable(hRequest, &dwSize);
尝试在 Visual Studio 2010 中包含 winhttp.h 时出现 C++ 307 错误
【中文标题】尝试在 Visual Studio 2010 中包含 winhttp.h 时出现 C++ 307 错误【英文标题】:C++ 307 Errors when trying to include winhttp.h in visual studio 2010
【发布时间】:2011-06-15 11:44:38
【问题描述】:
我有一个大问题。我正在尝试使用 WinHttp 通过 C++ 下载文件,并且我正在使用 Visual Studio 2010 来执行此操作。
我的问题是程序没有编译,因为产生了307错误,都是指winhttp.h
。我提到我已经包含了该文件。可能是什么问题呢?谢谢!
有一些:
------ Build started: Project: a, Configuration: Debug Win32 ------
b. Cpp
a. Cpp
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(50): error C2146:
Syntax error: missing ';' before identifier 'HINTERNET'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(50): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(50): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(51): error C2143: syntax error: missing ';' before '*'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(51): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(51): error C2378: 'HINTERNET': redefinition; symbol cannot be overloaded with a typedef
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(50): see declaration of 'HINTERNET'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(51): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(53): error C2146: syntax error: missing ';' before identifier 'INTERNET_PORT'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(53): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(53): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(54): error C2143: syntax error: missing ';' before '*'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(54): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(54): error C2378: 'INTERNET_PORT': redefinition; symbol cannot be overloaded with a typedef
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(53): see declaration of 'INTERNET_PORT'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(54): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(95): error C2146: syntax error: missing ';' before identifier 'dwResult'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(95): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(95): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(96): error C2146: syntax error: missing ';' before identifier 'dwError'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(96): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(96): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(107): error C2146: syntax error: missing ';' before identifier 'dwMajorVersion'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(107): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(107): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(108): error C2146: syntax error: missing ';' before identifier 'dwMinorVersion'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(108): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(108): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(144): error C2146: syntax error: missing ';' before identifier 'dwStructSize'
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(144): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(144): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c: \program files (x86)\microsoft sdks\windows\v7.0a\include\winhttp. H(145): error C2146: syntax error: missing ';' before identifier 'lpszScheme'
现在我有另一个问题。这是我的代码:
#include <windows.h>
#include <winhttp.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#include <string.h>
int main()
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPBYTE pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen( L"Internet Explorer example",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0 );
// Specify an HTTP server.
if( hSession )
hConnect = WinHttpConnect( hSession, L"www.my-new-gadget.com",
INTERNET_DEFAULT_HTTPS_PORT, 0 );
// Create an HTTP request handle.
if( hConnect )
hRequest = WinHttpOpenRequest( hConnect, L"GET", L"index.php",
NULL, WINHTTP_NO_REFERER,
NULL, NULL);
// Send a request.
if( hRequest )
bResults = WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
0, 0 );
// End the request.
if( bResults )
bResults = WinHttpReceiveResponse( hRequest, NULL );
HANDLE hFile = CreateFile("D:\\index.php", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (bResults)
do
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable( hRequest, &dwSize))
printf( "Error %u in WinHttpQueryDataAvailable.\n", GetLastError());
// Allocate space for the buffer.
pszOutBuffer = new byte[dwSize+1];
if (!pszOutBuffer)
printf("Out of memory\n");
dwSize=0;
else
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize+1);
if (!WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded))
printf( "Error %u in WinHttpReadData.\n", GetLastError());
else
//printf("%s", pszOutBuffer);
DWORD wmWritten;
bool fr = WriteFile(hFile, pszOutBuffer, dwSize, &wmWritten, NULL);
int n = GetLastError();
// Free the memory allocated to the buffer.
delete [] pszOutBuffer;
while (dwSize>0);
CloseHandle(hFile);
// Report any errors.
if (!bResults)
printf("Error %d has occurred.\n",GetLastError());
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
return 0;
输出是:
------ Build started: Project: a, Configuration: Debug Win32 ------
a.cpp
c:\users\admin\documents\visual studio 2010\projects\a\a\a.cpp(73): warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
a.obj : error LNK2019: unresolved external symbol __imp__WinHttpCloseHandle@4 referenced in function _main
a.obj : error LNK2019: unresolved external symbol __imp__WinHttpReadData@16 referenced in function _main
a.obj : error LNK2019: unresolved external symbol __imp__WinHttpQueryDataAvailable@8 referenced in function _main
a.obj : error LNK2019: unresolved external symbol __imp__WinHttpReceiveResponse@8 referenced in function _main
a.obj : error LNK2019: unresolved external symbol __imp__WinHttpSendRequest@28 referenced in function _main
a.obj : error LNK2019: unresolved external symbol __imp__WinHttpOpenRequest@28 referenced in function _main
a.obj : error LNK2019: unresolved external symbol __imp__WinHttpConnect@16 referenced in function _main
a.obj : error LNK2019: unresolved external symbol __imp__WinHttpOpen@20 referenced in function _main
MSVCRTD.lib(crtexew.obj) : error LNK2019: unresolved external symbol _WinMain@16 referenced in function ___tmainCRTStartup
c:\users\admin\documents\visual studio 2010\Projects\a\Debug\a.exe : fatal error LNK1120: 9 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
现在可能是什么问题?我正在尝试 2 天来制作一个程序来从给定的 URL 下载文件。这让我疯狂!请帮帮我!
【问题讨论】:
贴一些代码..也给我们一些错误,我猜大部分都是相似的。
你能发布整个错误信息吗?
发布整个#include
块。可能缺少一些依赖项(例如windows.h
或其他东西)。
是的失谐,这就是问题所在。我把 windows.h 头文件放在 winhttp.h 之后。 :(
第二个问题见this topic。
【参考方案1】:
在#include <winhttp.h>
之前添加#include <windows.h>
。
【讨论】:
以上是关于C++ winhttp 实现文件下载器的主要内容,如果未能解决你的问题,请参考以下文章
C++ WinINet InternetReadFile函数刷新
使用WinHttp接口实现HTTP协议GetPost和文件上传功能