軟體安裝程式第二篇(載入程式原始碼)

楊發荷發表於2020-11-28

1、載入程式

mian函式

//不顯示控制檯介面
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) 

// 第一個引數:程式本身執行路徑
// 第二個引數:被新增的資源程式
int main(int argc, char *argv[])
int main(int argc, char *argv[])
{
	if(argc== 1)
		executeInstall(argv[0]);
	if(argc== 2)
		executePackage(argv[0], argv[1]);
	return 1;
}

啟動安裝介面

void executeInstall(const char *exePath)
{
	std::string folder;
	std::string zipFile = virtualFolderName(argv[0], folder);
	releaseResource(zipFile); unzipFile(zipFile, folder);
	std::string exeFile = folder; 
	exeFile += "\\bin\\doxygen.exe " + std::string(argv[0]);
	PROCESS_INFORMATION pi; STARTUPINFOA si = { sizeof(si) };
	ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi));
	BOOL bRet = CreateProcessA(NULL, LPSTR(exeFile.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
	if(bRet)
	{
		::CloseHandle(pi.hThread);
		::CloseHandle(pi.hProcess);
	}
}

此處注意:exeFile += "\bin\doxygen.exe ",在後面會用到。

建立隱藏資料夾

std::string virtualFolderName(const std::string &exeFile, std::string &folder)
{
	size_t pos = exeFile.find_last_of("\\");
	std::string dir = exeFile.substr(0, pos);
	std::string exeName = exeFile.substr(pos);
	pos = exeName.find_last_of(".");
	std::string fName = exeName.substr(0, pos);
	dir += fName; if(_access(dir.c_str(), 0) == -1)
		_mkdir(dir.c_str()); folder = dir;
	SetFileAttributesA(dir.c_str(), FILE_ATTRIBUTE_HIDDEN);
	dir += fName; dir += ".zip"; return dir;
}

釋放資原始檔(安裝介面)

bool releaseResource(const std::string &zipFile)
{
	char fileName[255] = { 0 };
	HMODULE hModule = GetModuleHandle(NULL);
	GetModuleFileNameA(hModule, fileName, 255);
	HMODULE hexe = LoadLibraryA(fileName);
	HANDLE  hFile = CreateFileA(zipFile.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if(hFile == INVALID_HANDLE_VALUE) return false;
	HRSRC src = FindResourceExA(hexe, "安裝程式", "安裝程式", 0);
	if(src)
	{
		HGLOBAL glb = LoadResource(hexe, src);
		if(glb == NULL) return false;
		int dwSize = SizeofResource(hexe, src);
		if(dwSize == 0) return false; DWORD dwWrite = 0;
		WriteFile(hFile, LockResource(glb), dwSize, &dwWrite, NULL);
		UnlockResource(glb); FreeResource(glb); CloseHandle(hFile);
	}
	//釋放可執行檔案
	FreeLibrary(hexe);
	return true;
}

解壓資原始檔(安裝介面)

void unzipFile(const std::string &zipFile, const std::string &folder)
{
	HZIP hZip = OpenZip(zipFile.c_str(), "");
	ZIPENTRY ze;
	DWORD zResult = ZR_OK;
	GetZipItem(hZip, -1, &ze);
	int numitems = ze.index;
	for(int zi = 0; zi < numitems; zi++)
	{
		ZIPENTRY ze;
		GetZipItem(hZip, zi, &ze);
		char filePath[255] = { 0 };
		sprintf(filePath, "%s\\%s", folder.c_str(), ze.name);
		zResult = UnzipItem(hZip, zi, filePath);
	}
	CloseZip(hZip); remove(zipFile.c_str());
}

將安裝介面作為資源寫入exe

void executePackage(const std::string &exeFile, const std::string &path)
{
	size_t pos = exeFile.find_last_of(".");
	std::string zipFile = exeFile.substr(0, pos);
	std::string newExe = zipFile + "_install.exe";
	zipFile += ".zip";
	HZIP hZip = CreateZip(zipFile.c_str(), "");
	CopyFileA(exeFile.c_str(), newExe.c_str(), true);
	compressResource(path, hZip, "");
	CloseZip(hZip);
	addResourceFile(zipFile, newExe);
	DeleteFileA(zipFile.c_str());
}

壓縮檔案(安裝介面)

bool compressResource(const char *path, HZIP hZip, const char *dir)
{
	HANDLE hFile;
	char   buffer[MAX_PATH] = { 0, };
	WIN32_FIND_DATA pNextInfo;
	sprintf(buffer, "%s\\*", path);
	hFile = FindFirstFile(buffer, &pNextInfo);
	if(!hFile) return false; std::string  t;
	while(FindNextFile(hFile, &pNextInfo))
	{

		if(pNextInfo.cFileName[0] == '.')//過濾.和..
			continue;
		if(pNextInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		{
			ZeroMemory(buffer, MAX_PATH); char folder[255] = { 0 };
			sprintf(buffer, "%s\\%s", path, pNextInfo.cFileName);
			if(strlen(dir) == 0)
				sprintf(folder, "%s", pNextInfo.cFileName);
			else
				sprintf(folder, "%s\\%s", dir, pNextInfo.cFileName);
			compressResource(buffer, hZip, folder); continue;
		}
		char dstzn[255] = { 0 };
		if(strlen(dir) == 0)
			sprintf(dstzn, "%s", pNextInfo.cFileName);
		else
			sprintf(dstzn, "%s\\%s", dir, pNextInfo.cFileName);
		sprintf(buffer, "%s\\%s", path, pNextInfo.cFileName);
		ZipAdd(hZip, dstzn, buffer);
	}
	return true;
}

將壓縮的安裝介面作為資原始檔寫入exe中

void addResourceFile(const std::string &zipFile, const std::string &exeFile)
{
	HANDLE hFile = CreateFileA(zipFile.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
	if(hFile == INVALID_HANDLE_VALUE) return;
	SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd;
	InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
	SetSecurityDescriptorDacl(&sd, TRUE, nullptr, FALSE);
	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = &sd;
	sa.bInheritHandle = FALSE;
	struct _stat info;
	_stat(zipFile.c_str(), &info);
	HANDLE mapping = CreateFileMappingA(hFile, &sa, PAGE_READONLY, 0, info.st_size, nullptr);
	if(mapping == nullptr)
	{
		CloseHandle(hFile);
		return;
	}
	LPVOID addr = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
	int ret = GetLastError();
	if(addr == nullptr)
	{
		CloseHandle(mapping);
		CloseHandle(hFile);
		return;
	}
	HANDLE hexe = BeginUpdateResource(exeFile.c_str(), FALSE); if(!hexe) return;
	BOOL r = UpdateResource(hexe, "安裝程式", "安裝程式", 0, addr, info.st_size);
	UnmapViewOfFile(addr); BOOL er = EndUpdateResource(hexe, FALSE); 
	CloseHandle(mapping); CloseHandle(hFile); CloseHandle(hexe); return;
}

到此載入程式完成。

2、使用載入程式

2.1、安裝介面檔案結構

啟動cmd命令列工具,將載入程式(package.exe)直接拖入命令列工具中,然後將安裝介面的路徑新增到載入程式(package.exe)的後面,如下所示:
在這裡插入圖片描述
E:\frameware\software\安裝程式
在這裡插入圖片描述
E:\frameware\software\安裝程式\bin
在這裡插入圖片描述

安裝介面的配置檔案

在這裡插入圖片描述
等待一會之後,在載入程式同資料夾下面會有一個字尾_install.exe的檔案(package_install.exe)。
在這裡插入圖片描述
雙擊執行exe,就會執行之前安裝介面路徑中的bin\doxygen.exe程式。這個執行檔案可以自行修改。

安裝程式介面:

啟動介面顯示是startpicture.bmp圖片

在這裡插入圖片描述

軟體許可是讀取license.lic檔案中的內容。

在這裡插入圖片描述

軟體資訊讀取information.inf檔案中的內容

在這裡插入圖片描述

安裝路徑

在這裡插入圖片描述

安裝進度介面

上面一部分顯示的是一個動畫,中間是顯示詳細的安裝資訊,下面顯示的是安裝進度。
在這裡插入圖片描述

相關文章