qt使用wimlib-imagex,做windows系统备份还原

wimlib-imagex是个第三方工具,可对系统映像进行操作,下载地址:
https://wimlib.net/downloads/index.html
在这里插入图片描述
程序主要用到以下这两个文件:libwim-15.dll和wimlib-imagex.exe
在这里插入图片描述
wimlib-imagex.exe的调用命令参数,可以通过cmd命令行wimlib-imagex --help进行查看,也可以自行百度。




系统备份:通过wimlib-imagex的capture命令,对指定系统盘进行捕获映像,生成wim文件。
系统还原:进入winPE系统,对指定系统盘进行格式化,再通过wimlib-imagex的apply命令,将之前备份的完整的wim文件应用到系统盘。


以下为涉及的部分参考代码:

SystemReloadObject.cpp


//系统备份
bool CSystemReloadObject::systemBackup(const QString& backupName, const QString& backupDesc)
{
    QString sourcePath = getSystemDrive();

    m_pThread->systemBackup(sourcePath, backupName, backupDesc);
    return true;
}

//系统还原
bool CSystemReloadObject::systemRestore(const QString& backupName, const int& index)
{
    m_pThread->systemRestore(backupName, index);
    return true;
}


//本地模式下载安装
bool CSystemReloadObject::systemPEDownload()
{
    m_pThread->systemPEDownload();
    return true;
}


//获取当前系统盘盘符
QString CSystemReloadObject::getSystemDrive()
{
    char str[MAX_PATH]{0};
    GetSystemDirectoryA(str, MAX_PATH);
    return QString::fromStdString(std::string(1, str[0]));
}


//获取当前系统版本
QString CSystemReloadObject::getSystemVersion()
{
    QString vname;
    //先判断是否为win8.1或win10
    typedef void(__stdcall* NTPROC)(DWORD*, DWORD*, DWORD*);
    HINSTANCE hinst = LoadLibrary(L"ntdll.dll");
    DWORD dwMajor, dwMinor, dwBuildNumber;
    NTPROC proc = (NTPROC)GetProcAddress(hinst, "RtlGetNtVersionNumbers");
    proc(&dwMajor, &dwMinor, &dwBuildNumber);
    if (dwMajor == 6 && dwMinor == 3)	//win 8.1
    {
        vname = "Microsoft Windows 8.1";
        return vname;
    }
    if (dwMajor == 10 && dwMinor == 0)	//win 10
    {
        vname = "Microsoft Windows 10";
        return vname;
    }

    //判断win8.1以下的版本
    SYSTEM_INFO info;                //用SYSTEM_INFO结构判断64位AMD处理器
    GetSystemInfo(&info);            //调用GetSystemInfo函数填充结构
    OSVERSIONINFOEX os;
    os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
#pragma warning(disable:4996)
    int SystemVer = 0;
    if (GetVersionEx((OSVERSIONINFO*)&os))
    {

        //下面根据版本信息判断操作系统名称
        switch (os.dwMajorVersion)
        {                        //判断主版本号
        case 4:
            switch (os.dwMinorVersion)
            {                //判断次版本号
            case 0:
                if (os.dwPlatformId == VER_PLATFORM_WIN32_NT) {
                    vname = "Microsoft Windows NT 4.0";  //1996年7月发布
                    SystemVer = 40; // Windows NT 4.0
                }
                else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
                    vname = "Microsoft Windows 95";
                    SystemVer = 95;
                }

                break;
            case 10:
                vname = "Microsoft Windows 98";
                SystemVer = 41; // Windows 98
                break;
            case 90:
                vname = "Microsoft Windows Me";
                SystemVer = 42; // Windows Me
                break;
            }
            break;
        case 5:
            switch (os.dwMinorVersion)
            {               //再比较dwMinorVersion的值
            case 0:
                vname = "Microsoft Windows 2000";    //1999年12月发布
                SystemVer = 50; // Windows 2000
                break;
            case 1:
                vname = "Microsoft Windows XP";      //2001年8月发布
                SystemVer = 51; // Windows XP
                break;
            case 2:
                if (os.wProductType == VER_NT_WORKSTATION &&
                    info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
                {
                    vname = "Microsoft Windows XP Professional x64 Edition";
                    SystemVer = 52;
                }
                else if (GetSystemMetrics(SM_SERVERR2) == 0)
                {
                    vname = "Microsoft Windows Server 2003";   //2003年3月发布
                    SystemVer = 53;
                }
                else if (GetSystemMetrics(SM_SERVERR2) != 0)
                {
                    vname = "Microsoft Windows Server 2003 R2";
                    SystemVer = 54;
                }

                break;
            }
            break;
        case 6:
            switch (os.dwMinorVersion)
            {
            case 0:
                if (os.wProductType == VER_NT_WORKSTATION)
                {
                    vname = "Microsoft Windows Vista";
                    SystemVer = 60; // Windows Vista
                }
                else {
                    vname = "Microsoft Windows Server 2008";   //服务器版本
                    SystemVer = 61; // Windows Server 2008
                }

                break;
            case 1:
                if (os.wProductType == VER_NT_WORKSTATION)
                {
                    vname = "Microsoft Windows 7";
                    SystemVer = 70; // Windows 7

                }
                else
                {
                    vname = "Microsoft Windows Server 2008 R2";
                    SystemVer = 71; // Windows Server 2008 R2
                }

                break;
            case 2:
                if (os.wProductType == VER_NT_WORKSTATION)
                {
                    vname = "Microsoft Windows 8";
                    SystemVer = 80; // Windows 8
                }

                else {
                    vname = "Microsoft Windows Server 2012";
                    SystemVer = 81; // Windows Server 2012
                }

                break;
            }
            break;
        default:
            vname = "未知操作系统";
            SystemVer = 0;
        }
    }
    else {
        printf_s("版本获取失败\n");
    }
    return vname;
}


//获取当前存在的备份
void CSystemReloadObject::getSystemBackup()
{
    QString backupPath = QDir::currentPath() + "/SystemBackup/";
    QDir dir(backupPath);
    QFileInfoList infolist = dir.entryInfoList();

    QJsonArray backupArray;
    foreach(auto it, infolist){
        if(it.suffix() == "wim" || it.suffix() == "WIM"){
            QJsonObject backupObj;
            backupObj.insert("name", it.absoluteFilePath());
            backupArray.append(backupObj);
        }
    }

    emit sigBackupInfo(backupArray);
}


//获取当前存在的有效备份的卷
void CSystemReloadObject::getSystemBackupImage(const QString& backupPath)
{
    //使用wimlib-imagex的info命令检验
    QString cmd = QString("\"%1/SystemReload/wimlib-imagex.exe\" info \"%2\"")
                      .arg(QDir::currentPath())
                      .arg(backupPath);

    QProcess process;
    process.start(cmd);
    process.waitForFinished();
    QByteArray all = process.readAll();
    QString strall = QString(all);
    int indexs = 0;

    if (!strall.contains("Available Images:")) {
        qDebug() << "此wim无效,无法进行还原";
    }else{
        qDebug() << "有可用的Images";

        int pos = strall.indexOf("Available Images:");
        strall = strall.mid(pos);
        indexs = strall.count("Index:");
    }

    //添加数据到model
    QJsonArray imageArray;
    for(int i=0; i<indexs; i++){
        QJsonObject imageObj;
        imageObj.insert("name", QString::number(i+1));
        imageArray.append(imageObj);
    }

    emit sigImageInfo(imageArray);
}


//检测当前系统是否是winPE环境
bool CSystemReloadObject::isCurrentWinPE()
{
    HKEY hkey = NULL;
    unsigned char buffer[260] = { 0 };
    unsigned long dwsize = sizeof(buffer);
    std::string strfind;

    unsigned long iret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control", 0, KEY_READ, &hkey);
    if (iret != ERROR_SUCCESS)
        return false;

    iret = RegQueryValueExA(hkey, "SystemStartOptions", NULL, NULL, buffer, &dwsize);
    if (iret != ERROR_SUCCESS)
    {
        RegCloseKey(hkey);
        return false;
    }

    RegCloseKey(hkey);// get registry keys.

    // next find '/MININT' flag.
    strfind.assign((char*)buffer);
    std::transform(strfind.begin(), strfind.end(), strfind.begin(), tolower);// to lowercase.
    if ((int)strfind.find("minint", 0) > -1){
        //是winPE
        emit sigDialogOperte(1);
        return true;
    }

    //不是winPE
    emit sigDialogOperte(2);
    return false;
}


//检查当前是否存在winPE
bool CSystemReloadObject::hasLocalWinPE()
{
    //判断系统BCD引导文件是否有winPE的引导菜单
    QString cmd = QString("bcdedit /enum");

    QStringList args;
    args << "/C" << cmd;

    QString program = "cmd.exe";

    QProcess process;
    process.start(program, args);
    process.waitForFinished();

    QByteArray all = process.readAll();
    QString strall = QString(all);
    if (strall.contains(LOCAL_WINPE_DEVICE_GUID) || strall.contains(LOCAL_WINPE_OSLOADER_GUID)) {
        qDebug() << "当前存在winpe本地模式";
        emit sigDialogOperte(3);
        return true;
    }

    emit sigDialogOperte(4);
    return false;
}




//打开备份文件位置
void CSystemReloadObject::openBackupFilePath()
{
    QString strPath = QDir::currentPath() + "/SystemBackup";
    strPath.replace("/", "\\");
    QProcess process;
    process.startDetached("explorer", QStringList() << QString("/select,") << QString("%1").arg(strPath));
}


//关闭线程启用的外部程序
void CSystemReloadObject::exitApp()
{
    m_pThread->killProcess();
}


//重启电脑
void CSystemReloadObject::restartComputer()
{
    QString cmd = "shutdown /r /t 0";

    QStringList args;
    args << "/C" << cmd;

    QString program = "cmd.exe";
    QProcess process;
    process.start(program, args);
    process.waitForFinished();
}


