程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 使用Http在線自動升級程序

使用Http在線自動升級程序

編輯:關於VC++

開發背景

近幾日一些程序老要修改點小毛病,為避免每次都通知程序使用者,便有想做一個在線自動升級的程序。在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);
    ... 
有關其它細節請參考源代碼。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved