zoukankan      html  css  js  c++  java
  • c++ 使用WinHTTP实现文件下载功能

    因为要项目中要想要实现一个软件自动更新的功能,之前是使用socket直接下载。但切换下载源的时候很麻烦。所以换用http方式。
    网上找了很多资料,基本上就是下面几种:
    1.curllib //功能强大太但太麻烦而且没必要
    2.MFC自带的功能 // 项目不是使用的MFC所以舍
    3.IE控件下载 // 没办法获取到进度,而且因为不能获取到总大小所以很容易下载的资源不完整。

    思来想去,最后还是使用WinHTTP,比较简单快捷,而且功能上基本上都能够满足。

    #include <stdio.h>
    #include <Windows.h>
    #include <Winhttp.h>
    #pragma comment(lib,"Winhttp.lib")
    
    
    typedef void(*DownLoadCallback)(int ContentSize, int CUR_LEN);
    
    
    typedef struct _URL_INFO
    {
    	WCHAR szScheme[512];
    	WCHAR szHostName[512];
    	WCHAR szUserName[512];
    	WCHAR szPassword[512];
    	WCHAR szUrlPath[512];
    	WCHAR szExtraInfo[512];
    }URL_INFO, *PURL_INFO;
    
    
    void dcallback(int ContentSize, int file_size)
    {
    	printf("count:%d,size:%d
    ", ContentSize, file_size);
    }
    
    void download(const wchar_t *Url, const wchar_t *FileName, DownLoadCallback Func)
    {
    	URL_INFO url_info = { 0 };
    	URL_COMPONENTSW lpUrlComponents = { 0 };
    	lpUrlComponents.dwStructSize = sizeof(lpUrlComponents);
    	lpUrlComponents.lpszExtraInfo = url_info.szExtraInfo;
    	lpUrlComponents.lpszHostName = url_info.szHostName;
    	lpUrlComponents.lpszPassword = url_info.szPassword;
    	lpUrlComponents.lpszScheme = url_info.szScheme;
    	lpUrlComponents.lpszUrlPath = url_info.szUrlPath;
    	lpUrlComponents.lpszUserName = url_info.szUserName;
    
    	lpUrlComponents.dwExtraInfoLength = 
    		lpUrlComponents.dwHostNameLength = 
    		lpUrlComponents.dwPasswordLength = 
    		lpUrlComponents.dwSchemeLength = 
    		lpUrlComponents.dwUrlPathLength = 
    		lpUrlComponents.dwUserNameLength = 512;
    
    	WinHttpCrackUrl(Url, 0, ICU_ESCAPE, &lpUrlComponents);
    
    	// 创建一个会话
    	HINTERNET hSession = WinHttpOpen(NULL, WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0);
    	DWORD dwReadBytes, dwSizeDW = sizeof(dwSizeDW), dwContentSize, dwIndex = 0;
    	// 创建一个连接
    	HINTERNET hConnect = WinHttpConnect(hSession, lpUrlComponents.lpszHostName, lpUrlComponents.nPort, 0);
    	// 创建一个请求,先查询内容的大小
    	HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"HEAD", lpUrlComponents.lpszUrlPath, L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_REFRESH);
    	WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
    	WinHttpReceiveResponse(hRequest, 0);
    	WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, NULL, &dwContentSize, &dwSizeDW, &dwIndex);
    	WinHttpCloseHandle(hRequest);
    
    	// 创建一个请求,获取数据
    	hRequest = WinHttpOpenRequest(hConnect, L"GET", lpUrlComponents.lpszUrlPath, L"HTTP/1.1", WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_REFRESH);
    	WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
    	WinHttpReceiveResponse(hRequest, 0);
    
    	// 分段回调显示进度
    	DWORD BUF_LEN = 1024, ReadedLen = 0;
    	BYTE *pBuffer = NULL;
    	pBuffer = new BYTE[BUF_LEN];
    
    	HANDLE hFile = CreateFileW(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    
    	while (dwContentSize > ReadedLen)
    	{
    		ZeroMemory(pBuffer, BUF_LEN);
    		WinHttpReadData(hRequest, pBuffer, BUF_LEN, &dwReadBytes);
    		ReadedLen += dwReadBytes;
    
    		// 写入文件
    		WriteFile(hFile, pBuffer, dwReadBytes, &dwReadBytes, NULL);
    		// 进度回调
    		Func(dwContentSize, ReadedLen);
    
    	}
    
    	CloseHandle(hFile);
    	delete pBuffer;
    
    
    	/*
    	// 一次性写入整个文件
    	BYTE *pBuffer = NULL;
    
    	pBuffer = new BYTE[dwContentSize];
    	ZeroMemory(pBuffer, dwContentSize);
    	//do{
    		WinHttpReadData(hRequest, pBuffer, dwContentSize, &dwReadBytes);
    		Func(dwContentSize, dwReadBytes);
    	//} while (dwReadBytes == 0);
    	
    
    	HANDLE hFile = CreateFileW(FileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    	WriteFile(hFile, pBuffer, dwContentSize, &dwReadBytes, NULL);
    	CloseHandle(hFile);
    
    	delete pBuffer;
    	*/
    	WinHttpCloseHandle(hRequest);
    	WinHttpCloseHandle(hConnect);
    	WinHttpCloseHandle(hSession);
    
    	
    }
    
    
    
    int main(int argc, char* argv[])
    {
    	download(L"http://sw.bos.baidu.com/sw-search-sp/software/58d7820029ae7/BaiduMusic_10.1.7.7_setup.exe", L"./BaiduMusic_10.1.7.7_setup.exe", &dcallback);
    	system("pause");
    }
    
  • 相关阅读:
    centos7.6 使用yum安装mysql5.7
    解决hadoop本地库问题
    docker-compose 启动警告
    docker 安装zabbix5.0 界面乱码问题解决
    docker 部署zabbix问题
    zookeeper 超时问题
    hbase regionserver异常宕机
    (转载)hadoop 滚动升级
    hadoop Requested data length 86483783 is longer than maximum configured RPC length
    zkfc 异常退出问题,报错Received stat error from Zookeeper. code:CONNECTIONLOSS
  • 原文地址:https://www.cnblogs.com/jkcx/p/6374026.html
Copyright © 2011-2022 走看看