SystemReloadThread.cpp
void CSystemReloadThread::systemBackup(const QString& sourcePath, const QString& backupName, const QString& backupDesc)
{
    m_threadParams.clear();
    m_threadParams.append(sourcePath);
    m_threadParams.append(backupName);
    m_threadParams.append(backupDesc);

    m_memberFun = &CSystemReloadThread::systemBackup;
    this->start();
}

bool CSystemReloadThread::systemBackup(QVariantList params)
{
    //创建备份文件夹
    QDir tempDir(m_BackupFilePath);
    if (!tempDir.exists()) {
        if (!tempDir.mkpath(m_BackupFilePath)) {
            qDebug() << "failed to create backupDir";
            sigDialogResultThread(1,0);
            emit sigUpdateBtn(true);
            return false;
        }
    }

    QString filepath = m_BackupFilePath + params[1].toString() + ".wim";
    QFile wimFile(filepath);

    //不存在就采用捕获capture,存在就采用追加append
    if (!wimFile.exists()) {
        WimCapture(params[0].toString() + ":\\", m_BackupFilePath, params[1].toString(), params[2].toString()+"_"+getSystemDrive());
    }
    else {
        WimAppend(params[0].toString() + ":\\", m_BackupFilePath, params[1].toString(), params[2].toString()+"_"+getSystemDrive());
    }


    //判断进程结束后,是否已成功完成备份
    if ((m_DoingOutput.contains("Calculating integrity table for WIM") && m_DoingOutput.contains("(100%) done"))
        || (m_DoingOutput.contains("Archiving file data:") && m_DoingOutput.contains("(100%) done"))) {
        qDebug() << "备份成功完成";
        emit sigDialogResultThread(1,1);
        emit sigUpdateBtn(true);
        return true;
    }else if(m_DoingOutput.contains("ERROR: Exiting with error code")){
        qDebug()<< "系统备份失败";
        emit sigDialogResultThread(1,0);
        emit sigUpdateBtn(true);
        return false;
    }


    return false;
}


void CSystemReloadThread::systemRestore(const QString& backupName, const int& index)
{
    m_threadParams.clear();
    m_threadParams.append(backupName);
    m_threadParams.append(index);

    m_memberFun = &CSystemReloadThread::systemRestore;
    this->start();
}

bool CSystemReloadThread::systemRestore(QVariantList params)
{

    //winPE的系统盘可能和windows10下不同,因此此处需要从备份文件的描述中获取系统盘
    //使用wimlib-imagex的info命令检验
    QString cmd = QString("\"%1/SystemReload/wimlib-imagex.exe\" info \"%2\"")
          .arg(QDir::currentPath())
          .arg(params[0].toString());

    QProcess process;
    process.start(cmd);
    process.waitForFinished();
    QByteArray all = process.readAll();
    QString strall = QString(all);
    QString systemDrive;


    if (!strall.contains("Available Images:")) {
        qDebug() << "此wim无效,无法进行还原";
    }
    else {
        qDebug() << "有可用的Images";

        int pos = strall.indexOf("Description:");
        strall = strall.mid(pos);
        pos = strall.indexOf("\r\n");
        systemDrive = strall.mid(pos - 1, 1);
    }


    //在winPE环境中,先格式化系统盘
    if(FormatVolume(systemDrive, "NTFS")){
        qDebug()<< "格式化成功";
    }else{
        qDebug()<< "格式化失败";
        emit sigDialogResultThread(2,0);
        emit sigUpdateBtn(true);
        return false;
    }

    //将wim文件应用到系统盘
    WimApply(params[0].toString(), params[1].toInt(), systemDrive+":\\");
    if (m_DoingOutput.contains("Done applying WIM image") || (m_DoingOutput.contains("Applying metadata to files") && m_DoingOutput.contains("(100%) done"))) {
        qDebug() << "还原成功完成";
        emit sigDialogResultThread(2,1);
        emit sigUpdateBtn(true);
        return true;
    }else if(m_DoingOutput.contains("ERROR: Exiting with error code")){
        qDebug()<< "系统还原失败";
        emit sigDialogResultThread(2,0);
        emit sigUpdateBtn(true);
        return false;
    }

    return false;
}


void CSystemReloadThread::systemPEDownload()
{
    m_threadParams.clear();
    m_memberFun = &CSystemReloadThread::systemPEDownload;
    this->start();
}


