1、MFC自動更新問題的解決方案:大多數關於自動更新的問題,首先是在url地址上放一個壓縮包,本程序默認zip壓縮,把壓縮包從zip壓縮包下載到本地,然後解壓壓縮包把解壓後的文件拷貝到制定的目錄,注意千萬不要再壓縮包裏放更新的exe,因爲壓縮的exe不能更新本身。
2、核心代碼:
//此部分爲button部分實現代碼,獲取button上的文字,如果是Start Update,表示開始更新,啓動線程;
//如果是Complete,表示更新完成,刪除壓縮文件和解壓後的文件夾;
void CUpdateDlg::OnBnClickedMfcbuttonUp()
{
// TODO: Add your control notification handler code here
CString str;
if (GetDlgItemText(IDC_MFCBUTTON_UP, str))
{
if (str == "Start Update")
{
m_pThreadUpdate = AfxBeginThread(ThreadUpdate, &m_progressctrl, THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED);
//m_progressctrl爲進度條控件的變量
if (m_pThreadUpdate == NULL)
{
AfxMessageBox("Thread is fail!");
return;
}
m_pThreadUpdate->m_bAutoDelete = TRUE;//由系統處理線程
m_pThreadUpdate->ResumeThread();
SetTimer(1, 200, NULL);
}
else if (str == "Complete")
{
myDeleteDirectory("seer");
DeleteFile("seer.zip");
CDialog::EndDialog(0);
}
}
}
//定時器主要用於判斷是否從網上下載完文件,如果完成把button的文字變爲complete;
void CUpdateDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch (nIDEvent)
{
case 1:
if (bUpdate == TRUE)
{
SetDlgItemText(IDC_MFCBUTTON_UP, "Complete");
KillTimer(1);
}
break;
default:
break;
}
CDialogEx::OnTimer(nIDEvent);
}//此部分爲線程函數,主要調用下載文字函數
UINT CUpdateDlg::ThreadUpdate(LPVOID pParam)
{
CUpdateDlg *pDlg = new CUpdateDlg
CString url = "http://seer.xzxyun.com/entpublic/TDownLoadClientFile";
if (pDlg->DownloadIniFile(url, (CProgressCtrl *)pParam) != TRUE)
AfxMessageBox("fail");
return 0;
}//此部分爲項目核心,主要實現了從url上下載文件,顯示進度條進度,解壓文件,拷貝等功能;
BOOL CUpdateDlg::DownloadIniFile(CString &strUrl, CProgressCtrl * m_ctrl)
{
CString strFileName_ini, strHttp;
CString stroldname;
//CString sourcefile = "C:\\Users\\Administrator\\Desktop\\Update\\Update\\me";
char pBuf[MAX_PATH];
GetCurrentDirectory(MAX_PATH, pBuf);//獲取當前路徑
sourcefile = pBuf;//源目錄
strcat_s(pBuf, "\\seer");
stroldname = pBuf;//文件解壓後保存目錄
strcat_s(pBuf, ".zip");
strFileName_ini = pBuf;//壓縮文件的名稱
strHttp = strUrl;
CFile DownloadFile;
int nReceSize = 0;//每次下載文件的大小
DWORD dwStartTime, dwEndTime;//定義每次下載的起始時間,用於判斷網絡狀態
CHttpSocket HttpSocket;//定義網絡套接字http協議
char pData[1024];
CString strServer, strObject;
unsigned short nPort;//端口號
DWORD dwServiceType;//套接口類型
long nLength;
const char *pRequestHeader = NULL;//http請求的協議頭
AfxParseURL(strHttp, dwServiceType, strServer, strObject, nPort);//解析url,把url地址解析成相應的字段
pRequestHeader = HttpSocket.FormatRequestHeader((LPTSTR)(LPCTSTR)strServer,
(LPTSTR)(LPCTSTR)strObject, nLength);
HttpSocket.Socket();//創建socket
HttpSocket.Connect((LPTSTR)(LPCTSTR)strServer);//連接
HttpSocket.SendRequest();//發送請求
HttpSocket.SetTimeout(10000, 0);//延時
char szValue[30];
HttpSocket.GetField("Content-Length", szValue, 30);//獲取Content-Length字段的值,表示請求文件的大小
nFileSize = atoi(szValue);//整個壓縮文件的大小
DownloadFile.Open(strFileName_ini, CFile::modeCreate | CFile::modeWrite);//創建strFileName_ini文件並允許寫操作
int steps = nFileSize / (100*1024);
m_ctrl->SetRange(0, steps);//設置進度條的範圍
int curpos = 0;
while (nCompletedSize < nFileSize && bExitFlag == TRUE )
{
dwStartTime = GetTickCount();
//GetTickCount返回(retrieve)從操作系統啓動所經過(elapsed)的毫秒數,它的返回值是DWORD。
nReceSize = HttpSocket.Receive(pData, 1024);//接受數據
if (nReceSize == 0)
{
AfxMessageBox("service is closed");
break;
}
if (nReceSize == -1)
{
AfxMessageBox("receive timeout during data wrap!");
break;
}
dwEndTime = GetTickCount();
DownloadFile.Write(pData, nReceSize);//從buff把數據寫入文件中
nCompletedSize += nReceSize;//nCompletedSize爲已經下載的字節數
curpos = nCompletedSize / (100 * 1024);
m_ctrl->SetPos(curpos);//設置當前進度條的位置
Sleep(2);
}
m_ctrl->SetStep(curpos);
DownloadFile.Close();
if (m_zipImplement.Zip_UnPackFiles(strFileName_ini, stroldname))//解壓
{
//MessageBox(_T("解壓完成"), _T("提醒"), MB_OK);
}
else
MessageBox(_T("Unzipping date is fail"), _T("Remind"), MB_OK);
CopyDirectory(stroldname, sourcefile, FALSE);//拷貝
bUpdate = TRUE;
if (_access(strFileName_ini, 0) != -1)
return TRUE;
return FALSE;
}BOOL CopyDirectory(CString strSrcPath, CString strDesPath, BOOL bFailIfExists)
{
if (strSrcPath.IsEmpty())
{
OutputDebugString("source file is null,can't copy!");
//OutputDebugString函數,通過它,可以在在DEBUG或RELEASE情況也可以輸出調試日誌,
//從而對那些要求編譯爲RELEASE的程序可以方便的調試。
return FALSE;
}
if (strSrcPath.GetAt(strSrcPath.GetLength() - 1) != '\\')//GetAt取strSrcPath倒數第2個字符
strSrcPath += '\\';
if (strDesPath.GetAt(strDesPath.GetLength() - 1) != '\\')
strDesPath += '\\';
BOOL bRet = FALSE; // 因爲源目錄不可能爲空,所以該值一定會被修改
CFileFind ff;
BOOL bFound = ff.FindFile(strSrcPath + "*", 0);//查找當前目錄的所有文件
while (bFound) // 遞歸拷貝
{
bFound = ff.FindNextFile();
if (ff.GetFileName() == "." || ff.GetFileName() == "..")
continue;
CString strSubSrcPath = ff.GetFilePath();
CString strSubDespath = strSubSrcPath;
strSubDespath.Replace(strSrcPath, strDesPath);
if (ff.IsDirectory())
bRet = CopyDirectory(strSubSrcPath, strSubDespath, bFailIfExists); // 如果是目錄,遞歸拷貝文件夾
else
bRet = CopyFile(strSubSrcPath, strSubDespath, bFailIfExists); // 如果是文件,直接拷貝,bFailIfExists設爲false,把原來的文件直接覆蓋
if (!bRet)
break;
}
ff.Close();
return bRet;
}void myDeleteDirectory(CString directory_path)
{
CFileFind finder;
CString path;
path.Format(_T("%s/*.*"), directory_path);
BOOL bWorking = finder.FindFile(path);
while (bWorking)
{
bWorking = finder.FindNextFile();
if (finder.IsDirectory() && !finder.IsDots())//處理文件夾
{
myDeleteDirectory(finder.GetFilePath()); //遞歸刪除文件夾
RemoveDirectory(finder.GetFilePath());
}
else//處理文件
{
DeleteFile(finder.GetFilePath());
}
}
RemoveDirectory(directory_path);
}
3、關於解壓zip文件,我是直接用別人的代碼,代碼如下: