您的位置:首页 > 健康 > 美食 > 棋牌软件开发源代码_html简单登录界面代码_sem招聘_百度大全

棋牌软件开发源代码_html简单登录界面代码_sem招聘_百度大全

2024/10/5 9:05:31 来源:https://blog.csdn.net/Flame_Cyclone/article/details/142579062  浏览:    关键词:棋牌软件开发源代码_html简单登录界面代码_sem招聘_百度大全
棋牌软件开发源代码_html简单登录界面代码_sem招聘_百度大全

CWinHttpHelper

#pragma once#include <Windows.h>
#include <WinHttp.h>
#include <stdint.h>
#include <string>
#include <vector>
#include <functional>
#include <map>
#include <set>
#include <time.h>
#include <tchar.h>#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endiftypedef struct _WINHTTP_URL_INFO WINHTTP_URL_INFO, *LPWINHTTP_URL_INFO;
typedef struct _WINHTTP_PACKAGE_INFO WINHTTP_PACKAGE_INFO, *LPWINHTTP_PACKAGE_INFO;#define WINHTTP_HTTPS_DOWNLOAD_AGENT LR"(Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0)"#define WINHTTP_MAX_CONNS_PER_SERVER                    (256)           // 服务器最大连接数
#define WINHTTP_DOWNLOAD_BLOCK_SIZE                     (1024 * 32)     // 下载缓冲大小
#define WINHTTP_DOWNLOAD_MINIMUM_SIZE                   (1024 * 4)      // 单线程最小下载大小
#define WINHTTP_PROGRESS_UPDATE_INTERVAL_TIME           (1000)          // 下载进度更新时间
#define WINHTTP_SPEED_UPDATE_INTERVAL_TIME              (1000)          // 下载速度更新时间
#define WINHTTP_FILE_BACKUP_MAX_CONUT                   (0)             // 最多备份数量
#define WINHTTP_MAX_THREAD_COUNT                        (64)            // 最大下载线程数#define WINHTTP_RESOLVE_TIME_OUT                        (1000)          // 解析超时
#define WINHTTP_CONNECT_TIME_OUT                        (1000)          // 连接超时
#define WINHTTP_SEND_TIME_OUT                           (2000)          // 发送超时
#define WINHTTP_RECEIVE_TIME_OUT                        (5000)         // 接收超时// 进度信息
typedef struct _WINHTTP_PROGRESS_INFO
{double lfProgress;          // 当前进度(0.0f - 1.0f)double lfSpeed;             // 当前速度(字节/秒)double lfRemainTime;        // 剩余时间(毫秒)ULONGLONG ullCur;           // 当前下载量(字节)ULONGLONG ullTotal;         // 总数据量(字节)clock_t costTime;           // 消耗时间(毫秒)uint32_t activeThreads;     // 活动线程数uint32_t totalThreads;      // 总共线程数
}WINHTTP_PROGRESS_INFO, *LPWINHTTP_PROGRESS_INFO;class CWinHttpResult
{
public:CWinHttpResult() :code(0) {}std::string result;         //响应结果DWORD code;                 //响应状态码
};// WinHttp助手类
class CWinHttpHelper
{
public:CWinHttpHelper();~CWinHttpHelper();//// @brief: 添加请求头信息// @param: strCaption       头名// @param: strData          头数据// @ret: voidvoid AddRequestHeader(const _tstring strCaption, const _tstring strData);//// @brief: 移除请求头信息// @param: strCaption       头名// @param: strData          头数据// @ret: voidvoid RemoveRequestHeader(const _tstring strCaption, const _tstring strData);//// @brief: 清除请求头信息// @ret: voidvoid ClearRequestHeader();//// @brief: 获取下载内容大小// @param: strUrl           URL链接// @param: pUllLength       内容长度缓冲指针// @ret: bool               操作成功与否bool GetContentLength(const _tstring& strUrl, PULONGLONG pUllLength);//// @brief: 下载保存到文件// @param: strUrl           URL链接// @param: strFile          保存文件路径// @param: cbProgress       下载进度回调函数// @param: dwThreadCount    下载线程数// @ret: bool               操作成功与否bool DownloadToFile(const _tstring& strUrl, _tstring strFile, std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress = nullptr,DWORD dwThreadCount = 8);//// @brief: 下载保存到缓存// @param: strUrl           URL链接// @param: lpBuf            保存缓冲// @param: dwBufSize        缓冲大小// @param: cbProgress       下载进度回调函数// @param: dwThreadCount    下载线程数// @ret: bool               操作成功与否bool DownloadToBuffer(const _tstring& strUrl, std::string& vData,std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress = nullptr,DWORD dwThreadCount = 8);//// @brief: 发送Get请求// @param: strUrl           URL链接// @param: cbProgress       进度回调// @param: dwThreadCount    线程数// @ret: CWinHttpResult     响应结果CWinHttpResult Get(const _tstring& strUrl,std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress = nullptr,DWORD dwThreadCount = 1);//// @brief: 发送Post请求// @param: strUrl           URL链接// @param: strParam         请求参数// @param: cbProgress       进度回调// @param: dwThreadCount    线程数// @ret: CWinHttpResult     响应结果CWinHttpResult Post(const _tstring& strUrl,std::string& strParam,std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress = nullptr,DWORD dwThreadCount = 1);private://// @brief: 执行请求// @param: strUrl           URL链接// @param: strMethod        请求方法// @param: strParam         请求参数// @param: cbProgress       进度回调// @param: dwThreadCount    线程数// @ret: CWinHttpResult   响应结果CWinHttpResult _DoSendRequest(const _tstring& strUrl,const _tstring& strMethod,const std::string& strParam,std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress = nullptr,DWORD dwThreadCount = 1);// 获取请求头字符串_tstring _GetRequestHeaderString();// 清空文件内容void _TruncateFile(const _tstring& strPath);// 下载前备份文件bool _BackupFile(const _tstring& strPath);// 进度处理void _ProcessProcess(std::vector<WINHTTP_PACKAGE_INFO>& taskPackages);// 分段下载bool _PartialDownload(const _tstring& strUrl, const _tstring& strUrlFileName, const _tstring& strVerb, LPVOID lpBuf,ULONGLONG ullContentLength,DWORD dwThreadCount);// 任务包处理bool _PartialPackageTask(WINHTTP_PACKAGE_INFO& packInfo);// 分解链接bool _CrackUrl(const _tstring& strUrl, LPWINHTTP_URL_INFO lpUci);// 查询是否支持接收范围bool _IsSupportAcceptRanges(HINTERNET hRequest);// 查询资源大小bool _QueryContentLength(HINTERNET hRequest, PULONGLONG lpUllContentLength);// 获取状态码long _GetStatusCode(HINTERNET hRequest);// 发送请求bool _SendRequest(HINTERNET hRequest, _tstring strHeader,LPVOID lpData, DWORD dwSize);// 读取网络流bool _InternetReadData(HINTERNET hRequest, LPWINHTTP_PACKAGE_INFO lpPackage,bool fFile = false,std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress = nullptr);// 设置请求数据范围bool _SetRequestDataRange(HINTERNET hRequest, LONGLONG nBegin, LONGLONG nEng, bool isHasEnd = TRUE);// 下载分包bool _DownloadPackage(LPWINHTTP_PACKAGE_INFO pPackageInfo);void _SleepMillisecond(int millisecond) const;// 打印警告void _PrintWarn(LPCTSTR lpszError) const;// 打印错误void _PrintError(LPCTSTR lpszError) const;// 宽字节字符串转多字节字符串static std::string _WStrToMultiStr(UINT CodePage, const std::wstring& str);// 多字节字符串转宽字节字符串static std::wstring _MultiStrToWStr(UINT CodePage,const std::string& str);// 字符串转UTF-8编码字符串static std::string _TStrToU8Str(const _tstring& str);// 字符串转宽字节字符串static std::wstring _TStrToWStr(const _tstring& str);// 异步回调函数(暂未使用)static void _InternetStatusCallback(HINTERNET hInternet,DWORD_PTR dwContext,DWORD dwInternetStatus,LPVOID lpvStatusInformation,DWORD dwStatusInformationLength);private:std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> m_cbProgress;std::map<_tstring, std::set<_tstring>> m_RequestHeader;bool m_bSupportAcceptRanges;bool m_bHasSize;bool m_bAbort;
};

