C++制作安装包【1】—— 控制台实现

这篇具有很好参考价值的文章主要介绍了C++制作安装包【1】—— 控制台实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++制作安装包【1】—— 控制台实现

之前用NSIS的时候发现不方便自制UI,找了其他的安装包开发框架,开发手感还是不好,功能残缺不一。我就想 如何使用纯代码的方式制作安装包 呢?经历了众多艰难才终于摸出方法。网上现有的文章都是用NSIS,Windows Installer等等现成框架制作安装包的。所以我另开一个专栏,直接讲如何手撸安装包!

1.新建项目,包含所需的头文件

推荐开发环境:VS2022

#include<Windows.h>								//大Win头
#include<ShlObj.h>								//COM接口头文件
#include<wrl.h>									//用于COM接口,方便我们调用
using namespace Microsoft::WRL;

#include<iostream>								//C++标准输入输出
#include<fstream>								//C++标准文件
#include<string>								//C++标准字符串,另外也用于宽窄字符转换
using namespace std;

#include "zlib/zlib.h"							//源于Zlib,是Zlib的源头
#include "zlib/unzip.h"							//Zlib第三方库minizip的一个头文件,用于解压zip文件

#pragma comment(lib,"zlib/zlibstat")			//Zlib链接库

#include "resource.h"							//向项目添加资源时自动生成的资源头文件

Zlib地址:https://wwek.lanzoub.com/irjyk0i1gyhc

这里我们引用了一个第三方库 Zlib,上边已经有我编译好的Zlib库。各位读者直接去链接下载解包,将文件夹直接放进项目文件夹就行了。(这里的Installer是我的项目文件夹)

C++制作安装包【1】—— 控制台实现

为什么我们要引用 Zlib 库?一般而言,安装包其实是一个本身包含压缩文件的可执行程序 ,运行时就会将文件解压到安装目录,并通过修改注册表的方式将软件录入到系统里,从而实现程序的安装与卸载。所以我们使用 Zlib 库,实现程序自解压文件的功能 (当然你可以自己造轮子实现)

C++制作安装包【1】—— 控制台实现

2.将压缩文件添加到项目

那么我们如何将压缩文件“嵌入”到程序中呢?
我们可以利用 Windows资源文件(.rc文件) 载入

1.将压缩文件放入项目中

C++制作安装包【1】—— 控制台实现

2.右键项目->添加->新建项,资源->选择 资源文件(.rc)->添加

C++制作安装包【1】—— 控制台实现
C++制作安装包【1】—— 控制台实现

3.在资源视图里右键点击RC文件->添加资源->自定义->类型名称填入ZIP (可以自定义,只是个字符串资源),确定后就会发现我们已经将"ZIP"这个字符串加入资源文件里了。

C++制作安装包【1】—— 控制台实现
C++制作安装包【1】—— 控制台实现
C++制作安装包【1】—— 控制台实现

4.按第3步的方法再次添加资源,选择导入->右下角选择 所有文件 ->点击压缩文件->打开,选择你刚刚创建的资源类型 (弹出的列表会有),确定后回到“解决方案资源管理器”即可。

C++制作安装包【1】—— 控制台实现
C++制作安装包【1】—— 控制台实现
C++制作安装包【1】—— 控制台实现
C++制作安装包【1】—— 控制台实现
可以看到,新生成了四个文件项:

resource.h:这个头文件是VS自动生成的,定义资源ID这些琐事由VS帮我们做
Resource.rc:定义资源的引用列表
test.zip:使用的压缩文件,本质上还是对该文件的引用。所以在编译前我们是可以随时修改这个压缩文件的
zip1.bin:将链接资源的二进制文件,编译器通过这个实现文件的“嵌入”

当然,你嫌VS帮你做,结果导致报错改来改去很麻烦,可以手动重写 Resource.rc 和 resource.h 文件,不要忘记将Zip导入项目中就行了,这里不在一一赘述。

3.将资源从内存写入硬盘中

我们光有zip资源是不行的,我们要想一个方法将资源从程序中“取出来”,过程如下:

  1. FindResource() 通过资源描述符寻找zip资源
  2. LoadResource() 加载资源到内存
  3. LockResource() 锁定资源并得到资源在内存的指针

