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\n", 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");
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM