使用Windows Api+Qt做的一個系統備份工具
阿新 • • 發佈:2018-04-07
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_OBJECT public: 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_OBJECT public 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_OBJECT public 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 to WIM_GENERIC_READ, // Access mode WIM_OPEN_EXISTING, // Open disposition dwCreateFlags, 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做的一個系統備份工具