核心函數原型
UINT InternetGetFile(HINTERNET hOpen, LPCSTR szUrl, LPCSTR szFileName,
HWND hProgressDlg, int idStatusText, int idProgressBar);
關鍵實作細節
// 1. 開啟 URL(禁用快取,強制重新下載)
HINTERNET hConnect = InternetOpenUrlA(hOpen, szUrl,
"Accept: */*\r\n\r\n", -1,
INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD,
0);
// 2. 開啟本地檔案(二進位寫入)
FILE* fp = fopen(szFileName, "wb");
// 3. 取得檔案總大小(用於進度條)
DWORD fileSize = 0, sizeLen = 4;
HttpQueryInfo(hConnect, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&fileSize, &sizeLen, nullptr);
// 4. 分塊下載迴圈(16KB 緩衝區)
BYTE buffer[16384];
DWORD totalRead = 0, readSize;
DWORD startTime = timeGetTime();
do {
if (!InternetReadFile(hConnect, buffer, 16384, &readSize)) break;
if (readSize == 0) break; // EOF
fwrite(buffer, 1, readSize, fp);
totalRead += readSize;
// 更新進度條
if (fileSize && hProgressDlg) {
int percent = (totalRead * 100) / fileSize;
SendDlgItemMessage(hProgressDlg, idProgressBar, WM_USER+2, percent, 0);
}
// 計算並顯示下載速度
DWORD elapsed = timeGetTime() - startTime;
if (elapsed == 0) elapsed = 1;
float speedKB = (totalRead / 1024.0f) / (elapsed / 1000.0f);
char status[260];
sprintf(status, "%d KB / %d KB @ %.1f KB/s",
totalRead/1024, fileSize/1024, speedKB);
SetDlgItemText(hProgressDlg, idStatusText, status);
} while (true);
fclose(fp);
return 0;
必要連結庫
wininet.lib:Internet API
winmm.lib:timeGetTime 計算速度
健壯性建議
- 支援斷點續傳:記錄
totalRead,下次以 Range 標頭續傳
- 異常處理:網路中斷、磁碟滿、伺服器錯誤碼檢查
- 大檔案:使用 64 位元位移與
InternetSetFilePointer