使用 Http 在線自動升級程序
作者:余延斌
下載源代碼?開發背景
近幾日一些程序老要修改點小毛病,為避免每次都通知程序使用者,便有想做一個在線自動升級的程序。在VCKBase看到一個是使用 FTP 的,想到 FTP 需要用戶名密碼,許多程序如KFW 防火墻都能監看到程序發送的數據包,為防止密碼泄露,故自己選用Http來做更新。我的思路是用命令行傳遞程序名稱、版本號和 Update.ini 配置文件的 URL。命令行用法如下:
update.exe 程序名 版本 版本文件URL 例如: update.exe VolleyMail 3.0 http://www.extice.com/update/update.ini解析命令行參數的函數原型如下:
CUpdateApp::GetCmdLinePara(CStringArray ?Arr);該函數是將命令行參數分解并保存到 paraArr 數據中。然后將命令行信息傳遞給主對話框類,代碼如下:
dlg.m_strSoft = arr.GetAt(0); dlg.m_strVersion = arr.GetAt(1); AfxParseURL( arr.GetAt(2), dwType, dlg.m_strServer, dlg.m_strIniPath, dlg.m_dwPort);這是對話框的初始化,將軟件版本號顯示在 List 框中,如圖一:
m_cis.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT,5); m_pHttp=m_cis.GetHttpConnection( m_strServer,m_dwPort ); m_lbProduct.AddString(m_strSoft+" "+m_strVersion);

圖一
然后是查找可用的更新,先通過 ChttpFile 將 Update.INI 文件下載到系統臨時目錄下,然后調用 GetPrivateProfileString 讀取網上最新的版本號以及要更新的文件,判斷是否需要更新,部分代碼:
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 buf[128]; ::GetPrivateProfileString( m_strSoft, "VERSION", "1.0", buf, sizeof(buf), m_strTempDir+"\\update.ini"); m_strNewVer=buf; if(atof( m_strVersion ) >= atof( buf ) ) //現有版本大于 { m_strStatus = "您現在用的版本已是最新的!"; UpdateData(FALSE); m_buOK.EnableWindow(FALSE); return; }

先通過 CUpdateDlg::FindAppProcessID() 看要更新的程序是否在運行:
DWORD CUpdateDlg::FindAppProcessID() { HANDLE handle=::CreateToolhelp32Snapshot(TH32CS_SNAPALL,0); PROCESSENTRY32 Info; Info.dwSize = sizeof(PROCESSENTRY32); if(::Process32First(handle,&Info)) { do{ CString ss=Info.szExeFile; if(!ss.CompareNoCase(m_strSoft+".exe")) { ::CloseHandle(handle); return Info.th32ProcessID; } } while(::Process32Next(handle,&Info)); ::CloseHandle(handle); } return -1; }該函數返回程序進程號,如果要更新的程序正在運行的話,提示人工退出否則用TerminateProcess 殺掉進程!下載的文件大小用:
pFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH,str);取得。為防止下載一半網絡出現故障,先將下載的文件加后綴名.upg,下載全部成功后替換掉原來在用的程序,完成更新。
關鍵代碼部分如下:
... CStdioFile csf; if( !csf.Open( str+".upg", CFile::modeCreate | CFile::modeWrite | CFile::typeBinary | CFile::shareDenyWrite ) ) {//先為*.upg文件 AfxMessageBox("寫文件"+str +"錯誤!\n文件正在使用中,請先關閉程序!", MB_ICONSTOP); pFile->Close(); 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); ...有關其它細節請參考源代碼。

電子郵件:yybhz@126.com
作者主頁:http://yyb.yeah.net/
posted on 2006-06-20 18:55 楊粼波 閱讀(605) 評論(0) 編輯 收藏 引用 所屬分類: 文章收藏