作者:
余延斌
下載源代碼
?開(kāi)發(fā)背景
近幾日一些程序老要修改點(diǎn)小毛病,為避免每次都通知程序使用者,便有想做一個(gè)在線自動(dòng)升級(jí)的程序。在VCKBase看到一個(gè)是使用 FTP 的,想到 FTP 需要用戶名密碼,許多程序如KFW 防火墻都能監(jiān)看到程序發(fā)送的數(shù)據(jù)包,為防止密碼泄露,故自己選用Http來(lái)做更新。我的思路是用命令行傳遞程序名稱、版本號(hào)和 Update.ini 配置文件的 URL。命令行用法如下:
update.exe 程序名 版本 版本文件URL
例如:
update.exe VolleyMail 3.0 http://www.extice.com/update/update.ini
解析命令行參數(shù)的函數(shù)原型如下:
CUpdateApp::GetCmdLinePara(CStringArray ?Arr);
該函數(shù)是將命令行參數(shù)分解并保存到 paraArr 數(shù)據(jù)中。然后將命令行信息傳遞給主對(duì)話框類(lèi),代碼如下:
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);
這是對(duì)話框的初始化,將軟件版本號(hào)顯示在 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);

圖一
然后是查找可用的更新,先通過(guò) ChttpFile 將 Update.INI 文件下載到系統(tǒng)臨時(shí)目錄下,然后調(diào)用 GetPrivateProfileString 讀取網(wǎng)上最新的版本號(hào)以及要更新的文件,判斷是否需要更新,部分代碼:
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 ) ) //現(xiàn)有版本大于
{
m_strStatus = "您現(xiàn)在用的版本已是最新的!";
UpdateData(FALSE);
m_buOK.EnableWindow(FALSE);
return;
}

更新部分代碼
先通過(guò) CUpdateDlg::FindAppProcessID() 看要更新的程序是否在運(yùn)行:
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;
}
該函數(shù)返回程序進(jìn)程號(hào),如果要更新的程序正在運(yùn)行的話,提示人工退出否則用TerminateProcess 殺掉進(jìn)程!下載的文件大小用:
pFile->QueryInfo(HTTP_QUERY_CONTENT_LENGTH,str);
取得。為防止下載一半網(wǎng)絡(luò)出現(xiàn)故障,先將下載的文件加后綴名.upg,下載全部成功后替換掉原來(lái)在用的程序,完成更新。
關(guān)鍵代碼部分如下:
...
CStdioFile csf;
if( !csf.Open( str+".upg",
CFile::modeCreate
| CFile::modeWrite
| CFile::typeBinary
| CFile::shareDenyWrite ) )
{//先為*.upg文件
AfxMessageBox("寫(xiě)文件"+str +"錯(cuò)誤!\n文件正在使用中,請(qǐng)先關(guā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);
...
有關(guān)其它細(xì)節(jié)請(qǐng)參考源代碼。

作者信息
電子郵件:yybhz@126.com
作者主頁(yè):http://yyb.yeah.net/