c++ 下载并解压 .7z 格式的文件并在dialog对话框上显示下载进度条和解压进度条使用mfc 使用多线程
时间: 2024-02-11 14:05:10 浏览: 158
好的,针对你的问题,我给出以下解答:
首先,我们需要使用lib7zip库来解压.7z文件,因此需要将其添加到项目中。将lib7zip中的所有文件添加到您的项目中,并将其包含在您的源文件中。
然后,我们需要使用WinINet库来下载文件。使用WinINet,我们可以轻松地下载文件并跟踪下载进度。我们将使用HttpQueryDataAvailable函数获取下载文件的大小,然后使用InternetReadFile函数读取下载的数据。
接下来,我们需要在对话框上创建两个进度条控件:一个用于下载进度,另一个用于解压进度。我们还需要一个按钮来启动下载和解压过程。
最后,我们将使用多线程来执行下载和解压操作。我们将使用C++11中的std::thread类来创建线程。在下载和解压期间,我们将更新进度条并将状态消息发送回主线程以在对话框上显示。
以下是代码示例:
```c++
#include "stdafx.h"
#include "ZipExtractor.h"
#include <thread>
#include <iostream>
#include <fstream>
#include <wininet.h>
#include "lib7zip/7z.h"
#include "lib7zip/7zAlloc.h"
#include "lib7zip/7zBuf.h"
#include "lib7zip/7zCrc.h"
#include "lib7zip/7zFile.h"
#include "lib7zip/7zVersion.h"
#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "lib7zip.lib")
#define BUFFER_SIZE 10240
// 下载进度回调函数
static DWORD CALLBACK DownloadProgressCallback(
IN HINTERNET hInternet,
IN DWORD_PTR dwContext,
IN DWORD dwInternetStatus,
IN LPVOID lpvStatusInformation,
IN DWORD dwStatusInformationLength
)
{
if (dwInternetStatus == INTERNET_STATUS_RESPONSE_RECEIVED) {
DWORD nBytesAvailable = 0;
if (InternetQueryDataAvailable(hInternet, &nBytesAvailable, 0, 0)) {
// 更新下载进度条
CProgressCtrl* pDownloadProgressBar = (CProgressCtrl*)dwContext;
pDownloadProgressBar->SetRange32(0, nBytesAvailable);
pDownloadProgressBar->SetPos(0);
}
}
else if (dwInternetStatus == INTERNET_STATUS_REQUEST_COMPLETE) {
DWORD nBytesRead = 0;
LPBYTE pBuffer = (LPBYTE)lpvStatusInformation;
DWORD nBytesAvailable = *(LPDWORD)dwStatusInformationLength;
if (InternetReadFile(hInternet, pBuffer, nBytesAvailable, &nBytesRead)) {
// 更新下载进度条
CProgressCtrl* pDownloadProgressBar = (CProgressCtrl*)dwContext;
pDownloadProgressBar->SetPos(pDownloadProgressBar->GetPos() + nBytesRead);
}
}
return 0;
}
// 解压进度回调函数
static SRes ExtractCallback(
const void* pInData, // 输入数据
size_t nInSize, // 输入数据大小
void* pOutData, // 输出数据
size_t nOutSize, // 输出数据大小
void* pUserData // 用户数据(进度条控件指针)
)
{
// 更新解压进度条
CProgressCtrl* pExtractProgressBar = (CProgressCtrl*)pUserData;
pExtractProgressBar->SetPos(pExtractProgressBar->GetPos() + nInSize);
return SZ_OK;
}
// 下载并解压线程函数
void DownloadAndExtractThread(LPCTSTR lpszUrl, LPCTSTR lpszOutputPath, CProgressCtrl* pDownloadProgressBar, CProgressCtrl* pExtractProgressBar)
{
// 创建Internet连接
HINTERNET hInternet = InternetOpen(_T("7zDownloader"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInternet == NULL) {
AfxMessageBox(_T("Failed to create Internet connection"));
return;
}
// 打开URL
HINTERNET hUrl = InternetOpenUrl(hInternet, lpszUrl, NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (hUrl == NULL) {
AfxMessageBox(_T("Failed to open URL"));
InternetCloseHandle(hInternet);
return;
}
// 获取文件大小
DWORD nFileSize = 0;
DWORD nSizeLen = sizeof(DWORD);
if (!HttpQueryInfo(hUrl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &nFileSize, &nSizeLen, NULL)) {
AfxMessageBox(_T("Failed to get file size"));
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
return;
}
// 创建文件
HANDLE hFile = CreateFile(lpszOutputPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
AfxMessageBox(_T("Failed to create file"));
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
return;
}
// 更新下载进度条
pDownloadProgressBar->SetRange32(0, nFileSize);
pDownloadProgressBar->SetPos(0);
// 开始下载
char szBuffer[BUFFER_SIZE];
DWORD dwBytesRead = 0;
while (InternetReadFile(hUrl, szBuffer, BUFFER_SIZE, &dwBytesRead) && dwBytesRead > 0) {
DWORD dwBytesWritten = 0;
if (!WriteFile(hFile, szBuffer, dwBytesRead, &dwBytesWritten, NULL)) {
AfxMessageBox(_T("Failed to write file"));
CloseHandle(hFile);
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
return;
}
// 更新下载进度条
pDownloadProgressBar->SetPos(pDownloadProgressBar->GetPos() + dwBytesRead);
}
// 关闭文件和URL句柄
CloseHandle(hFile);
InternetCloseHandle(hUrl);
InternetCloseHandle(hInternet);
// 开始解压
CFile file;
if (!file.Open(lpszOutputPath, CFile::modeRead)) {
AfxMessageBox(_T("Failed to open file"));
return;
}
CArchive ar(&file, CArchive::load);
CMemoryFile memfile;
memfile.SetSize(ar.GetFile()->GetLength());
ar.Read(memfile.GetBuffer(), memfile.GetLength());
ar.Close();
file.Close();
// 打开7z文件
CLookToRead lookStream;
lookStream.buf = (Byte*)memfile.GetBuffer();
lookStream.size = memfile.GetLength();
lookStream.pos = 0;
LookToRead_CreateVTable(&lookStream, False);
CrcGenerateTable();
CSzArEx db;
SzArEx_Init(&db);
ISzAlloc allocImp;
allocImp.Alloc = SzAlloc;
allocImp.Free = SzFree;
CrcGenerateTable();
ISzAlloc allocTempImp;
allocTempImp.Alloc = SzAllocTemp;
allocTempImp.Free = SzFreeTemp;
CArchiveDatabase archiveDatabase;
SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
// 解压文件
for (UInt32 i = 0; i < db.NumFiles; i++) {
UInt32 blockIndex = 0xFFFFFFFF;
SRes res = SzArEx_Extract(&db, &lookStream.s, i, &blockIndex, ExtractCallback, pExtractProgressBar);
if (res != SZ_OK) {
AfxMessageBox(_T("Failed to extract file"));
break;
}
}
// 关闭7z文件
SzArEx_Free(&db, &allocImp);
memfile.Close();
// 更新解压进度条
pExtractProgressBar->SetPos(pExtractProgressBar->GetRange().right);
// 显示完成消息
AfxMessageBox(_T("Download and extract complete"));
}
// CZipExtractorDlg 对话框
class CZipExtractorDlg : public CDialogEx
{
// ...
public:
// ...
private:
// ...
afx_msg void OnBnClickedButtonDownload();
// ...
};
void CZipExtractorDlg::OnBnClickedButtonDownload()
{
// 获取下载URL和输出路径
CString strUrl, strOutputPath;
GetDlgItemText(IDC_EDIT_URL, strUrl);
GetDlgItemText(IDC_EDIT_OUTPUT_PATH, strOutputPath);
// 创建并启动线程
std::thread downloadThread(DownloadAndExtractThread, strUrl.GetBuffer(), strOutputPath.GetBuffer(), &m_wndDownloadProgressBar, &m_wndExtractProgressBar);
downloadThread.detach();
}
// ...
```
以上代码仅为示例,具体实现可能需要根据实际情况进行调整。
阅读全文