為避免每次修改小錯誤都需通知使用者手動更新,開發 HTTP 架構的線上自動更新程式。相較 FTP 方案,HTTP 無需帳號密碼傳輸,資安風險較低。
update.exe 程式名 版本號 更新設定檔URL
範例:update.exe VolleyMail 3.0 https://www.extice.com/update/update.ini
CStringArray paraArr;
CUpdateApp::GetCmdLinePara(paraArr);
dlg.m_strSoft = paraArr.GetAt(0);
dlg.m_strVersion = paraArr.GetAt(1);
AfxParseURL(paraArr.GetAt(2), dwType, dlg.m_strServer,
dlg.m_strIniPath, dlg.m_dwPort);
m_cis.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 5);
m_pHttp = m_cis.GetHttpConnection(m_strServer, m_dwPort);
m_lbProduct.AddString(m_strSoft + " " + m_strVersion);
// 下載 update.ini 至暫存目錄
CStdioFile csf;
csf.Open(m_strTempDir + "\\update.ini",
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
char buf[2048]; int n;
while ((n = pFile->Read(buf, 2048)) > 0) csf.Write(buf, n);
// 讀取最新版本號
char verBuf[128];
::GetPrivateProfileString(m_strSoft, "VERSION", "1.0",
verBuf, sizeof(verBuf), m_strTempDir + "\\update.ini");
m_strNewVer = verBuf;
if (atof(m_strVersion) >= atof(verBuf)) {
m_strStatus = "您現在用的版本已是最新的!";
UpdateData(FALSE);
m_buOK.EnableWindow(FALSE);
return;
}
DWORD CUpdateDlg::FindAppProcessID() {
HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
PROCESSENTRY32 pe; pe.dwSize = sizeof(pe);
if (::Process32First(hSnap, &pe)) {
do {
CString name = pe.szExeFile;
if (!name.CompareNoCase(m_strSoft + ".exe")) {
::CloseHandle(hSnap);
return pe.th32ProcessID;
}
} while (::Process32Next(hSnap, &pe));
}
::CloseHandle(hSnap);
return -1;
}
若程式正在執行,提示使用者手動關閉或強制 TerminateProcess 結束。
pFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH, str); // 取得檔案大小
DWORD dwLen = atol(str);
// 先下載至 .upg 暫存檔,防止中斷損壞原檔
CStdioFile csf;
if (!csf.Open(str + ".upg",
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite)) {
AfxMessageBox("寫入檔案錯誤!檔案正在使用中,請先關閉程式!", MB_ICONSTOP);
return FALSE;
}
char buf[2048]; DWORD dwRead = 0;
while ((n = pFile->Read(buf, sizeof(buf))) > 0) {
dwRead += n;
m_prog.SetPos(100 * dwRead / dwLen); // 更新進度條
// 處理訊息佇列保持介面回應
MSG msg;
for (int i = 0; i < 10; i++)
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg); DispatchMessage(&msg);
}
csf.Write(buf, n);
}
pFile->Close();
if (::DeleteFile(str)) { // 刪除舊檔
::rename(str + ".upg", str); // 重新命名新檔
m_strStatus = strFile + "完成更新!";
UpdateData(FALSE);
// ...
}
[VolleyMail]
VERSION=3.1
FILE1=VolleyMail.exe
FILE2=SomeDll.dll
...
採用 HTTP 下載、版本比對、進程檢測、暫存檔下載、原子替換機制,構建安全可靠的自動更新系統。完整細節請參考原始碼。