有了这三步,就能取zip文件到硬盘了。


	HINSTANCE hins = GetModuleHandle(0);    // 获取当前程序实例
	HRSRC my_zip = nullptr;					// 资源标识句柄
	DWORD zip_size = 0;						// 资源大小
	HGLOBAL zip_data = nullptr;				// 资源数据
		
	my_zip = ::FindResource(hins, MAKEINTRESOURCE(IDR_ZIP2), L"ZIP");  //通过资源标识符寻找资源
	zip_size = SizeofResource(nullptr, my_zip);						   //获取资源大小
	zip_data = LoadResource(nullptr, my_zip);						   //加载资源

	WCHAR SetupPath[MAX_PATH] = L"D:\\desktop\\myInstaller";		   //安装目录
	CreateDirectory(SetupPath, nullptr);							   //创建目录

	wstring AddStrEngine(SetupPath);
	AddStrEngine = AddStrEngine + wstring(L"\\m_zip.zip");

	// 先创建文件
	HANDLE zipfile = CreateFile2(AddStrEngine.c_str(), GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr);
	// 将数据写入文件
	WriteFile(zipfile, (LPCVOID)LockResource(zip_data), zip_size, nullptr, nullptr);
	// 关闭文件
	CloseHandle(zipfile);

4.解压文件

我们将zip文件取出来,接下来就可以解压了。
解压要连续经历7步:

  1. unzOpen64()————————————————打开zip
  2. unzGetGlobalInfo64()———————————— 读取zip全局数据
  3. unzGetCurrentFileInfo64()—————————— 获取当前解压文件信息
  4. unzOpenCurrentFile()———————————— 打开文件
  5. unzReadCurrentFile()———————————— 解压当前文件到内存
  6. unzCloseCurrentFile()————————————关闭当前文件
  7. unzClose()—————————————————关闭zip文件

C++制作安装包【1】—— 控制台实现

本质上还是依靠循环来读取并解压的。


	char zipLocation[MAX_PATH];				//zip位置
	unzFile compressZip = nullptr;			//zip句柄
	unz_global_info64 globalinfo = {};		//zip全局信息
	size_t zip_info_filename_length = 0;	//当前解压的文件名长度
	size_t zip_info_file_size = 0;			//当前解压的文件大小
	char* zip_info_FileName = nullptr;		//当前解压的文件名
	char* zip_info_FileData = nullptr;		//当前解压的文件数据
	unz_file_info64 fileinfo = {};			//解压文件的信息
	ofstream unzip_fstream;					//解压文件流
	string AStrEngine;						//用于拼接字符串

	sprintf_s(zipLocation, MAX_PATH, "%ws", AddStrEngine.c_str());
	compressZip = unzOpen64(zipLocation);		//打开zip

	unzGetGlobalInfo64(compressZip, &globalinfo);	//读取zip全局数据


	for (size_t i = 0; i < globalinfo.number_entry; ++i)	//逐个解压
	{
		AStrEngine.clear();
		AStrEngine = "D:\\desktop\\myInstaller\\";
		fileinfo = {};
		zip_info_FileName = new char[MAX_PATH];
		unzGetCurrentFileInfo64(compressZip, &fileinfo, zip_info_FileName, MAX_PATH,
			nullptr, 0, nullptr, 0);
		//获取当前解压文件信息

		zip_info_file_size = fileinfo.uncompressed_size;
		zip_info_FileData = new char[zip_info_file_size];
		zip_info_filename_length = strlen(zip_info_FileName);


		//如果是文件夹
		if (zip_info_FileName[zip_info_filename_length - 1] == '/')
		{
			AStrEngine += zip_info_FileName;
			CreateDirectoryA(AStrEngine.c_str(), nullptr);	
			//创建文件夹,解压文件时会解压到相应目录
		}
		else    //如果是文件就解压
		{
			unzOpenCurrentFile(compressZip);	//打开文件

			AStrEngine += zip_info_FileName;
			unzip_fstream.open(AStrEngine.c_str(), ios::out | ios::binary);
			unzReadCurrentFile(compressZip, reinterpret_cast<void*>(zip_info_FileData), zip_info_file_size);
			//读取当前文件到内存

			unzip_fstream.write(zip_info_FileData, zip_info_file_size);		//将文件从内存写入到硬盘里
			unzip_fstream.close();											//关闭文件
		}
		unzCloseCurrentFile(compressZip);	//关闭当前文件

		delete[] zip_info_FileName;
		delete[] zip_info_FileData;

		if (i + 1 < globalinfo.number_entry)
		{
			unzGoToNextFile(compressZip);	//解压下一个文件,指针偏移
		}
	}

	unzClose(compressZip);	//关闭zip文件

