1. 程式人生 > >使用Windows Api+Qt做的一個系統備份工具

使用Windows Api+Qt做的一個系統備份工具

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做的一個系統備份工具