bool CSystemReloadThread::systemPEDownload(QVariantList params)
{
    emit sigDialogResultThread(3,0);
    //创建下载文件夹
    QDir tempDir(m_DownloadFilePath);
    if (!tempDir.exists()) {
        if (!tempDir.mkpath(m_DownloadFilePath)) {
            qDebug() << "failed to create downDir";
            return false;
        }
    }


    //下载文件
    m_DownloadFlag = true;
    downloadFile(m_DownloadMd5, m_DownloadUrl, m_DownloadFilePath, "");
    if (!m_DownloadFlag) {
        qDebug() << "download error";
        emit sigDialogResultThread(3,1);
        return false;
    }


    //解压文件
    std::string strDownloadInfo = m_DownloadFilePath.toStdString() + "winPE_X64_local.zip";
    std::string strTempDirPath = m_DownloadFilePath.toStdString();

    unZip(strDownloadInfo.c_str(), strTempDirPath.c_str());
    DeleteFileA(strDownloadInfo.c_str());



    //本地模式,使用bcdedit.exe 编辑BCD引导文件,进行winPE的菜单添加
    QString systemDrive = getSystemDrive();
    QString cmd = QString("bcdedit /create {%1} /d %2 /device && "
                          "bcdedit /create  {%3} /d %4 /application osloader && "
                          "bcdedit /set {%5} ramdisksdidevice partition=%6: && "
                          "bcdedit /set {%7} ramdisksdipath %8 && "
                          "bcdedit /set {%9} device ramdisk=[%10:]%11,{%12} && "
                          "bcdedit /set {%13} description %14 && "
                          "bcdedit /set {%15} locale zh-CN && "
                          "bcdedit /set {%16} inherit {bootloadersettings} && "
                          "bcdedit /set {%17} osdevice ramdisk=[%18:]%19,{%20} && "
                          "bcdedit /set {%21} systemroot \\windows && "
                          "bcdedit /set {%22} detecthal Yes && "
                          "bcdedit /set {%23} winpe Yes && "
                          "bcdedit /set {%24} ems no && "
                          "bcdedit /displayorder {%25} /addlast && "
                          "bcdedit /timeout %26 && "
                          "bcdedit /default {%27}")
                      .arg(LOCAL_WINPE_DEVICE_GUID).arg(LOCAL_WINPE_DISPNAME)
                      .arg(LOCAL_WINPE_OSLOADER_GUID).arg(LOCAL_WINPE_DISPNAME)
                      .arg(LOCAL_WINPE_DEVICE_GUID).arg(systemDrive)
                      .arg(LOCAL_WINPE_DEVICE_GUID).arg(LOCAL_WINPE_BOOT_SDI)
                      .arg(LOCAL_WINPE_OSLOADER_GUID).arg(systemDrive).arg(LOCAL_WINPE_BOOT_WIM).arg(LOCAL_WINPE_DEVICE_GUID)
                      .arg(LOCAL_WINPE_OSLOADER_GUID).arg(LOCAL_WINPE_DISPNAME)
                      .arg(LOCAL_WINPE_OSLOADER_GUID)
                      .arg(LOCAL_WINPE_OSLOADER_GUID)
                      .arg(LOCAL_WINPE_OSLOADER_GUID).arg(systemDrive).arg(LOCAL_WINPE_BOOT_WIM).arg(LOCAL_WINPE_DEVICE_GUID)
                      .arg(LOCAL_WINPE_OSLOADER_GUID)
                      .arg(LOCAL_WINPE_OSLOADER_GUID)
                      .arg(LOCAL_WINPE_OSLOADER_GUID)
                      .arg(LOCAL_WINPE_OSLOADER_GUID)
                      .arg(LOCAL_WINPE_OSLOADER_GUID)
                      .arg(10)
                      .arg(LOCAL_WINPE_OSLOADER_GUID);



    QStringList args;
    args << "/C" << cmd;

    QString program = "cmd.exe";
    QProcess process;
    process.start(program, args);
    process.waitForFinished();


    //移动到系统盘指定文件夹
    QString i4path = systemDrive + ":/i4";
    QDir i4Dir(i4path);
    if (!i4Dir.exists()) {
        if (!i4Dir.mkpath(i4path))
            qDebug() << "failed to create dir";
    }

    QString i4sourcepath = QDir::currentPath() + "/SystemBackup/temp/winPE_X64_local";
    CopyDir(i4sourcepath, i4path);


    //删除文件夹
    QDir(i4sourcepath).removeRecursively();

    emit sigDialogResultThread(3,2);
    return false;
}



//将某个盘捕获到指定目录,生成wim文件
//WimCapture("c:\\", "e:\\", "c_bak", "c盘备份");
void CSystemReloadThread::WimCapture(const QString& sourcePath, const QString& targetPath, const QString& backupName, const QString& backupDescription)
{
    //wimlib-imagex capture C:\ D:\C_Bak.wim C_bak C盘备份 --check --snapshot
    QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" capture %2 \"%3\" \"%4\" \"%5\" --compress=XPRESS --threads=4 --snapshot")
    //QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" capture %2 \"%3\" \"%4\" \"%5\" --check --snapshot")
                              .arg(QDir::currentPath())
                              .arg(sourcePath)
                              .arg(targetPath + backupName +".wim")
                              .arg(backupName)
                              .arg(backupDescription);

    runCMD(commandLine.toStdString());
}



//追加到某个wim文件
//WimAppend("c:\\", "e:\\", "c_bak", "c盘备份");
void CSystemReloadThread::WimAppend(const QString& sourcePath, const QString& targetPath, const QString& backupName, const QString& backupDescription)
{
    //wimlib-imagex append c:\ d:\c_bak.wim c_bak_2 c盘备份
    //追加的话,参数%4(备份名字(不是备份文件))不能和之前相同
    QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" append %2 \"%3\" \"%4\" \"%5\" --compress=XPRESS --threads=4 --snapshot")
    //QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" append %2 \"%3\" \"%4\" \"%5\" --check --snapshot")
                              .arg(QDir::currentPath())
                              .arg(sourcePath)
                              .arg(targetPath + backupName + ".wim")
                              .arg(backupName +"_"+ QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
                              .arg(backupDescription);

    runCMD(commandLine.toStdString());
}