看到代码这么多,估计你此时和我都是一个表情 (😅),其实这部分代码很适合封装成函数,因为其功能对于做一个普通的安装包来说已经够完备了!你只要理解上述7步就可以立刻上手Zlib解压,只是麻烦在内存读取罢了。

5.修改注册表,将程序录入到系统中

C++制作安装包【1】—— 控制台实现
读者是不是经常看到这个“烦人”的UAC (用户账户控制) 窗口?然而,这个窗口可以提供基本的保护,起码不受简单恶意程序对系统的篡改 (绕过UAC的除外) 。安装或卸载程序时如果有设置UAC,这个窗口就会弹出,如果安装程序没有获得管理员的许可,获得相应的权限,是不能读取与修改注册表的,即安装失败。 这个时候,我们就需要申请权限。
C++制作安装包【1】—— 控制台实现
如何像一般安装包一样,先申请管理员权限再安装?

右键项目->属性->链接器->清单文件->UAC执行级别->将级别设为 RequireAdministrator (管理员)

C++制作安装包【1】—— 控制台实现
C++制作安装包【1】—— 控制台实现
有了管理员权限,仅差一步就大功告成了:


	HKEY hkey = nullptr;	//根键句柄

	//创建一个叫 MyInstaller 的子键,这个是安装与卸载程序的地方
	RegCreateKeyEx(HKEY_LOCAL_MACHINE,
		L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MyInstaller",
		0, (WCHAR*)L"", 0, KEY_READ | KEY_WRITE,
		nullptr, &hkey, nullptr);

	//打开子键
	RegOpenKey(HKEY_LOCAL_MACHINE,
		L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MyInstaller", &hkey);

	//设置在"程序与功能"中显示的应用图标 (启动程序地址)
	RegSetValueEx(hkey, L"DisplayIcon", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"D:\\desktop\\myInstaller\\d3dx12.exe"),
		wcslen(L"D:\\desktop\\myInstaller\\d3dx12.exe") * 2);

	//设置在"程序与功能"中显示的应用名称
	RegSetValueEx(hkey, L"DisplayName", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"我的程序"),
		wcslen(L"我的程序") * 2);

	//设置版本号
	RegSetValueEx(hkey, L"DisplayVersion", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"1.0.0.0"),
		wcslen(L"1.0.0.0") * 2);

	//设置发布者 (所属公司)
	RegSetValueEx(hkey, L"Publisher", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"DGAF"),
		wcslen(L"DGAF") * 2);

	//设置安装路径
	RegSetValueEx(hkey, L"InstallLocation", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"D:\\desktop\\myInstaller\\"),
		wcslen(L"D:\\desktop\\myInstaller\\") * 2);

	//设置卸载地址
	RegSetValueEx(hkey, L"UninstallString", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"D:\\desktop\\myInstaller\\Uninstall.exe"),
		wcslen(L"D:\\desktop\\myInstaller\\Uninstall.exe") * 2);

	//关闭子键
	RegCloseKey(hkey);
	

用到了以下四个函数,读者可以自行网上搜:

  1. RegCreateKeyEx
  2. RegOpenKey
  3. RegSetValueEx
  4. RegCloseKey

C++制作安装包【1】—— 控制台实现

我这边没有用管理员开VS,就会弹出这个窗口,可以直接到编译路径找到.exe,点击运行就行了

C++制作安装包【1】—— 控制台实现

效果就是这样,大家可以注意到,我现在还没有给出 Uninstall.exe 的源码。下一篇教程,我会讲如何做安装界面,顺带连卸载程序一并讲。可能有聪明的读者已经想到,原理都是一个样,还是用 修改注册表,删程序 的方式卸载,只不过是卸完擦屁股罢了。

6.添加程序快捷方式到桌面和开始菜单中

