MFC 關於自動更新問題的解決方案和代碼

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文件,我是直接用別人的代碼,代碼如下:





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章