//将wim文件应用到某个盘
//WimApply("e:\\c_bak.wim", 1, "c:\\");
void CSystemReloadThread::WimApply(const QString& backupPath, const int& index, const QString& targetPath)
{
    //wimlib-imagex apply d:\c_bak.wim 1 c:\

    QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" apply \"%2\" %3 %4")
                              .arg(QDir::currentPath())
                              .arg(backupPath)
                              .arg(index)
                              .arg(targetPath);

    runCMD(commandLine.toStdString());
}


//检查wim文件信息
//WimInfo("e:\\c_bak.wim");
void CSystemReloadThread::WimInfo(const QString& backupPath)
{
    //wimlib-imagex info d:\c_bak.wim
    QString commandLine = QString("\"%1/SystemReload/wimlib-imagex.exe\" info \"%2\"")
                              .arg(QDir::currentPath())
                              .arg(backupPath);

    runCommandLine(commandLine);
}

//获取当前系统盘盘符
QString CSystemReloadThread::getSystemDrive()
{
    char str[MAX_PATH]{0};
    GetSystemDirectoryA(str, MAX_PATH);
    return QString::fromStdString(std::string(1, str[0]));
}


//磁盘格式化(需要在winPE执行)
//参数:盘符(c) 、 文件系统(ntfs)
bool CSystemReloadThread::FormatVolume(QString drive, QString format)
{
    QString program = "cmd.exe";
    QStringList arguments;
    arguments << "/c" << "format " + drive + ": /FS:" + format + " /Q /Y";


    QProcess p;
    p.start(program, arguments);
    if (p.waitForStarted())
    {
        p.waitForFinished();
        qDebug() << "成功";
        return true;
    }
    else
    {
        qDebug() << "失败";
        return false;
    }

    return 0;
}


//通过命令行执行外部程序
int CSystemReloadThread::runCMD(std::string cmd)
{
    HANDLE hPipeRead, hPipeWrite;
    SECURITY_ATTRIBUTES saAttr;
    STARTUPINFOA siStartInfo;
    DWORD dwRead;
    CHAR chBuf[4096];

    // 创建匿名管道
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;
    if (!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0))
    {
        return 1;
    }

    // 为子进程设置文件句柄
    SetHandleInformation(hPipeRead, HANDLE_FLAG_INHERIT, 0);

    // 初始化 STARTUPINFOA 结构体
    ZeroMemory(&siStartInfo, sizeof(STARTUPINFOA));
    siStartInfo.cb = sizeof(STARTUPINFOA);
    siStartInfo.hStdOutput = hPipeWrite;
    siStartInfo.hStdError = hPipeWrite;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;

    // 启动外部程序
    if (!CreateProcessA(NULL, (LPSTR)cmd.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo))
    {
        return 1;
    }

    // 关闭管道的写入端,这样在读取管道时可以知道进程已结束
    CloseHandle(hPipeWrite);

    // 循环读取管道中的输出信息
    while (ReadFile(hPipeRead, chBuf, sizeof(chBuf), &dwRead, NULL) && dwRead > 0)
    {
        // 在这里对 chBuf 中的输出信息进行处理
        // 例如输出到控制台
        m_DoingOutput = QString::fromStdString(ANSItoUTF8(chBuf));
        emit sigUpdateDoingText(m_DoingOutput);

//        QFile logfile(QDir::currentPath()+ "/SystemBackup/test.log");
//        logfile.open(QIODevice::ReadWrite|QIODevice::Text|QIODevice::Append);
//        QDataStream out(&logfile);
//        out<< m_DoingOutput <<"\r\n";
//        logfile.close();
    }

    // 等待子进程结束
    WaitForSingleObject(piProcInfo.hProcess, INFINITE);

    // 关闭句柄
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);
    CloseHandle(hPipeRead);

    return 0;
}


//关闭正在执行的外部程序
void CSystemReloadThread::killProcess()
{
    if(piProcInfo.hProcess){
        TerminateProcess(piProcInfo.hProcess,0);
        CloseHandle(piProcInfo.hProcess);
        CloseHandle(piProcInfo.hThread);
    }
}