不多说,上代码:


	WCHAR DesktopPath[MAX_PATH];				//桌面路径
	WCHAR Programs_path[MAX_PATH];				//开始菜单路径
	::SHGetSpecialFolderPath(nullptr, DesktopPath, CSIDL_DESKTOPDIRECTORY, false);		//获取桌面路径
	::SHGetSpecialFolderPath(nullptr, Programs_path, CSIDL_PROGRAMS, false);			//获取菜单路径

	ComPtr<IShellLink>		pShortcutLink;		//lnk链接接口
	ComPtr<IPersistFile>	pPersistFile;		//lnk文件接口

	//创建pShortcutLink
	CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShortcutLink)); 

	pShortcutLink->SetPath(L"D:\\desktop\\MyInstaller\\Media Play.exe");			//设置启动程序
	pShortcutLink->SetIconLocation(L"D:\\desktop\\MyInstaller\\softmgr.ico", 0);	//设置快捷方式图标位置
	pShortcutLink->SetWorkingDirectory(L"D:\\desktop\\MyInstaller\\");				//设置快捷方式工作目录
	pShortcutLink->SetDescription(L"一个快捷方式");									//设置说明

	pShortcutLink.As(&pPersistFile);	//将数据传递给pPersistFile接口

	//最终创建快捷方式

	pPersistFile->Save((wstring(DesktopPath) + wstring(L"\\myInstaller.lnk")).c_str(), false);	//添加到桌面
	pPersistFile->Save((wstring(Programs_path) + wstring(L"\\myInstaller.lnk")).c_str(), false);	//添加到开始菜单

到这里,你的安装包就大功告成了。

C++制作安装包【1】—— 控制台实现

完整代码示例


// Media Player Setup.cpp

#include<Windows.h>								//大Win头
#include<ShlObj.h>								//COM接口头文件
#include<wrl.h>									//用于COM接口,方便我们调用
using namespace Microsoft::WRL;

#include<iostream>								//C++标准输入输出
#include<fstream>								//C++标准文件
#include<string>								//C++标准字符串,另外也用于宽窄字符转换
#include<conio.h>								//用于接收键盘消息
using namespace std;

#include "zlib/zlib.h"							//源于Zlib,是Zlib的源头
#include "zlib/unzip.h"							//Zlib第三方库minizip的一个头文件,用于解压zip文件

#pragma comment(lib,"zlib/zlibstat")			//Zlib链接库

#include "resource.h"							//向项目添加资源时自动生成的资源头文件



