在 Visual Studio 项目中配置图标并使用 Inno Setup 创建安装包
在本教程中,我们将学习如何为 Visual Studio 编译项目配置图标,并使用 Inno Setup 创建安装包。教程包括以下部分:
- 设置项目图标:在 Visual Studio 中配置 .exe 文件的图标,或者使用第三方工具替换编译后的图标。
- 创建安装包:使用 Inno Setup 编写脚本,创建安装包。
除了Inno Setup之外,还可以使用NSIS、Enigma Virtual Box。
文章目录
- [在 Visual Studio 项目中配置图标并使用 Inno Setup 创建安装包](#在 Visual Studio 项目中配置图标并使用 Inno Setup 创建安装包)
-
- [1. 设置项目图标(默认为 Cocos Logo 可跳过)](#1. 设置项目图标(默认为 Cocos Logo 可跳过))
-
- [1.1 方法1:在 Visual Studio 中设置 .exe 文件的图标(编译前)](#1.1 方法1:在 Visual Studio 中设置 .exe 文件的图标(编译前))
- [1.2 方法2:使用第三方工具替换 .exe 文件的图标(编译后)](#1.2 方法2:使用第三方工具替换 .exe 文件的图标(编译后))
- [2. 创建安装包](#2. 创建安装包)
-
- [2.1 Inno Setup 脚本说明](#2.1 Inno Setup 脚本说明)
- [2.2 完整脚本实现](#2.2 完整脚本实现)
- [2.3 构建运行](#2.3 构建运行)
- [3. 阶段性小结](#3. 阶段性小结)
- [4. 进一步兼容尝试](#4. 进一步兼容尝试)
-
- [4.1 缺啥补啥](#4.1 缺啥补啥)
- [4.2 辅助方法:使用 Dependency Walker 分析依赖项](#4.2 辅助方法:使用 Dependency Walker 分析依赖项)
- [4.3 其他方法(理论上可行,若前文依旧无法解决可考虑)](#4.3 其他方法(理论上可行,若前文依旧无法解决可考虑))
- [5. 总结](#5. 总结)
1. 设置项目图标(默认为 Cocos Logo 可跳过)
1.1 方法1:在 Visual Studio 中设置 .exe 文件的图标(编译前)
-
准备图标文件 :
确保你有一个 .ico 格式的图标文件。如果你的图标是 .png 格式,可以使用在线工具或图像编辑软件将其转换为 .ico 格式。
-
添加图标资源 :
切换到资源视图之后,右键项目名 -> 添加 -> 资源:
在添加资源中选择 Icon,导入:
切换文件类型后,选择项目 Resource 内的 favicon.ico 文件即可:
双击导入的 icon,页面如下:
-
启动编译,确认 ico :
重新清理解决方案,启动编译之后,确认编译文件夹下的 exe 文件是否不再是原 Cocos 的 logo:
1.2 方法2:使用第三方工具替换 .exe 文件的图标(编译后)
如果你已经编译好 .exe 文件并希望在编译后设置执行程序的 logo,可以使用第三方工具替换图标。
例如,可以使用 Resource Hacker 替换图标,这里给出一个思路(未尝试)。
2. 创建安装包
使用 Inno Setup 创建安装包,包含自定义安装包的图标、应用名称和安装路径。
下载地址:Inno Setup 官方网站
进入官方网站后点击下载即可:点击下载
下载安装后新建一个空脚本(.iss 文件),进行如下操作。
2.1 Inno Setup 脚本说明
我们基于以下内容作为示例:
- 游戏编译文件夹路径为
E:\cocos\IceHockey\proj.win32\Release.win32
- 图标路径为
E:\cocos\IceHockey\proj.win32\Release.win32\Resources\favicon.ico
- 游戏名称是"冰球大作战"
- 编译后的可执行文件名是
IceHockey.exe
首先,在脚本顶部定义参数:
bash
#define MyAppName "冰球大作战"
#define MyAppVersion "1.0"
#define MyAppSource "E:\cocos\IceHockey\proj.win32\Release.win32"
#define MyAppExeName "IceHockey.exe"
#define MyAppIcon "E:\cocos\IceHockey\proj.win32\Release.win32\Resources\favicon.ico"
MyAppName
:应用程序的名称,将显示在安装向导和快捷方式中。MyAppVersion
:应用程序的版本号。MyAppSource
:游戏编译后的输出目录路径,包含可执行文件和资源文件。MyAppExeName
:应用程序的可执行文件名称。MyAppIcon
:应用程序的图标文件路径,将用于安装包和快捷方式图标。
在脚本部分相关配置如下:
-
[Setup]
部分:AppName
:安装程序显示的应用名称。AppVersion
:安装程序显示的应用版本。DefaultDirName
:应用程序的默认安装目录。DefaultGroupName
:开始菜单中的程序组名称。OutputBaseFilename
:生成的安装包文件名。Compression
和SolidCompression
:安装包的压缩选项。SetupIconFile
:安装程序的图标文件。
-
[Files]
部分:Source
和DestDir
:定义要打包的文件及其目标目录。Flags: ignoreversion
:忽略文件版本检查。recursesubdirs
:递归包含子目录中的所有文件。
-
[Icons]
部分:Name
:快捷方式名称和位置。Filename
:快捷方式指向的可执行文件。IconFilename
:快捷方式使用的图标文件。
2.2 完整脚本实现
根据模板生成完整的 Inno Setup 脚本(.iss 文件):
bash
#define MyAppName "冰球大作战"
#define MyAppVersion "1.0"
#define MyAppSource "E:\cocos\IceHockey\proj.win32\Release.win32"
#define MyAppExeName "IceHockey.exe"
#define MyAppIcon "E:\cocos\IceHockey\proj.win32\Release.win32\Resources\favicon.ico"
[Setup]
; 安装程序信息
AppName={#MyAppName}
AppVersion={#MyAppVersion}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename={#MyAppName}Setup
Compression=lzma
SolidCompression=yes
SetupIconFile={#MyAppIcon}
[Files]
; 将所有游戏文件添加到安装包
Source: "{#MyAppSource}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MyAppSource}\*.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MyAppSource}\Resources\*"; DestDir: "{app}\Resources"; Flags: ignoreversion recursesubdirs
[Icons]
; 创建桌面快捷方式
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
; [Run]
; 安装完成后自动运行游戏
; Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: nowait postinstall skipifsilent
此时页面如下:
2.3 构建运行
随后点击构建中的编译或运行(Run),进行安装后测试游戏是否可以直接打开运行:
在我们安装 Inno Setup 6 的 output 目录中,即可看到我们的安装包:
点击后效果如下:
最终生成的页面图标如下:
3. 阶段性小结
通过上述步骤,即可在 Visual Studio 项目中设置 .exe 文件的图标,并使用 Inno Setup 创建包含自定义图标和安装路径的安装包。
至此即实现了 Cocos2d-x 游戏打包,我们可以发给其他游戏开发课程的同学了。
(blog over)
4. 进一步兼容尝试
4.1 缺啥补啥
如果发给没有配置 Visual Studio 环境的电脑,如缺失 Microsoft Visual C++ Redistributable packages、Windows SDK 10.0.17763.0 的机房电脑,依旧运行不起来:
经尝试,找到电脑中此 DLL 文件后放入打包目录中一起打包,则会出现下一个 DLL 文件缺失:
递归两三轮的实践后,发现一共缺失如下:
- MSVCP140.DLL
- MSVCR120.dll
- MSVCR110.dll
- VCRUNTIME140.DLL
- VCRUNTIME140D.dll
- ucrtbased.dll
推荐下载 Everything(速度快)搜索,一般在如下地址也能找到:
C:\Windows\System32
xx\Microsoft Visual Studio\2022(版本)\Community\VC\Redist\...
C:\Program Files (x86)\Windows Kits\10\bin\10.xxx(SDK 版本)
更新后的脚本如下(或者不更新脚本,将其移入MyAppSource文件夹内即可):
bash
#define MyAppName "冰球大作战"
#define MyAppVersion "1.0"
#define MyAppSource "E:\cocos\IceHockey\proj.win32\Release.win32"
#define MyAppExeName "IceHockey.exe"
#define MyAppIcon "E:\cocos\IceHockey\proj.win32\Release.win32\Resources\favicon.ico"
; 缺啥补啥
#define VcRunTime "C:\windows\system32\VCRUNTIME140.DLL"
#define MSVCP140 "C:\windows\system32\MSVCP140.DLL"
#define MSVCR120 "C:\windows\system32\MSVCR120.DLL"
#define MSVCR110 "C:\windows\system32\MSVCR110.DLL"
#define WindowsKitsDir "C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0"
#define System32Dir "C:\Windows\System32"
#define UCRTDir "C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\ucrt"
[Setup]
; 安装程序信息
AppName={#MyAppName}
AppVersion={#MyAppVersion}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename={#MyAppName}-only-Denpendency
Compression=lzma
SolidCompression=yes
SetupIconFile={#MyAppIcon}
[Files]
; 将所有游戏文件添加到安装包
Source: "{#MyAppSource}\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MyAppSource}\*.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MyAppSource}\Resources\*"; DestDir: "{app}\Resources"; Flags: ignoreversion recursesubdirs
; 添加缺失的依赖文件
Source: "{#VcRunTime}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MSVCP140}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MSVCR120}"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#MSVCR110}"; DestDir: "{app}"; Flags: ignoreversion
; 添加 Windows Kits 目录下的所有 DLL 文件
; Source: "{#WindowsKitsDir}\*.dll"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
; 添加 System32 目录下的所有 DLL 文件
; Source: "{#System32Dir}\*.dll"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
; 添加 ucrtbased.dll 文件
Source: "{#UCRTDir}\ucrtbased.dll"; DestDir: "{app}"; Flags: ignoreversion
; 添加 vcruntime140d.dll 文件
Source: "{#System32Dir}\vcruntime140d.dll"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
; 创建桌面快捷方式并使用自定义图标
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{#MyAppIcon}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{#MyAppIcon}"
[Run]
; 安装完成后自动运行游戏
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: nowait postinstall skipifsilent
经实践,此时打包安装后可成功运行!
(blog over again)
4.2 辅助方法:使用 Dependency Walker 分析依赖项
根据 bug 搜集对应的 dll 文件多少有点被动。
理论上,使用 Dependency Walker 分析依赖项,可以提前知道所有需要包含的 DLL 文件以及对应的文件。
- 下载并安装 Dependency Walker。
- 打开你的可执行文件(例如
FinalGame.exe
)。 - Dependency Walker 会显示所有依赖的 DLL 文件。右键 show full path,记录所有需要的文件,然后将它们添加到 Inno Setup 脚本中。
(PS:这个软件使用分析依赖项的时候特别卡,体验极差。)
4.3 其他方法(理论上可行,若前文依旧无法解决可考虑)
手动逐一添加 DLL 文件虽然可以最轻量地解决问题,但或许并不是最优雅和高效的方法。
显然,Microsoft Visual C++ Redistributable packages 不仅仅包含这些,最关键的是,如果手动找全了所有的 dll,是否会出现其他的无法运行问题。
-
下载 Visual C++ Redistributable Package,将 Visual C++ Redistributable Package 安装程序包含在安装包中,并在安装过程中自动安装。这样可以确保目标机器上安装了所有必要的运行时库,一同放入安装包内。
- 前往 Microsoft Visual C++ Redistributable Packages 页面。
- 下载适用于 Cocos2d-x 应用程序的所有必要的 Visual C++ Redistributable Packages。例如,Visual Studio 2013、2015 - 2022,下载相应的 redistributable 安装程序,还有 Windows SDK。
- 设置 Inno 安装脚本时同时运行这个安装包。
bash#define VcRedist "vcredist_x64.exe" [Run] ; 安装 Visual C++ Redistributable Filename: "{tmp}\{#VcRedist}"; Parameters: "/quiet /norestart"; StatusMsg: "Installing Visual C++ Redistributable..."; Flags: waituntilterminated
-
在 Visual Studio 中配置静态链接运行时库,编译后重新打包(会增加可执行文件大小,Maybe 从 30M => 300M)。
- 打开项目属性。
- 导航到
C/C++
->代码生成
。 - 在
运行时库
下,选择多线程 (/MT)
或多线程调试 (/MTd)
。 - 重新编译项目。
5. 总结
本篇博客希望你不仅掌握了如何在 Visual Studio 项目中设置 .exe 文件的图标,还学会了使用 Inno Setup 创建包含自定义图标和安装路径的安装包。
我们还探讨了如何解决在目标机器上运行游戏时可能遇到的 DLL 缺失问题。希望这篇教程能帮助你更顺利地发布和分享你的游戏。