//下载文件
bool CSystemReloadThread::downloadFile(QString md5, const QString& downloadUrl, const QString& downloadDirPath, const QString& filename)
{
    //请求链接
    QStringList list = downloadUrl.split("/");
    QString filename2 = list.at(list.size() - 1);

    if (filename.length() > 0)
        filename2 = "/" + filename;

    //存放文件夹
    QString downloadDir(downloadDirPath);
    QDir dir(downloadDir);
    if (!dir.exists()) {
        if (!dir.mkpath(downloadDir))
            qDebug() << "failed to create dir";
    }

    //打开目标文件,先open,便于后续分块写入
    QString downloadName(downloadDir + filename2);
    QFile downloadFile(downloadName);
    if (!downloadFile.open(QIODevice::ReadWrite)) {
        qDebug() << "open downloadFile error";
        return false;
    }

    //发送HTTP-Get请求
    QEventLoop* loop = new QEventLoop;
    QNetworkAccessManager* manager = new QNetworkAccessManager(this);
    QNetworkRequest request;
    request.setUrl(QUrl(downloadUrl));

    QNetworkReply* reply = manager->get(request);
    if (!reply) {
        qDebug() << "Failed to send request!";
        return false;
    }
    //信号与槽接收响应
    //分块获取文件信息,并写入文件中
    QObject::connect(reply, &QNetworkReply::readyRead, this, [&]() {
            downloadFile.write(reply->readAll());
        }, Qt::DirectConnection);

    //定时获取下载进度
    qint64 curtype = 0;
    qint64 oldtype = 0;
    qint64 totaltype = 0;
    int usetime = 0;
    QTimer* time = new QTimer(this);
    time->start(1000);
    QObject::connect(time, &QTimer::timeout, this, [&] {
            qint64 speed = curtype - oldtype;
            oldtype = curtype;
            usetime++;
        }, Qt::DirectConnection);

    //网络请求完成时
    QObject::connect(reply, &QNetworkReply::finished, this, [&]() {
            //处理HTTP响应
            if (reply->error() != QNetworkReply::NoError) {
                qDebug() << "Error:" << reply->errorString();
                qDebug() << "download failed!";
                downloadFile.close();
                m_DownloadFlag = false;
                dir.remove(downloadName);
            }
            else {
                downloadFile.write(reply->readAll());
                downloadFile.close();
                qDebug() << "download success";

                //检验文件
                QFile theFile(downloadName);
                if (!theFile.open(QIODevice::ReadOnly)) {
                    qDebug() << "open failed";
                }

                QCryptographicHash hash(QCryptographicHash::Md5);
                const qint64 blockSize = 1024 * 1024 * 100;  // 每次读取的块大小
                QByteArray buffer;
                while (!theFile.atEnd()) {
                    buffer = theFile.read(blockSize);
                    hash.addData(buffer);
                }
                QByteArray md5file = hash.result();

                theFile.close();
                if (md5file.toHex().constData() != md5.toLower()) {
                    m_DownloadFlag = false;
                    DeleteFileA(downloadName.toStdString().c_str());
                }
                else {

                }
            }

            manager->deleteLater();
            reply->deleteLater();
            time->deleteLater();
            loop->exit();
        }, Qt::DirectConnection);

    // 下载进度处理
    QObject::connect(reply, &QNetworkReply::downloadProgress, [&](qint64 bytesReceived, qint64 bytesTotal) {
        //qDebug() << "Downloaded" << bytesReceived << "out of" << bytesTotal << "bytes";
        curtype = bytesReceived;
        totaltype = bytesTotal;
    });

    loop->exec();
    return m_DownloadFlag;
}




//解压压缩包
//传参:压缩包路径、目标文件夹路径
void CSystemReloadThread::unZip(const char* zipName, const char* dirName) {
    int iErr = 0;
    struct zip* zipfile = NULL;
    struct zip_file* entries = NULL;
    struct zip_stat stat;
    zip_int64_t i64Num = 0;
    zip_int64_t i64Count = 0;
    int iRead = 0;
    int iLen = 0;
    char buf[1024];

    memset(&stat, 0, sizeof(stat));
    memset(buf, 0, sizeof(buf));

    zipfile = zip_open(zipName, ZIP_CHECKCONS, &iErr);
    if (!zipfile)
    {
        printf("zip open failed:%d\n", iErr);
        exit(EXIT_FAILURE);
    }

    //get how many entrrites in archive
    i64Num = zip_get_num_entries(zipfile, 0);
    for (i64Count = 0; i64Count < i64Num; i64Count++)
    {
        iLen = 0;
        if (zip_stat_index(zipfile, i64Count, 0, &stat) == 0)
        {
            printf("the file name is:%s\n", stat.name);
        }

        entries = zip_fopen_index(zipfile, i64Count, 0);
        if (!entries)
        {
            printf("fopen index failed\n");
            goto End;
        }

        //create the original file
        char filePath[MAX_PATH]{ 0 };
        strcpy(filePath, dirName);
        strcat(filePath, "/");
        strcat(filePath, stat.name);

        if (filePath[strlen(filePath) - 1] == '/') {
            QDir tempDir(filePath);
            if (!tempDir.exists()) {
                if (!tempDir.mkdir(filePath))
                    qDebug() << "failed to create dir";
            }
            zip_fclose(entries);
            continue;
        }

        FILE* fp = fopen(filePath, "wb+");
        if (!fp)
        {
            printf("create local file failed\n");
            zip_fclose(entries);
            goto End;
        }

        while (iLen < stat.size)
        {
            iRead = zip_fread(entries, buf, 1024);
            if (iRead < 0)
            {
                printf("read file failed\n");
                fclose(fp);
                zip_fclose(entries);
                goto End;
            }

            fwrite(buf, 1, iRead, fp);
            iLen += iRead;
        }

        zip_fclose(entries);
        fclose(fp);
    }

End:
    zip_close(zipfile);
}