int main()
{
	::CoInitialize(nullptr);	//初始化COM接口

	HINSTANCE hins = GetModuleHandle(0);				//获取当前程序实例
	HRSRC my_zip = nullptr;								//资源标识句柄
	DWORD zip_size = 0;									//资源大小
	HGLOBAL zip_data = nullptr;							//资源数据
	wstring StrPrintfEngineW;							//用于拼接字符串的Unicode版本
	WCHAR* SetupPathW = new WCHAR[MAX_PATH];			//安装目录的Unicode版本
	BROWSEINFO file_open_dialog = {};					//文件夹选择框
	LPITEMIDLIST idl = nullptr;
	

	cout << endl;
	cout << "您正在安装零秋Player!\n"
		 << "按Y确认安装,并选择安装目录\n"
		 << "按N取消安装并退出\n";

	bool isExit = false;	//是否退出循环

	while (!isExit)
	{
		if (_kbhit())			//如果有键盘消息
		{
			switch (_getch())
			{
			case 'N':
			case 'n':
				exit(0);
				break;

			case 'Y':
			case 'y':
				file_open_dialog.hwndOwner = nullptr;
				file_open_dialog.pszDisplayName = SetupPathW;
				file_open_dialog.lpszTitle = L"请选择你的安装目录:";
				file_open_dialog.ulFlags = BIF_RETURNFSANCESTORS;

				idl = SHBrowseForFolder(&file_open_dialog);		//如果没有选择就继续
				if (nullptr == idl)
				{
					continue;
				}
				SHGetPathFromIDList(idl, SetupPathW);
				isExit = true;
				break;

			}
		}
	}


	//————————————————————————————————————————————————————————————————————————————————————————————————————————————
	


	my_zip = ::FindResource(hins, MAKEINTRESOURCE(IDR_ZIP2), L"ZIP");  //通过资源标识符寻找资源
	zip_size = SizeofResource(nullptr, my_zip);						   //获取资源大小
	zip_data = LoadResource(nullptr, my_zip);						   //加载资源


	StrPrintfEngineW = SetupPathW;
	StrPrintfEngineW += wstring(L"\\ZAMediaPlayerSetup.zip");

	// 先创建文件
	HANDLE zipfile = CreateFile2(StrPrintfEngineW.c_str(), GENERIC_WRITE, 0, CREATE_ALWAYS, nullptr);
	// 将数据写入文件
	WriteFile(zipfile, (LPCVOID)LockResource(zip_data), zip_size, nullptr, nullptr);
	// 关闭文件
	CloseHandle(zipfile);



	//————————————————————————————————————————————————————————————————————————————————————————————————————————————


	char SetupPathA[MAX_PATH];				//安装路径的ASCII版本
	char zipLocation[MAX_PATH];				//zip位置
	unzFile compressZip = nullptr;			//zip句柄
	unz_global_info64 globalinfo = {};		//zip全局信息
	size_t zip_info_filename_length = 0;	//当前解压的文件名长度
	size_t zip_info_file_size = 0;			//当前解压的文件大小
	char* zip_info_FileName = nullptr;		//当前解压的文件名
	char* zip_info_FileData = nullptr;		//当前解压的文件数据
	unz_file_info64 fileinfo = {};			//解压文件的信息
	ofstream unzip_fstream;					//解压文件流
	string StrPrintfEngineA;				//用于拼接字符串的ASCII版本

	sprintf_s(SetupPathA, MAX_PATH, "%ws", SetupPathW);
	sprintf_s(zipLocation, MAX_PATH, "%ws", StrPrintfEngineW.c_str());
	compressZip = unzOpen64(zipLocation);		//打开zip

	unzGetGlobalInfo64(compressZip, &globalinfo);	//读取zip全局数据


	for (size_t i = 0; i < globalinfo.number_entry; ++i)	//逐个解压
	{
		StrPrintfEngineA = SetupPathA;
		StrPrintfEngineA += "\\";
		fileinfo = {};
		zip_info_FileName = new char[MAX_PATH];
		unzGetCurrentFileInfo64(compressZip, &fileinfo, zip_info_FileName, MAX_PATH,
			nullptr, 0, nullptr, 0);
		//获取当前解压文件信息

		zip_info_file_size = fileinfo.uncompressed_size;
		zip_info_FileData = new char[zip_info_file_size];
		zip_info_filename_length = strlen(zip_info_FileName);


		//如果是文件夹
		if (zip_info_FileName[zip_info_filename_length - 1] == '/')
		{
			StrPrintfEngineA += zip_info_FileName;
			CreateDirectoryA(StrPrintfEngineA.c_str(), nullptr);
			//创建文件夹,解压文件时会解压到相应目录
		}
		else    //如果是文件就解压
		{
			unzOpenCurrentFile(compressZip);	//打开文件

			StrPrintfEngineA += zip_info_FileName;
			unzip_fstream.open(StrPrintfEngineA.c_str(), ios::out | ios::binary);
			unzReadCurrentFile(compressZip, reinterpret_cast<void*>(zip_info_FileData), zip_info_file_size);
			//读取当前文件到内存

			unzip_fstream.write(zip_info_FileData, zip_info_file_size);		//将文件从内存写入到硬盘里
			unzip_fstream.close();											//关闭文件
		}
		unzCloseCurrentFile(compressZip);	//关闭当前文件

		delete[] zip_info_FileName;
		delete[] zip_info_FileData;

		if (i + 1 < globalinfo.number_entry)
		{
			unzGoToNextFile(compressZip);	//解压下一个文件,指针偏移
		}
	}

	unzClose(compressZip);	//关闭zip文件


	//————————————————————————————————————————————————————————————————————————————————————————————————————————————


	HKEY hkey = nullptr;	//根键句柄

	//创建一个叫 MyInstaller 的子键,这个是安装与卸载程序的地方
	RegCreateKeyEx(HKEY_LOCAL_MACHINE,
		L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZA_MediaPlayer",
		0, (WCHAR*)L"", 0, KEY_READ | KEY_WRITE,
		nullptr, &hkey, nullptr);

	//打开子键
	RegOpenKey(HKEY_LOCAL_MACHINE,
		L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZA_MediaPlayer", &hkey);

	StrPrintfEngineW = SetupPathW;
	StrPrintfEngineW += L"\\";
	StrPrintfEngineW += L"Media Player.exe";

	//设置在"程序与功能"中显示的应用图标 (启动程序地址)
	RegSetValueEx(hkey, L"DisplayIcon", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(StrPrintfEngineW.c_str()),
		StrPrintfEngineW.length() * 2);


	//设置在"程序与功能"中显示的应用名称
	RegSetValueEx(hkey, L"DisplayName", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"零秋Player"),
		wcslen(L"零秋Player") * 2);

	//设置版本号
	RegSetValueEx(hkey, L"DisplayVersion", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"1.0.0.0"),
		wcslen(L"1.0.0.0") * 2);

	//设置发布者 (所属公司)
	RegSetValueEx(hkey, L"Publisher", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(L"DGAF"),
		wcslen(L"DGAF") * 2);


	//设置安装路径
	RegSetValueEx(hkey, L"InstallLocation", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(SetupPathW),
		wcslen(SetupPathW) * 2);


	StrPrintfEngineW = SetupPathW;
	StrPrintfEngineW += L"\\";
	StrPrintfEngineW += L"Uninstall.exe";


	//设置卸载地址
	RegSetValueEx(hkey, L"UninstallString", 0, REG_SZ,
		reinterpret_cast<const BYTE*>(StrPrintfEngineW.c_str()),
		StrPrintfEngineW.length() * 2);

	//关闭子键
	RegCloseKey(hkey);



	//————————————————————————————————————————————————————————————————————————————————————————————————————————————



	WCHAR DesktopPath[MAX_PATH];				//桌面路径
	WCHAR Programs_path[MAX_PATH];				//开始菜单路径

	::SHGetSpecialFolderPath(nullptr, DesktopPath, CSIDL_DESKTOPDIRECTORY, false);		//获取桌面路径
	::SHGetSpecialFolderPath(nullptr, Programs_path, CSIDL_PROGRAMS, false);			//获取菜单路径

	ComPtr<IShellLink>		pShortcutLink;		//lnk链接接口
	ComPtr<IPersistFile>	pPersistFile;		//lnk文件接口

	CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShortcutLink));

	StrPrintfEngineW = SetupPathW;
	StrPrintfEngineW += L"\\";

	pShortcutLink->SetPath((StrPrintfEngineW + wstring(L"Media Player.exe")).c_str());			//设置启动程序
	pShortcutLink->SetIconLocation((StrPrintfEngineW + wstring(L"appicon.ico")).c_str(), 0);	//设置快捷方式图标位置
	pShortcutLink->SetWorkingDirectory(SetupPathW);												//设置快捷方式工作目录
	pShortcutLink->SetDescription(L"零秋播放器——快捷方式");										//设置说明

	pShortcutLink.As(&pPersistFile);	//将数据传递给pPersistFile接口

	//最终创建快捷方式

	pPersistFile->Save((wstring(DesktopPath) + wstring(L"\\零秋播放器.lnk")).c_str(), false);		//添加到桌面
	pPersistFile->Save((wstring(Programs_path) + wstring(L"\\零秋播放器.lnk")).c_str(), false);		//添加到开始菜单


	StrPrintfEngineW = SetupPathW;
	StrPrintfEngineW += wstring(L"\\ZAMediaPlayerSetup.zip");

	DeleteFile(StrPrintfEngineW.c_str());		//删除多余的安装zip

	cout << endl;
	cout << "安装已完成!" << endl;
	system("pause");

}