CWinHttpHelper.cpp

#include "CWinHttpHelper.h"
#include <strsafe.h>
#include <time.h>
#include <thread>
#include <algorithm>
#include <schannel.h>
#include <deque>#pragma comment(lib, "winhttp.lib")#define HTTP_READ_BLOCK_SIZE                     (1024 * 8)  // 读取块大小#define INTERNET_MAX_HOST_NAME_LENGTH   256
#define INTERNET_MAX_USER_NAME_LENGTH   128
#define INTERNET_MAX_PASSWORD_LENGTH    128
#define INTERNET_MAX_PORT_NUMBER_LENGTH 5           // INTERNET_PORT is unsigned short
#define INTERNET_MAX_PORT_NUMBER_VALUE  65535       // maximum unsigned short value
#define INTERNET_MAX_PATH_LENGTH        2048
#define INTERNET_MAX_SCHEME_LENGTH      32          // longest protocol name length
#define INTERNET_MAX_URL_LENGTH         (INTERNET_MAX_SCHEME_LENGTH \+ sizeof("://") \+ INTERNET_MAX_PATH_LENGTH)// 设置安全标志
const DWORD g_dwSecurityFlags =   SECURITY_FLAG_IGNORE_UNKNOWN_CA |SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |SECURITY_FLAG_IGNORE_CERT_CN_INVALID |SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;// 下载分包信息
typedef struct _WINHTTP_PACKAGE_INFO
{enum DownloadStatus {DS_Downloading = 0,DS_DownloadFinish = 1,DS_DownloadFailed = 2,DS_DownloadCancel = 3,};_tstring strUrl;                    // 链接_tstring strFileName;               // 保存文件名_tstring strVerb;                   // 谓词LPVOID lpBuffer;                    // 保存缓冲ULONGLONG ullDataStartPos;          // 请求数据起始位置ULONGLONG ullDataEndPos;            // 请求数据结束位置ULONGLONG ullDataCurPos;            // 当前数据起始位置ULONGLONG ullDataCurSize;           // 已接收数据大小ULONGLONG ullDataTotalSize;         // 请求数据总大小DWORD dwStatus;                     // 下载状态DWORD dwPartID;                     // 任务ID_WINHTTP_PACKAGE_INFO(const _tstring& url = _T(""), const _tstring& name = _T(""), const _tstring& verb = _T("GET"),LPVOID lpBuffer = nullptr, ULONGLONG begin = 0, ULONGLONG size = 0, DWORD id = 0){this->lpBuffer = lpBuffer;this->strFileName = name;this->strUrl = url;this->strVerb = verb;this->ullDataCurPos = begin;this->ullDataTotalSize = size;this->dwPartID = id;this->dwStatus = DownloadStatus::DS_Downloading;this->ullDataStartPos = begin;this->ullDataEndPos = size > 0 ? begin + size - 1 : begin;this->ullDataCurSize = 0;}}WINHTTP_PACKAGE_INFO, *LPWINHTTP_PACKAGE_INFO;typedef struct _WINHTTP_URL_INFO
{WCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH];WCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH];WCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];WCHAR szPassword[INTERNET_MAX_PASSWORD_LENGTH];WCHAR szUrlPath[INTERNET_MAX_URL_LENGTH];WCHAR szExtraInfo[MAX_PATH];URL_COMPONENTS uc = { 0 };_WINHTTP_URL_INFO(){memset(this, 0, sizeof(*this));this->uc.dwStructSize = sizeof(this->uc);this->uc.lpszUrlPath = this->szUrlPath;this->uc.dwUrlPathLength = _countof(this->szUrlPath);this->uc.lpszScheme = this->szScheme;this->uc.dwSchemeLength = _countof(this->szScheme);this->uc.lpszHostName = this->szHostName;this->uc.dwHostNameLength = _countof(this->szHostName);this->uc.lpszUserName = this->szUserName;this->uc.dwUserNameLength = _countof(this->szUserName);this->uc.lpszPassword = this->szPassword;this->uc.dwPasswordLength = _countof(this->szPassword);this->uc.lpszExtraInfo = this->szExtraInfo;this->uc.dwExtraInfoLength = _countof(this->szExtraInfo);}
}WINHTTP_URL_INFO, *LPWINHTTP_URL_INFO;CWinHttpHelper::CWinHttpHelper():m_bAbort(false),m_bSupportAcceptRanges(false),m_bHasSize(false)
{
}CWinHttpHelper::~CWinHttpHelper()
{}std::string CWinHttpHelper::_WStrToMultiStr(UINT CodePage, const std::wstring& str
)
{//计算缓冲区所需的字节长度int cbMultiByte = ::WideCharToMultiByte(CodePage, 0, str.c_str(), -1, NULL, 0, NULL, 0);std::string strResult(cbMultiByte, 0);//成功则返回写入到指示的缓冲区的字节数size_t nConverted = ::WideCharToMultiByte(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size(), NULL, NULL);//调整内容长度strResult.resize(nConverted);return strResult;
}std::wstring CWinHttpHelper::_MultiStrToWStr(UINT CodePage, const std::string& str
)
{//计算缓冲区所需的字符长度int cchWideChar = ::MultiByteToWideChar(CodePage, 0, str.c_str(), -1, NULL, NULL);std::wstring strResult(cchWideChar, 0);//成功则返回写入到指示的缓冲区的字符数size_t nConverted = ::MultiByteToWideChar(CodePage, 0, str.c_str(), (int)str.size(), &strResult[0], (int)strResult.size());//调整内容长度strResult.resize(nConverted);return strResult;
}std::string CWinHttpHelper::_TStrToU8Str(const _tstring& str
)
{
#ifdef _UNICODEreturn _WStrToMultiStr(CP_UTF8, str);
#elsereturn _WStrToMultiStr(CP_UTF8, _MultiStrToWStr(CP_ACP, str));
#endif
}std::wstring CWinHttpHelper::_TStrToWStr(const _tstring& str
)
{
#ifdef _UNICODEreturn str;
#elsereturn _MultiStrToWStr(CP_ACP, str);
#endif
}void CWinHttpHelper::AddRequestHeader(const _tstring strCaption, const _tstring strData)
{auto itFind = m_RequestHeader.find(strCaption);if (m_RequestHeader.end() == itFind){std::set<_tstring> setData;setData.insert(strData);m_RequestHeader.insert(std::make_pair(strCaption, setData));}else{itFind->second.insert(strData);}
}void CWinHttpHelper::RemoveRequestHeader(const _tstring strCaption, const _tstring strData)
{auto itFind = m_RequestHeader.find(strCaption);if (m_RequestHeader.end() == itFind){return;}if (strData.empty()){m_RequestHeader.erase(itFind);}else{itFind->second.erase(strData);if (itFind->second.empty()){m_RequestHeader.erase(itFind);}}
}void CWinHttpHelper::ClearRequestHeader()
{m_RequestHeader.clear();
}_tstring CWinHttpHelper::_GetRequestHeaderString()
{_tstring strResult;size_t nItemIndex = 0;size_t nItemCount = m_RequestHeader.size();for (const auto& item : m_RequestHeader){strResult += item.first;strResult += _T(": ");size_t nDataIndex = 0;size_t nDataCount = item.second.size();for (const auto& data : item.second){strResult += data;nDataIndex++;if (nDataIndex < nDataCount){strResult += _T(";");}}nItemIndex++;if (nItemIndex < nItemCount){strResult += _T("\r\n");}}return strResult;
}bool CWinHttpHelper::GetContentLength(const _tstring& strUrl, PULONGLONG lpUllContentLength
)
{WINHTTP_URL_INFO urlInfo;HINTERNET hSession = NULL;HINTERNET hConnect = NULL;HINTERNET hRequest = NULL;bool bSuccess = false;if (strUrl.empty() || NULL == lpUllContentLength){return false;}// 分解URLif (!_CrackUrl(strUrl, &urlInfo)){return false;}_tstring strHeader = _GetRequestHeaderString();_tstring strParam;do{// 初始化应用程序对 WinHttp 函数的使用hSession = ::WinHttpOpen(WINHTTP_HTTPS_DOWNLOAD_AGENT, //指向字符串变量的指针,该变量包含调用 WinHTTP 函数的应用程序或实体的名称WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, //所需的访问类型WINHTTP_NO_PROXY_NAME, //代理访问时要使用的代理服务器的名称WINHTTP_NO_PROXY_BYPASS, //代理访问时要使用的代理服务器的密码WINHTTP_FLAG_SECURE_DEFAULTS // 指示影响此函数行为的各种选项的标志);// 打开给定站点的 HTTP 会话hConnect = ::WinHttpConnect(hSession,//由先前调用 WinHttpOpen 返回的有效 HINTERNETWinHTTP 会话句柄urlInfo.szHostName, //HTTP 服务器的主机名urlInfo.uc.nPort, //建立连接的服务器上的 TCP/IP 端口0 //保留参数, 必须为0);if (NULL == hConnect){_PrintError(_T("InternetConnect"));break;}// 创建 HTTPS / HTTP 请求句柄DWORD dwFlags = (INTERNET_SCHEME_HTTPS == urlInfo.uc.nScheme) ? WINHTTP_FLAG_SECURE : 0;hRequest = ::WinHttpOpenRequest(hConnect, //WinHttpConnect 返回的 HTTP 会话的 HINTERNET 连接句柄_TStrToWStr(_T("GET")).c_str(), //请求的 HTTP 谓词urlInfo.szUrlPath, //指定 HTTP 谓词的目标资源名称NULL, //HTTP 版本的字符串的指针WINHTTP_NO_REFERER,//指定从中获取 请求 pwszObjectName 中的 URL 的文档的 URLWINHTTP_DEFAULT_ACCEPT_TYPES, //指定客户端接受的媒体类型dwFlags   //Internet 标志值);if (NULL == hRequest){_PrintError(_T("HttpOpenRequest"));break;}// 设置安全标志DWORD dwSecurityFlags = g_dwSecurityFlags;if (!::WinHttpSetOption(hRequest,  WINHTTP_OPTION_SECURITY_FLAGS, &dwSecurityFlags, sizeof(dwSecurityFlags))){_PrintError(_T("WinHttpSetOption"));break;}// 设置客户端证书上下文if (!::WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0)){_PrintError(_T("WinHttpSetOption"));break;}// 设置超时if (!::WinHttpSetTimeouts(hRequest, 500, 500, 1000, 1000)){_PrintError(_T("WinHttpSetTimeouts"));break;}// 发送请求bool fResult = false;for (int i = 0; i < 5; i++){if (_SendRequest(hRequest, strHeader, nullptr, 0)){fResult = true;break;}_PrintError(_T("_SendRequest Retry"));_tprintf(_T("GetContentLength _SendRequest Retry: %d\r\n"), i + 1);}if (!fResult){_PrintError(_T("SendRequest"));break;}// 等待接收 WinHttpSendRequest 发起的 HTTP 请求的响应if (!::WinHttpReceiveResponse(hRequest, NULL)){_PrintError(_T("WinHttpReceiveResponse"));break;}// 获取状态码DWORD statusCodes = _GetStatusCode(hRequest);if (statusCodes < 200 || statusCodes >= 300){break;}// 记录是否支持接收范围请求m_bSupportAcceptRanges = _IsSupportAcceptRanges(hRequest);// 查询文件大小if (!_QueryContentLength(hRequest, lpUllContentLength)){_PrintError(_T("QueryContentLength"));break;}bSuccess = true;} while (false);// 释放资源if (hRequest)::WinHttpCloseHandle(hRequest);if (hConnect)::WinHttpCloseHandle(hConnect);if (hSession)::WinHttpCloseHandle(hSession);return bSuccess;
}bool CWinHttpHelper::DownloadToFile(const _tstring& strUrl, _tstring strFile, std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress,DWORD dwThreadCount
)
{ULONGLONG ullContentLength = 0;if (strUrl.empty()){return false;}if (strFile.empty()){size_t nPos = strUrl.find_last_of(_T("/"));if (_tstring::npos != nPos){strFile = strUrl.substr(nPos + 1);}}if (strFile.empty()){return false;}m_cbProgress = cbProgress;//限制线程数量dwThreadCount = dwThreadCount < 1 ? 1 : dwThreadCount;dwThreadCount = dwThreadCount > WINHTTP_MAX_THREAD_COUNT ? WINHTTP_MAX_THREAD_COUNT : dwThreadCount;bool fResult = false;for (int i = 0; i < 10; i++){if (GetContentLength(strUrl, &ullContentLength)){fResult = true;break;}_tprintf(_T("GetContentLength retry: %d\r\n"), i + 1);}// 获取资源大小if (!fResult){_PrintError(_T("GetContentLength"));return false;}// 不支持范围请求则仅单线程下载if (!m_bSupportAcceptRanges || !m_bHasSize){dwThreadCount = 1;}// 备份文件if (!_BackupFile(strFile)){_PrintError(_T("BackupFile"));return false;}// 删除文件, 防止下载后改名冲突if (!::DeleteFile(strFile.c_str()) && (ERROR_FILE_NOT_FOUND != ::GetLastError())){return false;}// 清空一下临时文件(如果存在的话)_tstring strTmpFile = strFile + _T(".tmp");(void)_TruncateFile(strTmpFile);// 多线程分段下载if (!_PartialDownload(strUrl, strTmpFile, _T("GET"),  NULL, ullContentLength, dwThreadCount)){_PrintError(_T("_PartialDownload"));return false;}// 下载完成则修改文件名::MoveFile(strTmpFile.c_str(), strFile.c_str());return true;
}bool CWinHttpHelper::DownloadToBuffer(const _tstring& strUrl, std::string& vData,std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress,DWORD dwThreadCount
)
{ULONGLONG ullContentLength = 0;if (strUrl.empty()){return false;}m_cbProgress = cbProgress;//限制线程数量dwThreadCount = dwThreadCount < 1 ? 1 : dwThreadCount;dwThreadCount = dwThreadCount > WINHTTP_MAX_THREAD_COUNT ? WINHTTP_MAX_THREAD_COUNT : dwThreadCount;// 获取资源大小if (!GetContentLength(strUrl, &ullContentLength)){_PrintError(_T("GetContentLength"));return false;}// 不支持范围请求则仅单线程下载if (!m_bSupportAcceptRanges || !m_bHasSize){dwThreadCount = 1;}try{vData.resize(ullContentLength);// 多线程分段下载if (!_PartialDownload(strUrl, _T(""), _T("GET"), (LPVOID)vData.data(), ullContentLength, dwThreadCount)){_PrintError(_T("PartialDownload"));return false;}}catch (...){return false;}return true;
}CWinHttpResult CWinHttpHelper::Get(const _tstring& strUrl, std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress/* = nullptr*/,DWORD dwThreadCount/* = 1*/
)
{return _DoSendRequest(strUrl, _T("GET"), "", cbProgress, dwThreadCount);
}CWinHttpResult CWinHttpHelper::Post(const _tstring& strUrl, std::string& strParam, std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress/* = nullptr*/,DWORD dwThreadCount/* = 1*/
)
{return _DoSendRequest(strUrl, _T("POST"), strParam, cbProgress, dwThreadCount);
}CWinHttpResult CWinHttpHelper::_DoSendRequest(const _tstring& strUrl,const _tstring& strMethod,const std::string& strParam,std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress/* = nullptr*/,DWORD dwThreadCount
)
{CWinHttpResult httpsResponse;WINHTTP_URL_INFO urlInfo;ULONGLONG ullContentLength = 0;HINTERNET hSession = NULL;HINTERNET hConnect = NULL;HINTERNET hRequest = NULL;bool bSuccess = false;// 分解URLif (!_CrackUrl(strUrl, &urlInfo)){return httpsResponse;}_tstring strHeader = _GetRequestHeaderString();do{// 初始化应用程序对 WinHttp 函数的使用hSession = ::WinHttpOpen(WINHTTP_HTTPS_DOWNLOAD_AGENT, //指向字符串变量的指针,该变量包含调用 WinHTTP 函数的应用程序或实体的名称WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, //所需的访问类型WINHTTP_NO_PROXY_NAME, //代理访问时要使用的代理服务器的名称WINHTTP_NO_PROXY_BYPASS, //代理访问时要使用的代理服务器的密码WINHTTP_FLAG_SECURE_DEFAULTS // 指示影响此函数行为的各种选项的标志);if (NULL == hSession){_PrintError(_T("WinHttpOpen"));break;}// 打开给定站点的 HTTP 会话hConnect = ::WinHttpConnect(hSession,//由先前调用 WinHttpOpen 返回的有效 HINTERNETWinHTTP 会话句柄urlInfo.szHostName, //HTTP 服务器的主机名urlInfo.uc.nPort, //建立连接的服务器上的 TCP/IP 端口0 //保留参数, 必须为0);if (NULL == hConnect){_PrintError(_T("WinHttpConnect"));break;}// 创建 HTTPS / HTTP 请求句柄DWORD dwFlags = (INTERNET_SCHEME_HTTPS == urlInfo.uc.nScheme) ? WINHTTP_FLAG_SECURE : 0;hRequest = ::WinHttpOpenRequest(hConnect, //WinHttpConnect 返回的 HTTP 会话的 HINTERNET 连接句柄_TStrToWStr(strMethod).c_str(), //请求的 HTTP 谓词urlInfo.szUrlPath, //指定 HTTP 谓词的目标资源名称NULL, //HTTP 版本的字符串的指针WINHTTP_NO_REFERER,//指定从中获取 请求 pwszObjectName 中的 URL 的文档的 URLWINHTTP_DEFAULT_ACCEPT_TYPES, //指定客户端接受的媒体类型dwFlags   //Internet 标志值);// 发送请求if (!_SendRequest(hRequest, strHeader, (LPVOID)strParam.data(), (DWORD)strParam.size())){_PrintError(_T("SendRequest"));break;}// 等待接收 WinHttpSendRequest 发起的 HTTP 请求的响应if (!::WinHttpReceiveResponse(hRequest, NULL)){break;}// 记录状态码httpsResponse.code = _GetStatusCode(hRequest);// 查询文件大小if (!_QueryContentLength(hRequest, &ullContentLength)){_PrintError(_T("QueryContentLength"));break;}// 捕获异常try{httpsResponse.result.resize(ullContentLength);//资源过小检查if (ullContentLength < WINHTTP_DOWNLOAD_MINIMUM_SIZE){dwThreadCount = 1;}// 不支持范围请求则仅单线程下载if (!m_bSupportAcceptRanges || !m_bHasSize || ullContentLength < WINHTTP_DOWNLOAD_MINIMUM_SIZE){dwThreadCount = 1;}if (dwThreadCount <= 1){WINHTTP_PACKAGE_INFO packageInfo;packageInfo.lpBuffer = (LPVOID)httpsResponse.result.data();packageInfo.ullDataTotalSize = ullContentLength;packageInfo.ullDataCurPos = 0;if (!_InternetReadData(hRequest, &packageInfo, false, cbProgress)){_PrintError(_T("_InternetReadData"));break;}}else{if (!_PartialDownload(strUrl, _T(""), strMethod, (LPVOID)httpsResponse.result.data(), ullContentLength, dwThreadCount)){break;}}}catch (...){}bSuccess = true;} while (false);// 释放资源if (hRequest)::WinHttpCloseHandle(hRequest);if (hConnect)::WinHttpCloseHandle(hConnect);if (hSession)::WinHttpCloseHandle(hSession);return httpsResponse;
}void CWinHttpHelper::_TruncateFile(const _tstring& strPath)
{HANDLE hFile = INVALID_HANDLE_VALUE;hFile = ::CreateFile(strPath.c_str(),GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE,NULL,TRUNCATE_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL);if (INVALID_HANDLE_VALUE != hFile){::CloseHandle(hFile);}
}bool CWinHttpHelper::_BackupFile(const _tstring& strPath)
{TCHAR szBuf[MAX_PATH] = { 0 };_tstring strBakFile;bool isBackupOk = false;if (0 == WINHTTP_FILE_BACKUP_MAX_CONUT){return true;}for (int i = 1; i <= WINHTTP_FILE_BACKUP_MAX_CONUT; i++){::StringCchPrintf(szBuf, _countof(szBuf), _T("%02d"), i);strBakFile = strPath + _T(".") + szBuf + _T(".bak");if (::MoveFile(strPath.c_str(), strBakFile.c_str())){isBackupOk = true;break;}if (ERROR_FILE_NOT_FOUND == ::GetLastError()){isBackupOk = true;break;}}//备份失败, 则删除最早一个备份文件if (!isBackupOk){_tstring strOld;_tstring strNew;::StringCchPrintf(szBuf, _countof(szBuf), _T("%02d"), 1);strOld = strPath + _T(".") + szBuf + _T(".bak");// 无法删除if (!::DeleteFile(strOld.c_str())){return false;}for (int i = 1; i < WINHTTP_FILE_BACKUP_MAX_CONUT; i++){::StringCchPrintf(szBuf, _countof(szBuf), _T("%02d"), i);strNew = strPath + _T(".") + szBuf + _T(".bak");;::StringCchPrintf(szBuf, _countof(szBuf), _T("%02d"), i + 1);strOld = strPath + _T(".") + szBuf + _T(".bak");;if (!::MoveFile(strOld.c_str(), strNew.c_str())){break;}}::StringCchPrintf(szBuf, _countof(szBuf), _T("%02d"), WINHTTP_FILE_BACKUP_MAX_CONUT);strBakFile = strPath + _T(".") + szBuf + _T(".bak");if (::MoveFile(strPath.c_str(), strBakFile.c_str())){isBackupOk = true;}}return isBackupOk;
}void CWinHttpHelper::_ProcessProcess(std::vector<WINHTTP_PACKAGE_INFO>& taskPackages)
{ULONGLONG ullLastDownload = 0;clock_t refreshInterval = WINHTTP_PROGRESS_UPDATE_INTERVAL_TIME;clock_t lastTime = ::clock();clock_t lastProgressTime = ::clock();clock_t speedTime = WINHTTP_SPEED_UPDATE_INTERVAL_TIME;double lfRemainTime = 0;double lfSpeed = 0.0f;bool fQuit = false;clock_t startTime = ::clock();std::deque<double> dqCurSpeed;// 等待所有线程结束下载while (!fQuit && !m_bAbort){ULONGLONG ullDownloaded = 0;ULONGLONG ullTotalLength = 0;DWORD dwDownloadingCount = 0;// 统计已下载量 与 总下载量for (const auto& item : taskPackages){ullDownloaded += item.ullDataCurSize;ullTotalLength += item.ullDataTotalSize;if (WINHTTP_PACKAGE_INFO::DownloadStatus::DS_Downloading == item.dwStatus){dwDownloadingCount++;}}// 速度计算clock_t curTime = ::clock();if (curTime - lastTime >= speedTime || 0 == dwDownloadingCount || curTime - startTime < speedTime){if (curTime - lastTime >= speedTime){lfSpeed = (double)(ullDownloaded - ullLastDownload) / ((double)speedTime / 1000.0f);}if (0 == dwDownloadingCount){lfSpeed = (double)(ullDownloaded - ullLastDownload) / ((double)(curTime - lastTime) / 1000.0f);}if (curTime - startTime < speedTime){lfSpeed = (double)(ullDownloaded - ullLastDownload) / ((double)(curTime - lastTime) / 1000.0f);}if (isinf(lfSpeed) || isnan(lfSpeed)){lfSpeed = 0.0f;}// 统计最近 10 次下载速度平均值作为下载预估剩余时间的速度if (dqCurSpeed.size() < 10){dqCurSpeed.push_back(lfSpeed);}else{dqCurSpeed.pop_front();dqCurSpeed.push_back(lfSpeed);}double lfAveSpeed = 0.0f;for (const auto& item : dqCurSpeed){lfAveSpeed += item;}lfAveSpeed /= dqCurSpeed.size();// 计算剩余时间lfRemainTime = ((double)(ullTotalLength - ullDownloaded)) / lfAveSpeed;lastTime = curTime;ullLastDownload = ullDownloaded;}// 进度报告if (curTime - lastProgressTime > refreshInterval || 0 == dwDownloadingCount){if (m_cbProgress){WINHTTP_PROGRESS_INFO progress = { 0 };progress.lfProgress = (double)ullDownloaded / (double)ullTotalLength;progress.ullCur = ullDownloaded;progress.ullTotal = ullTotalLength;progress.lfSpeed = lfSpeed;progress.activeThreads = dwDownloadingCount;progress.totalThreads = taskPackages.size();progress.costTime = curTime - startTime;progress.lfRemainTime = lfRemainTime;if (!m_cbProgress(progress)){m_bAbort = true;}}lastProgressTime = curTime;if (0 == dwDownloadingCount){fQuit = true;}}_SleepMillisecond(50);}
}bool CWinHttpHelper::_PartialDownload(const _tstring& strUrl,const _tstring& strUrlFileName,const _tstring& strVerb, LPVOID lpBuf,ULONGLONG ullContentLength,DWORD dwThreadCount
)
{//资源过小检查if (ullContentLength < WINHTTP_DOWNLOAD_MINIMUM_SIZE){dwThreadCount = 1;}// 每个包大小ULONGLONG ullSinglePackageSize = ullContentLength / dwThreadCount;std::vector<std::thread> downloadThreads;// 保留容量, 防止发生空间分配导致迭代器失效std::vector<WINHTTP_PACKAGE_INFO> m_downloadPackages;m_downloadPackages.reserve(dwThreadCount);// 添加下载任务for (DWORD i = 0; i < dwThreadCount; i++){ULONGLONG ullBeginPos = ullSinglePackageSize * i;ULONGLONG ullPackageSize = (i != dwThreadCount - 1) ? ullSinglePackageSize : ullContentLength - ullBeginPos;if (lpBuf){m_downloadPackages.emplace_back(WINHTTP_PACKAGE_INFO(strUrl, _T(""), strVerb, (LPBYTE)lpBuf + ullBeginPos, ullBeginPos, ullPackageSize, i));}else{m_downloadPackages.emplace_back(WINHTTP_PACKAGE_INFO(strUrl, strUrlFileName, strVerb, nullptr, ullBeginPos, ullPackageSize, i));}downloadThreads.emplace_back(std::thread([this, &m_downloadPackages, i]() {_PartialPackageTask(m_downloadPackages[i]);}));}// 创建进度报告线程std::thread processTask([this, &m_downloadPackages]() {_ProcessProcess(m_downloadPackages);});processTask.join();// 等待所有下载线程结束for (auto &item : downloadThreads){item.join();}// 获取每个线程的下载状态, 全部下载完成才算完成bool isAllFinish = std::all_of(m_downloadPackages.begin(), m_downloadPackages.end(), [](const WINHTTP_PACKAGE_INFO& item) {return WINHTTP_PACKAGE_INFO::DownloadStatus::DS_DownloadFinish == item.dwStatus;});m_bAbort = false;return isAllFinish;
}bool CWinHttpHelper::_PartialPackageTask(WINHTTP_PACKAGE_INFO& packInfo
)
{bool fResult = false;while (!m_bAbort){packInfo.dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_Downloading;if (_DownloadPackage(&packInfo)){packInfo.dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_DownloadFinish;fResult = true;break;}packInfo.dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_DownloadFailed;}if (!fResult){m_bAbort = true;_tprintf(_T("[Fail] Task ID: %d\r\n"), packInfo.dwPartID);}else{//_tprintf(_T("[OK] Task ID: %d\r\n"), packInfo.dwPartID);}return fResult;
}void CWinHttpHelper::_SleepMillisecond(int millisecond) const
{int span = 10;if (millisecond < span){std::this_thread::sleep_for(std::chrono::milliseconds(span));return;}// 分段休眠, 防止中断休眠不及时clock_t tBegin = clock();while (!m_bAbort){if (clock() - tBegin > millisecond){break;}std::this_thread::sleep_for(std::chrono::milliseconds(span));}
}bool CWinHttpHelper::_DownloadPackage(LPWINHTTP_PACKAGE_INFO pPackageInfo)
{WINHTTP_URL_INFO urlInfo;HINTERNET hSession = NULL;HINTERNET hConnect = NULL;HINTERNET hRequest = NULL;bool bSuccess = false;// 分解URLif (!_CrackUrl(pPackageInfo->strUrl, &urlInfo)){return false;}_tstring strHeader = _GetRequestHeaderString();do{// 初始化应用程序对 WinHttp 函数的使用hSession = ::WinHttpOpen(WINHTTP_HTTPS_DOWNLOAD_AGENT, //指向字符串变量的指针,该变量包含调用 WinHTTP 函数的应用程序或实体的名称WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, //所需的访问类型WINHTTP_NO_PROXY_NAME, //代理访问时要使用的代理服务器的名称WINHTTP_NO_PROXY_BYPASS, //代理访问时要使用的代理服务器的密码WINHTTP_FLAG_SECURE_DEFAULTS // 指示影响此函数行为的各种选项的标志);if (NULL == hSession){_PrintError(_T("InternetOpen"));break;}// 打开给定站点的 HTTP 会话hConnect = ::WinHttpConnect(hSession,//由先前调用 WinHttpOpen 返回的有效 HINTERNETWinHTTP 会话句柄urlInfo.szHostName, //HTTP 服务器的主机名urlInfo.uc.nPort, //建立连接的服务器上的 TCP/IP 端口0 //保留参数, 必须为0);if (NULL == hConnect){_PrintError(_T("InternetConnect"));break;}// 创建 HTTPS / HTTP 请求句柄DWORD dwFlags = (INTERNET_SCHEME_HTTPS == urlInfo.uc.nScheme) ? WINHTTP_FLAG_SECURE : 0;hRequest = ::WinHttpOpenRequest(hConnect, //WinHttpConnect 返回的 HTTP 会话的 HINTERNET 连接句柄_TStrToWStr(pPackageInfo->strVerb).c_str(), //请求的 HTTP 谓词urlInfo.szUrlPath, //指定 HTTP 谓词的目标资源名称NULL, //HTTP 版本的字符串的指针WINHTTP_NO_REFERER,//指定从中获取 请求 pwszObjectName 中的 URL 的文档的 URLWINHTTP_DEFAULT_ACCEPT_TYPES, //指定客户端接受的媒体类型dwFlags   //Internet 标志值);if (NULL == hRequest){_PrintError(_T("HttpOpenRequest"));break;}// 设置请求文件数据范围if (!_SetRequestDataRange(hRequest, pPackageInfo->ullDataCurPos, pPackageInfo->ullDataEndPos, true)){_PrintError(_T("SetContentRange"));break;}// 设置超时BOOL fResult = ::WinHttpSetTimeouts(hRequest, WINHTTP_RESOLVE_TIME_OUT, WINHTTP_CONNECT_TIME_OUT, WINHTTP_SEND_TIME_OUT, WINHTTP_RECEIVE_TIME_OUT);// 发送请求for (int i = 0; i < 10 && !m_bAbort; i++){if (_SendRequest(hRequest, strHeader, nullptr, 0)){fResult = true;break;}}if (!fResult){_PrintError(_T("SendRequest"));break;}// 等待接收 WinHttpSendRequest 发起的 HTTP 请求的响应if (!::WinHttpReceiveResponse(hRequest, NULL)){_PrintError(_T("WinHttpReceiveResponse"));break;}// 查询文件大小ULONGLONG UllContentLength = 0;if (!_QueryContentLength(hRequest, &UllContentLength)){_PrintError(_T("_QueryContentLength"));break;}// 读取数据到文件/缓冲if (!_InternetReadData(hRequest, pPackageInfo, NULL == pPackageInfo->lpBuffer)){_PrintError(_T("_InternetReadData"));break;}bSuccess = true;} while (false);// 释放资源if (hRequest)::WinHttpCloseHandle(hRequest);if (hConnect)::WinHttpCloseHandle(hConnect);if (hSession)::WinHttpCloseHandle(hSession);return bSuccess;
}bool CWinHttpHelper::_SetRequestDataRange(HINTERNET hRequest, LONGLONG nBegin, LONGLONG nEng, bool isHasEnd
)
{WCHAR szBuf[MAX_PATH] = { 0 };if (isHasEnd){(void)::StringCchPrintfW(szBuf, _countof(szBuf), L"Range:bytes=%lld-%lld", nBegin, nEng);}else{(void)::StringCchPrintfW(szBuf, _countof(szBuf), L"Range:bytes=%lld-", nBegin);}return ::WinHttpAddRequestHeaders(hRequest, szBuf, (DWORD)wcslen(szBuf), 0);
}bool CWinHttpHelper::_InternetReadData(HINTERNET hRequest,LPWINHTTP_PACKAGE_INFO lpPackage,bool fFile/* = false*/,std::function<bool(const WINHTTP_PROGRESS_INFO& progress)> cbProgress/* = nullptr*/
)
{LARGE_INTEGER liDistanceToMove = { 0 };HANDLE hFile = INVALID_HANDLE_VALUE;bool bDownloadFinish = false;bool bRet = false;ULONGLONG ullCurRead = 0;ULONGLONG ullTotal = lpPackage->ullDataTotalSize;clock_t lastTime = ::clock();clock_t updateInterval = 100;LPBYTE lpBufPos = (LPBYTE)lpPackage->lpBuffer;lpPackage->dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_Downloading;std::vector<uint8_t> vData;do{if (fFile){// 共享读写 创建/打开 文件, 多线程读写hFile = ::CreateFile(lpPackage->strFileName.c_str(),GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,NULL);if (INVALID_HANDLE_VALUE == hFile){_PrintError(_T("CreateFile"));m_bAbort = true;break;}// 设置数据写入位置liDistanceToMove.QuadPart = lpPackage->ullDataCurPos;::SetFilePointerEx(hFile, liDistanceToMove, NULL, FILE_BEGIN);}do{// 检查可用数据DWORD dwAvailable = 0;DWORD dwRead = 0;if (!::WinHttpQueryDataAvailable(hRequest, &dwAvailable)){lpPackage->dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_DownloadFailed;_PrintError(_T("WinHttpQueryDataAvailable"));if (ERROR_WINHTTP_TIMEOUT != ::GetLastError()){m_bAbort = true;}break;}try{vData.resize(dwAvailable);}catch (...){_PrintError(_T("std::vector resize"));break;}// 读取网络数据if (dwAvailable > 0){bRet = ::WinHttpReadData(hRequest, vData.data(), dwAvailable, &dwRead);if (!bRet){lpPackage->dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_DownloadFailed;_PrintError(_T("WinHttpReadData"));break;}// 写入到文件if (fFile){DWORD dwWritten = 0;if (!::WriteFile(hFile, vData.data(), dwRead, &dwWritten, NULL)){lpPackage->dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_DownloadFailed;_PrintError(_T("WriteFile"));break;}}else{// 写入到缓冲memcpy(lpBufPos, vData.data(), dwRead);lpBufPos += dwRead;}}// 记录当前线程数据位置lpPackage->ullDataCurPos += dwRead;lpPackage->ullDataCurSize += dwRead;clock_t curTime = ::clock();ullCurRead += dwRead;if (curTime - lastTime > updateInterval || 0 == dwRead){lastTime = curTime;// 进度回调if (cbProgress){WINHTTP_PROGRESS_INFO progress = { 0 };progress.lfProgress = (double)ullCurRead / (double)ullTotal;progress.ullCur = ullCurRead;progress.ullTotal = ullTotal;if (cbProgress(progress)){m_bAbort = true;}}}// 检查下载是否完成if (!dwAvailable){bDownloadFinish = true;lpPackage->dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_DownloadFinish;break;}// 中断下载检查if (m_bAbort){lpPackage->dwStatus = WINHTTP_PACKAGE_INFO::DownloadStatus::DS_DownloadCancel;break;}} while (bRet && !m_bAbort);} while (false);if (INVALID_HANDLE_VALUE != hFile){::CloseHandle(hFile);}return bDownloadFinish;
}bool CWinHttpHelper::_IsSupportAcceptRanges(HINTERNET hRequest)
{WCHAR szBuf[MAX_PATH] = { 0 };DWORD dwBufferLength = sizeof(szBuf);DWORD dwIndex = 0;if (!::WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_ACCEPT_RANGES, WINHTTP_HEADER_NAME_BY_INDEX, (LPVOID)szBuf, &dwBufferLength, &dwIndex)){return false;}if (0 == _wcsicmp(szBuf, L"bytes")){return true;}return false;
}bool CWinHttpHelper::_QueryContentLength(HINTERNET hRequest, PULONGLONG lpUllContentLength
)
{ULONGLONG ullContentLength = 0;DWORD dwBufferLength = sizeof(ullContentLength);// 查询资源大小if (!::WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER64,WINHTTP_HEADER_NAME_BY_INDEX, //标头名称&ullContentLength, //接收信息的缓冲区&dwBufferLength, //数据缓冲区的长度NULL    //从零开始的标头索引的指针,用于枚举具有相同名称的多个标头)){m_bHasSize = false;_PrintError(_T("QueryContentLength HttpQueryInfo"));*lpUllContentLength = 0;return false;}m_bHasSize = true;*lpUllContentLength = ullContentLength;return true;
}long CWinHttpHelper::_GetStatusCode(HINTERNET hRequest)
{DWORD dwRespCode = 0;DWORD dwBufferLength = sizeof(dwRespCode);// 查询请求状态码if (!::WinHttpQueryHeaders(hRequest, //WinHttpOpenRequest 返回的 HINTERNET 请求句柄WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, //指定“查询信息标志”页上列出的属性标志和修饰符标志的组合WINHTTP_HEADER_NAME_BY_INDEX, //标头名称&dwRespCode, //接收信息的缓冲区&dwBufferLength, //数据缓冲区的长度NULL    //从零开始的标头索引的指针,用于枚举具有相同名称的多个标头)){return dwRespCode;}return dwRespCode;
}bool CWinHttpHelper::_SendRequest(HINTERNET hRequest, _tstring strHeader,LPVOID lpData, DWORD dwSize
)
{std::wstring wstrHeader = _TStrToWStr(strHeader);LPCWSTR lpHeader = (LPCWSTR)wstrHeader.data();size_t dwHeaderSize = wstrHeader.size();if (wstrHeader.empty()){lpHeader = WINHTTP_NO_ADDITIONAL_HEADERS;dwHeaderSize = 0;}// 将指定的请求发送到 HTTP 服务器if (::WinHttpSendRequest(hRequest, //WinHttpOpenRequest 返回的 HINTERNET 句柄lpHeader,//要追加到请求的其他标头dwHeaderSize,//附加标头的长度(以字符为单位)lpData,//请求标头之后发送的任何可选数据dwSize, //可选数据的长度(以字节为单位)dwSize, //发送的总数据的长度NULL)){return true;}// 安全 HTTP 服务器需要客户端证书if (ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED != ::GetLastError()){return false;}// 没有客户端证书if (!::WinHttpSetOption(hRequest,WINHTTP_OPTION_CLIENT_CERT_CONTEXT,WINHTTP_NO_CLIENT_CERT_CONTEXT,0)){return false;}// 再次发送请求if (::WinHttpSendRequest(hRequest, //WinHttpOpenRequest 返回的 HINTERNET 句柄lpHeader,//要追加到请求的其他标头dwHeaderSize,//附加标头的长度(以字符为单位)lpData,//请求标头之后发送的任何可选数据dwSize, //可选数据的长度(以字节为单位)dwSize, //发送的总数据的长度NULL)){return true;}return false;
}bool CWinHttpHelper::_CrackUrl(const _tstring& strUrl, LPWINHTTP_URL_INFO lpurlInfo
)
{// 将 URL 分解到其组件部件中if (!WinHttpCrackUrl(_TStrToWStr(strUrl).c_str(), 0, 0, &lpurlInfo->uc)){return false;}if (0 < ::wcslen(lpurlInfo->uc.lpszExtraInfo)){::wcscat_s(lpurlInfo->uc.lpszUrlPath, _countof(lpurlInfo->szUrlPath), lpurlInfo->uc.lpszExtraInfo);}// 协议检查if (!(INTERNET_SCHEME_HTTPS == lpurlInfo->uc.nScheme || INTERNET_SCHEME_HTTP == lpurlInfo->uc.nScheme)){return false;}return true;
}void CWinHttpHelper::_PrintError(LPCTSTR lpszError) const
{::_tprintf(_T("[Error] %s LastError[%d] Tid: %d\n"), lpszError, ::GetLastError(), ::GetCurrentThreadId());
}void CWinHttpHelper::_PrintWarn(LPCTSTR lpszError)  const
{::_tprintf(_T("[Warn] %s LastError[%d] Tid: %d\n"), lpszError, ::GetLastError(), ::GetCurrentThreadId());
}void CWinHttpHelper::_InternetStatusCallback(HINTERNET hSession, DWORD_PTR dwContext, DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength
)
{UNREFERENCED_PARAMETER(hSession);UNREFERENCED_PARAMETER(dwContext);UNREFERENCED_PARAMETER(dwStatusInformationLength);}

 main.cpp

#include "CDownloadFile.h"
#include "CWinHttpHelper.h"
#include "CWinHttp.h"
#include <locale>
#include <iostream>#define GET_URL1  R"(https://gitee.com/flame_cyclone/fcassistant-binary/releases/download/1.0.1.15/LuaExample.lua)"
#define GET_URL2  R"(https://gitee.com/flame_cyclone/fcassistant-binary/releases/download/1.0.1.15/LuaExample.lua2)"#define POST_URL  R"(https://gitee.com/flame_cyclone/fcassistant-binary/releases/download/1.0.1.15/LuaExample.lua)"
#define UPDATE_URL                           _T("https://gitee.com/flame_cyclone/fc_font_tool/raw/master/Release/update.json")
#define UPDATE_URL2                           _T("https://gitee.com/flame_cyclone/fc_font_tool/releases/download/1.0.0.4/FC_Font_Tool.exe")#define TEST_LINK _T("https://cn.download.nvidia.com/Windows/561.09/561.09-desktop-win10-win11-64bit-international-dch-whql.exe")#define TEST_LINK_AMD _T("https://drivers.amd.com/drivers/whql-amd-software-adrenalin-edition-24.8.1-win10-win11-aug-rdna.exe")int main()
{setlocale(LC_ALL, "");{CWinHttpHelper obj;obj.AddRequestHeader(_T("Content-Type"), _T("application/json;charset=UTF-8"));obj.AddRequestHeader(_T("Accept"), _T("*/*"));obj.AddRequestHeader(_T("Content-Type"), _T("application/json;charset=UTF-8"));obj.AddRequestHeader(_T("Referer"), _T("https://www.amd.com/"));std::string str;auto res = obj.Get(UPDATE_URL2, nullptr, 2);std::string vBuf;obj.DownloadToBuffer(TEST_LINK_AMD,vBuf,[](const WINHTTP_PROGRESS_INFO& progress) {_tprintf(_T("%d/%d cost: %.3lfs Progress: %.3lf%% %lld/%lld Speed: %.1lf Mbps %.1lfMB/s %.1lfKB/s RemainTime: %.1lfs\n"),progress.activeThreads,progress.totalThreads, (double)progress.costTime / 1000.0f,progress.lfProgress * 100, progress.ullCur, progress.ullTotal,progress.lfSpeed / (1024.0f * 1024.0f) * 8.0f,progress.lfSpeed / (1024.0f * 1024.0f),progress.lfSpeed / (1024.0f), progress.lfRemainTime);return true;}, 32);return 0;}return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com