//拷贝文件夹
//CopyDir("e:\\zyh","f:\\zyh");
bool CSystemReloadThread::CopyDir(const QString& fromDir, const QString& toDir)
{
    QDir sourceDir(fromDir);
    QDir targetDir(toDir);
    if (!targetDir.exists()) {    /**< 如果目标目录不存在,则进行创建 */
        if (!targetDir.mkpath(targetDir.absolutePath())) {
            qDebug() << targetDir.absolutePath();
            return false;
        }
    }

    QFileInfoList fileInfoList = sourceDir.entryInfoList();
    foreach(QFileInfo fileInfo, fileInfoList) {
        if (fileInfo.fileName() == "." || fileInfo.fileName() == "..")
            continue;

        if (fileInfo.isDir()) {    /**< 当为目录时,递归的进行copy */
            if (!CopyDir(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName())))
                return false;
        }
        else {            /**< 当允许覆盖操作时,将旧文件进行删除操作 */
            if (targetDir.exists(fileInfo.fileName())) {
                targetDir.remove(fileInfo.fileName());
            }

            /// 进行文件copy
            if (!QFile::copy(fileInfo.filePath(), targetDir.filePath(fileInfo.fileName()))) {
                return false;
            }
            else {
                qDebug() << "copy file" << fileInfo.filePath() << "success";
            }
        }
    }
    return true;
}


本次主要利用该工具做系统备份和还原,经研究发现,极客狗装机和老毛桃之类的第三方系统操作软件,调用的其实也是wimlib-imagex.exe,因此进行参考,但是发现利用其备份系统时,有时候遇到某些文件会导出备份出错,暂不清楚原因。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/218803.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Win环境中安装Jenkins指南

目录 安装Java环境 下载并安装Jenkins Jenkins版本 启动Jenkins 如何删除Jenkins 安装Java环境 访问 Oracle官方网站 下载并安装JDK 安装完成后&#xff0c;设置系统环境变量 JAVA_HOME 到你的 JDK 安装路径&#xff0c;并将 %JAVA_HOME%\bin 添加到系统 PATH 中。 下载…

SAP中的新旧事务码

SAP中的新旧事务码 SAP随着新版本的发布&#xff0c;我们知道sap已经更新了很多的程序和TCODE。sap提供了很多新的TCODE来替换旧的TCODE&#xff0c;新TCODE有很多的新特性和新功能。在这个这种情况下&#xff0c;很多旧TCODE就会被废弃。我们如何查找这个替换呢&#xff1f; …

什么是国际语音呼叫中心?国际语音呼叫中心能干什么?

1.什么是国际语音呼叫中心&#xff1f; 国际语音呼叫中心是指利用语音技术提供咨询、客服、销售、市场调研等呼叫中心服务的一种解决方案。与传统的呼叫中心相比&#xff0c;国际语音呼叫中心采用了更加高效、智能的呼叫技术&#xff0c;通过应用智能语音识别技术、自然语言处…

图解通信原理(以太网通信及物理层工作原理)

偶尔看到一篇对phy与mac讲解清楚的优秀文章&#xff0c;因此记录下来&#xff0c;此文章转发自知乎图解通信原理&#xff08;以太网通信及物理层工作原理&#xff09; - 知乎 概述 以太网是一种计算机局域网通信技术&#xff0c;主要由介质访问层(MAC L2) 协议、物理层&#…

采购透明拼接屏,需要注意些什么

在采购透明拼接屏时&#xff0c;需要注意以下几点&#xff1a; 尺寸和分辨率&#xff1a;根据实际应用需求选择合适的尺寸和分辨率。如果用于商业展示&#xff0c;需要选择较大的屏幕尺寸和较高的分辨率&#xff0c;以提供更好的视觉效果和观看体验。 透明度&#xff1a;透明…

企业微信配置可信域名

首先去申请一个域名&#xff0c;然后将域名绑定到有公网ip的云服务器上&#xff0c;绑定到具体的网站&#xff1b;然后再企业微信&#xff0c;管理后台&#xff0c;点击具体的应用&#xff0c;进【网页授权及JS-SDK】&#xff1b;点击底部的【申请校验域名】点击下载文件&#…

从0到1实现Flink 实战实时风控系统的经验总结

随着互联网金融的快速发展&#xff0c;实时风控系统成为保障业务安全和用户信任的关键。本文将分享从零开始构建Flink实时风控系统的经验&#xff0c;并提供相关示例代码。 一、搭建Flink环境 首先&#xff0c;我们需要搭建Flink环境。以下是一些基本步骤&#xff1a; 安装Ja…

HNU-电路与电子学-2021期末A卷(不含解析)