C++制作安装包【1】—— 控制台实现
C++制作安装包【1】—— 控制台实现

C++制作安装包【1】—— 控制台实现

这里有示例😎项目下载:https://wwek.lanzoub.com/iA0RE0ia3yri
密码:dgaf
下一章,我们将会用 Windows窗口 完善这个安装包。文章来源地址https://www.toymoban.com/news/detail-442306.html

到了这里,关于C++制作安装包【1】—— 控制台实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 超好玩C++控制台打飞机小游戏,附源码

    我终于决定还是把这个放出来。 视频在这:https://v.youku.com/v_show/id_XNDQxMTQwNDA3Mg==.html 具体信息主界面上都有写。 按空格暂停,建议暂停后再升级属性。 记录最高分的文件进行了加密。 有boss(上面视频2分47秒)。 挺好玩的。 可能有bug,不想改了,整体体验不错就行了。 更多

    2024年02月05日
    浏览(35)
  • Docker安装sentinel控制台

    1、拉取镜像,直接使用run命令,如果说本地没有镜像就会直接去远程仓库拉取: --network是你自己建立的网桥,不加这一行也行,就是默认网桥bridge 按照我的命令你是执行不成功的,因为没有网桥,此时你需要先将你创建的这个docker 容器删掉 docker rm -f  sentinel-dashboard  把网

    2024年02月03日
    浏览(35)
  • RocketMQ, Dashboard, 控制台安装

    本文主要说明RocketMQ的控制台(Dashboard)的安装过程。工作中一直用的是别人装好的,这次终于自己亲手装了一遍。 由于每次都要启动三个应用,比较烦,于是我写了一键启动脚本,分享给大家。这个脚本可以一键启动RocketMQ的所有应用。还能自动识别应用是否已经启动成功

    2024年02月14日
    浏览(28)
  • Docker安装Elasticsearch和控制台

    安装 Elasticsearch 使用 Docker 非常简单。以下是详细步骤: 安装 Docker :如果你还没有安装 Docker,请从 Docker 官网 下载并安装适用于你操作系统的 Docker 版本。 拉取 Elasticsearch 镜像 :打开命令行界面(CLI),输入以下命令以从 Docker Hub 拉取最新的 Elasticsearch 镜像: 请确保将

    2024年02月04日
    浏览(30)
  • 在控制台实现贪吃蛇

    本文通过C语言在Windows环境下的控制台实现贪吃蛇小游戏,实现的基本功能包括地图的绘制,蛇的移动(这个过程到底是吃到食物还是没有吃到食物),以及贪吃蛇是否撞墙,或撞到自身,通过贪吃蛇是否吃到食物来计算当前的得分,还将实现加速减速的功能以及暂停游戏的

    2024年04月27日
    浏览(36)
  • 08-Linux安装RocketMQ、RocketMQ控制台

    下载RocketMQ         http://rocketmq.apache.org/release_notes/release-notes-4.4.0/ 环境要求         Linux 64位操作系统         64bit JDK 1.8+ 1 上传文件到Linux系统         /usr/local/rocketMQ 2 解压到安装目录         unzip rocketmq-all-4.4.0-bin-release.zip 3 解压后的文件夹名为 rocketmq-4

    2024年02月05日
    浏览(32)
  • 区块链搭建联盟链及控制台安装

    执行成功后,我们将看到当前目录下生成了一个 nodes 目录。nodes 目录下存在两个目录,分别是 127.0.0.1 和 cert ,我们进入 127.0.0.1 目录 ,执行执行 bash start_all.sh , 看到输出 “start successfully” 表示节点启动成功。至此,一切顺利的话,我们的链就创建并启动成功了 检查是否

    2024年02月02日
    浏览(43)
  • 【c++】设置控制台窗口字体颜色和背景色(system和SetConsoleTextAttribute函数 )

    编译后弹出的黑框框(exe 可执行文件)总是黑底白字,在做实践大作业时想到尝试改变字体的颜色与背景色,搜索发现有 system 和 SetConsoleTextAttribute 两个函数,各有长处,详细了解一下,为了以后的使用。 操作平台:Microsoft Visual Studio 2019  [content] system函数 (Windows系统)

    2024年02月06日
    浏览(42)
  • java实现控制台购书系统

    目录 代码 实现思路 0x1 创建Book图书 0X2 读取图书 0x3 书籍判断  0x4 订单计算 总结 就是增删改查,定义图书为class类,但是图书Bokk class的有参构造函数为数组类型实例化。,这样可以将书籍的编号名称,单击库存依次存入,使用就通过数组books[]的索引来拿到每一项的值,通过遍历数组

    2024年01月21日
    浏览(34)
  • C++编程案例讲解-基于结构体的控制台通讯录管理系统

    添加联系人 :向通讯录中添加新人,信息包括(姓名、性别、年龄、联系电话、家庭住址)最多记录1000人 显示联系人 :显示通讯录中所有的联系人信息 删除联系人 :按照姓名进行删除指定联系人信息 查找联系人 :按照姓名查看指定联系人信息 修改联系人 :按照姓名重新

    2024年02月05日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包