標籤:Widnows API Dism Qt Wimgapi
使用Windows Api+Qt做的一個系統備份工具
由於公司應用大量裝機的情況,以前使用ghost軟體來處理,但是自從uefi模式出現後ghost已經不能很好的應用了,雖然現在有Acronis軟體替代,但是產生的備份檔案沒有很好的工具去修改,所以遇到需要添加鏡像驅動和補丁的時候帶來非常大的麻煩。系統內建的dism工具確實好用,但是每次都需要輸入命令列輸入,效率不能提高。因此根據現在的實際情況,清明三天假連學帶做了這款視窗版的備份還原工具,功能目前很很簡單,只有備份分區(檔案夾)和還原資料分割函數,下一步會添加驅動添加功能。廢話不說,上代碼。
//DismTools.h qt widget 標頭檔 #pragma once#include <QWidget>#include <QThread>#include "ui_DismTools.h"#include <QString>#include <QLabel>#include "BackUp.h"#include "Restore.h"#include "BcdBoot.h"class DismTools : public QWidget{Q_OBJECTpublic:DismTools(QWidget *parent = Q_NULLPTR);~DismTools(){thread.quit();thread.wait();}private:Ui::DismToolsClass ui;private slots:void on_BackUp_clicked();void on_BackUp_finished(const QString&);void on_Restore_clicked();void on_Restore_finished(const QString&);private:QThread thread;BackUp*bk;Restore *restore;BcdBoot *boot;signals:void backSig(const QString &,const QString &);void restoreSig(const QString &, const QString &);void bcdbootSig(const QString &);//PWSTR pszTmpDir = L"C:\\tmp";};
//dismtools.cpp 代碼#pragma execution_character_set("utf-8")#include "DismTools.h"#include "BackUp.h"#include <QFileInfo>#include <QFileDialog>DismTools::DismTools(QWidget *parent): QWidget(parent){ui.setupUi(this);connect(ui.backUp, &QPushButton::clicked, this, &DismTools::on_BackUp_clicked);connect(ui.restore, &QPushButton::clicked, this, &DismTools::on_Restore_clicked);}void DismTools::on_BackUp_clicked(){QString dir = QFileDialog::getExistingDirectory(this, tr("選擇備份分區"),"/home",QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);QFileInfo fi(dir);if (!fi.exists()){return;}QString fileName = QFileDialog::getSaveFileName(this, QString("儲存鏡像檔案"),"/home/",QString("鏡像檔案 (*.wim)"));QFileInfo fi1(fileName);bk = new BackUp();bk->moveToThread(&thread);connect(&thread, &QThread::finished, bk, &QObject::deleteLater);connect(this, &DismTools::backSig, bk, &BackUp::doBackUp);connect(bk, &BackUp::resultReady, this, &DismTools::on_BackUp_finished);thread.start();ui.label->setText("鏡像備份中...");ui.backUp->setDisabled(true);emit backSig(fileName, dir);}void DismTools::on_BackUp_finished(const QString &finished){ui.label->setText(finished);QMessageBox::warning(this, "", finished);ui.backUp->setDisabled(false);}void DismTools::on_Restore_clicked(){QString dir = QFileDialog::getExistingDirectory(this, tr("選擇恢複分區"),"/home",QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);QFileInfo fi(dir);if (!fi.exists()){return;}QString fileName = QFileDialog::getOpenFileName(this, QString("選擇鏡像檔案"),"/home/",QString("鏡像檔案 (*.wim)"));QFileInfo fi1(fileName);restore = new Restore();restore->moveToThread(&thread);connect(&thread, &QThread::finished, restore, &QObject::deleteLater);connect(this, &DismTools::restoreSig, restore, &Restore::doRestore);connect(restore, &Restore::resultReady, this, &DismTools::on_Restore_finished);thread.start();ui.label->setText("鏡像恢複中...");ui.restore->setDisabled(true);emit restoreSig(fileName, dir);}void DismTools::on_Restore_finished(const QString &finished){ui.label->setText(finished);QMessageBox::warning(this, "", finished);ui.restore->setDisabled(false);int ret = QMessageBox::question(this, "", QString("是否添加引導項?"), QMessageBox::Ok,QMessageBox::No);if (ret = 0){QString souces = QFileDialog::getExistingDirectory(this, tr("選擇Windows系統根目錄"),"/home",QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);QString bootPath = QFileDialog::getExistingDirectory(this, tr("選擇Windows開機磁碟分割"),"/home",QFileDialog::ShowDirsOnly| QFileDialog::DontResolveSymlinks);boot = new BcdBoot();boot->doBcdBoot(souces, bootPath);connect(boot, &BcdBoot::resultReady, this, [=](const QString &result){QMessageBox::information(this, "", result);});return;}}//backup代碼#pragma once#pragma execution_character_set("utf-8")#include <qobject.h>#include <QString>#include <QMessageBox>#include "windows.h"#include "wimgapi.h"class BackUp:public QObject{Q_OBJECTpublic slots:void doBackUp(const QString &pszWimFile,const QString &pszCaptureDir);signals:void resultReady(const QString &result);};
//backup.cpp#include "BackUp.h"#include <QMessageBox>void BackUp::doBackUp(const QString &pszWimFile, const QString &pszCaptureDir){bool sucess = true;const wchar_t * WimFile = reinterpret_cast<const wchar_t *>(pszWimFile.utf16());const wchar_t * CaptureDir = reinterpret_cast<const wchar_t *>(pszCaptureDir.utf16());DWORD dwFlags = 0,dwDisposition = WIM_CREATE_ALWAYS,dwDesiredAccess = WIM_GENERIC_WRITE,dwCreateFlags = 0,dwCaptureFlags = WIM_FLAG_VERIFY,dwCompressionType = WIM_COMPRESS_LZX,dwCreationResult = 0,dwError = 0;HANDLE hWim = WIMCreateFile(WimFile,dwDesiredAccess,dwDisposition,dwCreateFlags,dwCompressionType,&dwCreationResult);sucess = hWim;if (!sucess){//QMessageBox::critical(this, QString("Error!"), QString("BackUp Error with code Create Fail"));//QMessageBox::critical(NULL, QString("Error!"), QString("Create Image Fail"));emit resultReady(QString("檔案建立失敗"));return;}//WIMSetTemporaryPath(hWim, pszTmpDir);HANDLE hImage = WIMCaptureImage(hWim, CaptureDir, dwCaptureFlags);sucess = hImage;if (!sucess){//QMessageBox::critical(NULL, QString("Error!"), QString("BackUp Error with code BackUp Status"));emit resultReady(QString("備份失敗"));return;}WIMCloseHandle(hImage);WIMCloseHandle(hWim);emit resultReady(QString("備份成功"));}
//restore.h 代碼#pragma once#pragma execution_character_set("utf-8")#include <QObject>#include <QString>#include "Windows.h"#include "wimgapi.h"class Restore : public QObject{Q_OBJECTpublic slots:void doRestore(const QString &pszWimFile, const QString &pszCaptureDir);signals:void resultReady(const QString &result);};//restore.cpp#include "Restore.h"void Restore::doRestore(const QString &pszWimFile, const QString &pszCaptureDir){bool sucess = true;const wchar_t * WimFile = reinterpret_cast<const wchar_t *>(pszWimFile.utf16());const wchar_t * pszApplyDir = reinterpret_cast<const wchar_t *>(pszCaptureDir.utf16());HANDLE hWim = NULL,hImage = NULL;DWORD dwCreateFlags = 0,dwCreateResult = 0,dwImageIndex = 1,dwError = 0;WIM_INFO WimInfo = { 0 };hWim = WIMCreateFile(WimFile, // Existing .wim file to append the image toWIM_GENERIC_READ, // Access modeWIM_OPEN_EXISTING, // Open dispositiondwCreateFlags,0, // Compression type is ignored for WIM_OPEN_EXISTING.&dwCreateResult);sucess = hWim;if (!sucess){//QMessageBox::critical(this, QString("Error!"), QString("BackUp Error with code Create Fail"));//QMessageBox::critical(NULL, QString("Error!"), QString("Create Image Fail"));emit resultReady(QString("鏡像讀取失敗"));return;}WIMGetAttributes(hWim, &WimInfo, sizeof(WimInfo));if (WimInfo.ImageCount < dwImageIndex){emit resultReady(QString("鏡像讀取失敗"));return;}WIMSetTemporaryPath(hWim, pszApplyDir);hImage = WIMLoadImage(hWim, dwImageIndex);sucess = hImage;if (!sucess){//QMessageBox::critical(NULL, QString("Error!"), QString("BackUp Error with code BackUp Status"));emit resultReady(QString("不能擷取鏡像索引"));return;}WIMApplyImage(hImage, pszApplyDir, WIM_FLAG_FILEINFO);//sucess = WIMApplyImage(hImage, pszApplyDir, WIM_FLAG_NO_APPLY);if (!sucess){//QMessageBox::critical(NULL, QString("Error!"), QString("BackUp Error with code BackUp Status"));emit resultReady(QString("鏡像還原失敗"));return;}WIMCloseHandle(hImage);WIMCloseHandle(hWim);emit resultReady(QString("鏡像還原成功"));}
bcdboot 代碼就不貼了,簡單的都不不好意思。。。
附件有詳細代碼 測試環境 vs2017+qt msvc2017 +wadk環境,由於製作內部使用,因此介面比較醜陋,有時間最佳化吧
運行
附件連結:代碼
使用Windows Api+Qt做的一個系統備份工具