【写在前面】 电路与电子学好像是从2020级开设的课程&#xff0c;故实际上目前只有2020与2021两个年级考过期末考试。 本份卷子的参考性很高&#xff0c;这是2020级的期末考卷。题目都是很典型的&#xff0c;每一道题都值得仔细研究透。 特别注意&#xff1a;看得懂答案跟写得…

编译原理词法分析:NFA转DFA(原理+完整代码+可视化实现)

NFA转换为DFA 【本文内容摘要】 什么是DFA通过子集构造法将NFA转换为DFA生成DFA的dot文件并且形成可视化。 如果本文对各位看官有用的话&#xff0c;请记得给一个免费的赞哦&#xff08;收藏也不错&#xff09;&#xff01; 文章目录 NFA转换为DFA一、什么是DFA二、NFA转换为…

SSM项目实战-前端-将uid存放在pinia中

https://pinia.vuejs.org/zh/getting-started.html 1、安装pinia npm install pinia {"name": "pro20-schedule","private": true,"version": "0.0.0","type": "module","scripts": {"d…

《 金融业图数据库建设发展调研报告 》:政策技术双轮驱动 图数据库未来大有可为

加gzh“大数据食铁兽”&#xff0c;回复“20231204“&#xff0c;获取材料完整版 导读 为更好地了解我国金融业图数据库技术的应用现状及需求&#xff0c;发现行业共性问题&#xff0c;宣传成功经验&#xff0c;本报告组织了针对金融业图数据库建设发展的调研工作&#xff0…

全球与中国木质颗粒燃料市场:增长趋势、竞争格局与前景展望

木质颗粒汽油的主要优点之一是环境永续性。木质颗粒被认为是碳中立的&#xff0c;因为燃烧过程中释放的二氧化碳量大约等于木材生长过程中吸收的二氧化碳量。这种封闭的碳循环减少了温室气体净排放并减轻了气候变迁的影响。作为一种可再生资源&#xff0c;木屑颗粒还可以透过促…

win11 install oh-my-posh

安装配置 下载 Nerd Fonts 字体 oh-my-posh font installNerd Fonts 网站下载&#xff0c;解压后右击安装 为终端设置 Nerd Fonts 字体 修改 Windows 终端设置&#xff08;默认快捷方式&#xff1a;CTRL SHIFT ,&#xff09;&#xff0c;在settings.json文件defaults属性下添…

nginx对多个服务器的高可用,容易出现鉴权失败

高可用简单测试正常&#xff0c;但是出现高概率401鉴权错误 抓包发现&#xff0c;确实是401 &#xff0c; 而鉴权是两次交互&#xff1a; 抓包发现鉴权到不同服务器上了&#xff0c;导致鉴权没有完成。 此时就需要我们的ip_hash,把同一IP地址的请求,都分配给同一台后端服务器&…

Python如何从文件中读取数据

从文件中读取数据 1. 读取整个文件 要读取文件&#xff0c;首先来创建一个文件&#xff1a; 然后打开并读取这个文件&#xff0c;再将其内容显示到屏幕上&#xff1a; file_reader.py with open(pi_digits.txt) as file_object:contents file_object.read()print(contents)…

人工智能时代AIGC绘画实战

系列文章目录 送书第一期 《用户画像&#xff1a;平台构建与业务实践》 送书活动之抽奖工具的打造 《获取博客评论用户抽取幸运中奖者》 送书第二期 《Spring Cloud Alibaba核心技术与实战案例》 送书第三期 《深入浅出Java虚拟机》 送书第四期 《AI时代项目经理成长之道》 …

金和OA saveAsOtherFormatServlet接口任意文件上传漏洞复现 [附POC]

文章目录 金和OA saveAsOtherFormatServlet接口任意文件上传漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 金和OA saveAsOtherFormatServlet接口任意文件上传漏洞复现 [附POC] 0x01 前言 免责…

OA系统是什么,能用低代码开发吗?

OA是什么&#xff1f;管办公室活动的 OA是Office Automation&#xff08;办公自动化&#xff09;的简称&#xff0c;原是指利用电脑进行全自动的办公&#xff0c;现在基本所有和办公相关的系统都可以称作是OA。绝大部分企业将OA用于企业内部的协作沟通&#xff0c;处理企业内部…

Raspberry Pi 2, 2 of n - Pi 作为 IoT 消息代理

目录 介绍 环境 先决条件 - 设置静态 IP 地址 安装 Mosquitto 启动/停止 Mosquitto 配置先决条件 - 安装 mqtt_spy 配置 Mosquitto 配置 Mosquitto - 无安全性 测试 Mosquitto 配置 - 无安全性 配置 Mosquitto - 使用密码身份验证 Mosquitto 测试 - 带密码验证 概括 介绍 在本文…

嵌入式设备里,SOC与MCU的区别是什么?

今日话题&#xff0c;嵌入式设备里&#xff0c;SOC与MCU的区别是什么?MCU与SOC有着明显的区别。MCU是嵌入式微控制器&#xff0c;而SOC则是片上系统。虽然这两者看似只有一个"嵌入式系统"的区别&#xff0c;但实际上在软件和硬件方面存在显著差异。首先&#xff0c;…