简介:InstallShield for VC++ 6.0 是专为 Microsoft Visual C++ 6 定制的安装包制作工具,面向使用 VC++6 开发 Windows 程序、需要将 Release 版 EXE 打包发布的开发者。它可直接从 VC++6 的 Tools 菜单调用 InstallShield Wizard,省去单独配置工程与脚本的麻烦,适合中小型桌面软件的安装盘制作与分发场景。压缩包共 27 个文件,约 10.04MB,包含 SETUP.EXE、_ISDEL.EXE 等可执行程序,_SYS1.CAB、_USER1.CAB、DATA1.CAB 等安装数据包,SETUP.INI、FIXUP.INI 等配置脚本,以及 SETUP.INS、SETUP.LID、LAYOUT.BIN 等工程与布局文件,另有 README 说明文档和若干 GIF、JPG、BMP 界面素材,结构完整可直接使用。目前已有 1175 人学习下载。借助该工具,读者能快速生成带安装向导、卸载入口与文件注册逻辑的发布包,掌握从编译到打包的完整流程,减少手工编写安装脚本的排错成本。
1. 为什么今天还有人用 InstallShield 给 VC++ 6.0 项目做安装包
如果你手上维护着一套 VC++ 6.0 的老工程,编译出来的 exe 和一堆 dll、ocx、ini 散在 Release 目录里,客户拿到手第一句话往往是“怎么装”。这时候你大概率会被人推荐 InstallShield——一个在当代开发环境里显得有点年代感、但在 Win32 老项目交付场景里依然能打的打包工具。它能把 VC++ 6.0 产物、运行库、注册表项、快捷方式、卸载入口一次性收进一个 setup.exe,双击就能装,控制面板里能卸。适合谁?适合还在维护工控、医疗设备上位机、老 MFC 系统、产线测试软件的团队,尤其是那些不能轻易升级编译器的项目。这篇笔记就按“选版本 → 建工程 → 收文件 → 写脚本 → 排错”的顺序,把 InstallShield for VC++ 6.0 安装包制作工具这条链路讲透,让你照着能复现一个能装能卸的包。
2. 选对 InstallShield 版本与工程类型:别一上来就翻车
2.1 版本差异与 VC++ 6.0 的匹配关系
InstallShield 的版本线拉得很长,从早期的 InstallShield 5.x、6.x,到后来的 DevStudio、Professional、Premier,再到被收购后的 Express、Professional、Premier 各代。VC++ 6.0 流行的年代,配套常见的是 InstallShield Professional 6.x 和 InstallShield DevStudio 9 这一档。它们对 Win9x/XP 时代的安装行为支持最完整,脚本引擎是 InstallScript,工程文件是 .ism,编译出来是 setup.exe + data 目录。
如果你手头只有较新的 InstallShield 版本,也不是不能用,但要注意两点:一是新版本默认工程模板可能偏向 MSI,对 VC++ 6.0 这种老式文件拷贝+注册表写入的交付方式不如 InstallScript 工程直接;二是新版本生成的 setup.exe 在极老的操作系统上可能跑不起来。所以我的建议是:优先找 InstallShield Professional 6.x 或 DevStudio 9 这一档的安装介质,在虚拟机里装好,专门用来维护老项目。
提示:不要在生产机上直接装老版本 InstallShield,它可能会替换系统里的某些运行库组件,影响其他软件。用一台干净的 WinXP 或 Win7 虚拟机最稳妥。
2.2 工程类型选择:InstallScript 还是 MSI
InstallShield 里新建工程时,常见选项有 InstallScript Project、InstallScript MSI Project、Basic MSI Project 等。对 VC++ 6.0 项目,我一般选InstallScript Project,原因有三:
第一,VC++ 6.0 产物里经常有需要注册的 ocx、需要写注册表的配置项、需要判断系统目录的安装路径,InstallScript 写这些逻辑最顺手。第二,InstallScript 工程编译出来是单文件 setup.exe 加数据包,客户拿到就是一个目录,拷贝走就能装,不需要额外分发 MSI。第三,老项目交付环境里经常有“安装前先检测某个进程是否在运行”“安装后自动启动服务”这类需求,InstallScript 的脚本能力比纯 MSI 灵活。
如果你选 Basic MSI Project,也不是不行,但后面写自定义动作会绕一些,而且 MSI 的日志排查对新手不够友好。所以这篇笔记以 InstallScript Project 为主线。
2.3 新建工程时的关键选项
打开 InstallShield,File → New → Project,选 InstallScript Project,填工程名和保存路径。接下来几个向导页要注意:
- Application Information:填公司名、应用名、版本号、默认安装目录。这里的应用名会出现在控制面板的卸载列表里,别写错。
- Installation Architecture:一般选“Single instance”或“Multiple instance”,老项目多数是单实例。
- Setup Languages:至少勾选中文和英文,后面可以只保留中文。
- Installation Type:选“Full”或“Custom”,如果客户需要选组件,就选 Custom。
建完工程后,你会看到左侧的工程树,核心节点包括:Installation Designer、Script、Setup Files、Components、Files、Registry、Shortcuts 等。后面所有操作都围绕这棵树展开。
3. 把 VC++ 6.0 产物收进安装包:文件、注册表、快捷方式
3.1 用 Components 和 Files 组织文件
VC++ 6.0 项目编译后,Release 目录里通常有:主 exe、若干 dll、可能还有 ocx、ini、dat、帮助文件。不要一股脑全塞进一个 Component,按功能拆成几个 Component,比如“主程序”“运行库”“示例数据”“帮助文档”。这样后面做自定义安装类型时,客户可以只装主程序。
操作步骤:
- 在 Installation Designer 里点 Components,右键 New Component,命名如 MainApp。
- 选中 MainApp,在右侧 Files 页签里,右键 Add Files,把 Release 目录下的主 exe 和依赖 dll 加进来。
- 再建一个 Runtime 组件,把 VC++ 6.0 运行库(mfc42.dll、msvcrt.dll、msvcp60.dll 等)加进来。注意:这些运行库如果目标机器已有,可以选择“Only install if not present”,避免覆盖系统文件。
- 如果项目有 ocx,单独建一个 OCX 组件,后面在脚本里做自注册。
文件加入后,每个文件都有属性:Destination 目录、是否自注册、是否共享、版本号等。Destination 一般用<INSTALLDIR>或<WINDIR>这样的变量。自注册的 ocx 要把“Self-Registered”设为 Yes。
3.2 注册表项与 INI 文件的处理
VC++ 6.0 程序经常把配置写在注册表 HKEY_LOCAL_MACHINE\Software\公司名\应用名 下,或者写在安装目录的 ini 里。InstallShield 的 Registry 节点可以预先定义这些键值。
操作:点 Registry → 右键 New Registry Key,按层级建到你的应用键,然后在右侧加字符串值、DWORD 值。安装时这些键会被写入,卸载时默认会删除(注意:如果键下有用户数据,要谨慎设置卸载行为)。
INI 文件如果需要在安装时生成,可以用 InstallScript 的WriteProfString函数在脚本里写,比直接放一个静态 ini 更灵活,因为安装路径是变量。
3.3 快捷方式与卸载入口
快捷方式在 Shortcuts 节点配置。常见需求:桌面快捷方式、开始菜单程序组、快速启动栏(老系统)。操作:右键 Shortcuts → New Shortcut,指定目标文件(从 Files 里选)、工作目录、图标、名称。
卸载入口 InstallShield 会自动在控制面板注册,但如果你想在开始菜单里也放一个“卸载”快捷方式,可以指向setup.exe并带/uninstall参数,或者用 InstallScript 的LaunchUninstall相关逻辑。注意:卸载快捷方式的目标路径要用<INSTALLDIR>变量,不能写死。
注意:VC++ 6.0 程序如果依赖当前工作目录读取 ini 或 dat,快捷方式的“Start in”一定要设成安装目录,否则双击快捷方式启动后找不到文件,这是血泪经验里最常见的一条。
4. 用 InstallScript 写安装逻辑:从拷贝到自注册
4.1 InstallScript 脚本的基本结构
InstallShield 的脚本文件是 setup.rul,编译后嵌入 setup.exe。脚本里有一系列事件函数,比如OnBegin、OnFirstUIBefore、OnMoving、OnEnd、OnUninstall等。你不需要全部重写,多数逻辑可以在向导生成的骨架上改。
一个典型的 VC++ 6.0 项目安装脚本,核心要做几件事:检测是否已安装、关闭正在运行的程序、拷贝文件、注册 ocx、写注册表、创建快捷方式、安装完成提示。下面给一个精简的脚本片段,展示自注册 ocx 和写注册表的写法。
// setup.rul 片段:自注册 ocx 与写注册表 function OnFirstUIBefore() NUMBER nResult; STRING szAppPath, szKey; begin // 先让 InstallShield 走默认的界面流程 nResult = OnFirstUIBefore(); if (nResult = BACK) then return BACK; endif; // 获取安装目录 szAppPath = TARGETDIR; // 自注册 ocx:假设组件里有个 MyCtrl.ocx if (ComponentIsItemSelected("OCXComponent") = TRUE) then // 调用系统 regsvr32 注册,注意路径要加引号 LaunchAppAndWait(WINDIR ^ "system32\\regsvr32.exe", "/s \"" + szAppPath ^ "MyCtrl.ocx\"", LAAW_OPTION_WAIT); endif; // 写注册表:HKEY_LOCAL_MACHINE\Software\MyCompany\MyApp\InstallPath szKey = "Software\\MyCompany\\MyApp"; RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); RegDBSetKeyValueEx(szKey, "InstallPath", REGDB_STRING, szAppPath, -1); RegDBSetKeyValueEx(szKey, "Version", REGDB_STRING, "1.0.0", -1); return 0; end;逻辑说明:OnFirstUIBefore是首次安装时界面出现前的事件,这里先调用默认实现让向导正常走,然后在后面追加自定义动作。ComponentIsItemSelected判断用户是否勾选了某个组件,避免没装 ocx 却去注册。LaunchAppAndWait调 regsvr32 做静默注册,/s参数不弹框,LAAW_OPTION_WAIT等待注册完成再继续。RegDBSetKeyValueEx写注册表,REGDB_STRING表示字符串值,最后一个参数 -1 表示值长度自动计算。
参数说明:WINDIR是系统目录变量,在 64 位系统上要注意 system32 和 SysWOW64 的区别,但 VC++ 6.0 产物是 32 位的,在 64 位系统上注册 ocx 要用 SysWOW64 下的 regsvr32。如果你的安装包要兼容 64 位系统,这里需要加判断。
4.2 安装前检测与进程关闭
老项目经常遇到“程序正在运行,文件被占用,安装失败”。解决办法是在脚本里检测进程并提示用户关闭,或者直接结束进程。InstallScript 里可以用FindWindow找窗口,或者用LaunchAppAndWait调 taskkill。
// 检测并结束正在运行的主程序 function OnBegin() NUMBER nResult; STRING szCmd; begin // 用 taskkill 结束进程,/IM 指定映像名,/F 强制 szCmd = "cmd.exe /c taskkill /IM MyApp.exe /F"; LaunchAppAndWait("", szCmd, LAAW_OPTION_WAIT | LAAW_OPTION_HIDDEN); // 不关心返回值,进程不存在时 taskkill 会报错,但无所谓 end;逻辑说明:OnBegin是安装开始前的事件,这里直接调 taskkill 强制结束主程序。LAAW_OPTION_HIDDEN隐藏命令行窗口,避免用户看到黑框一闪。注意:强制结束进程可能导致用户数据丢失,更友好的做法是先弹窗提示,用户确认后再结束。这里为了演示简化了。
4.3 安装完成后的收尾动作
安装完成后常见需求:启动主程序、打开帮助文件、写安装日志。可以在OnEnd里做。
function OnEnd() STRING szAppPath; begin szAppPath = TARGETDIR ^ "MyApp.exe"; // 询问用户是否立即启动,这里用静默启动演示 if (LaunchAppAndWait(szAppPath, "", LAAW_OPTION_NOWAIT) < 0) then // 启动失败,可以写日志或提示 MessageBox("主程序启动失败,请手动运行。", INFORMATION); endif; end;逻辑说明:LaunchAppAndWait用LAAW_OPTION_NOWAIT表示不等待程序退出,安装程序继续走完卸载注册等收尾。如果启动失败,弹一个提示框。实际项目中,更常见的是弹一个“是否立即启动”的选择框,用AskYesNo函数。
5. 避坑与排查:VC++ 6.0 打包最常见的五个翻车点
5.1 安装后程序报“找不到 mfc42.dll”
现象:在开发机上装完能跑,到客户机上双击 exe 提示缺少 mfc42.dll 或 msvcr60.dll。
原因:VC++ 6.0 默认动态链接 MFC 和 CRT,但安装包里没带这些运行库,或者带了但没装到系统目录。
解决:在 Components 里单独建一个 Runtime 组件,把 mfc42.dll、msvcrt.dll、msvcp60.dll 加进去,Destination 设为<WINDIR>\System32(32 位系统)或<WINDIR>\SysWOW64(64 位系统上的 32 位程序)。更稳妥的做法是用 InstallShield 自带的 Merge Module,但老版本可能没有 VC++ 6.0 的模块,手动加文件也行。注意不要覆盖系统里更新的版本,文件属性里设“Only install if not present”或比较版本号。
5.2 ocx 注册失败,程序启动报“类未注册”
现象:安装过程没报错,但程序启动时提示某个 ActiveX 控件类未注册。
原因:ocx 文件没有自注册,或者注册时用了 64 位 regsvr32 去注册 32 位 ocx。
解决:在 Files 里把 ocx 的 Self-Registered 设为 Yes,让 InstallShield 自动处理。如果手动写脚本注册,在 64 位系统上要用SysWOW64\regsvr32.exe。另外,注册 ocx 需要管理员权限,安装包要以管理员身份运行。可以在工程设置里勾选“Require Administrator Privileges”。
5.3 卸载后注册表残留,重装时读到旧配置
现象:卸载程序后重新安装,程序读到的还是上次的配置,或者控制面板里出现两个卸载项。
原因:卸载时没有删除自定义注册表键,或者卸载注册信息没清理干净。
解决:在 Registry 节点里,把自定义键的卸载行为设为“Delete on uninstall”。如果键下有用户数据不想删,至少要把 InstallPath、Version 这类安装信息删掉。另外,InstallShield 的卸载信息在 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall 下,如果工程改了应用名或公司名,旧键可能残留,需要手动清理或写脚本删除。
5.4 安装路径含空格或中文,脚本里路径拼接出错
现象:安装到“C:\Program Files\My App”或中文目录后,程序启动找不到文件,或者 ocx 注册失败。
原因:脚本里拼接路径时没加引号,或者用了短路径名导致中文乱码。
解决:所有传给外部程序的路径都要加引号,比如"\"" + szAppPath + "MyCtrl.ocx\""。InstallScript 里字符串拼接用^或+,注意变量类型。如果路径含中文,确保安装包的语言设置里包含了中文,并且脚本文件保存为 ANSI 或 UTF-8 带 BOM 的格式,避免编译后乱码。
5.5 在 64 位系统上安装后,程序读写注册表被重定向
现象:32 位程序在 64 位系统上写 HKEY_LOCAL_MACHINE\Software\MyCompany,结果写到了 Wow6432Node 下,程序自己读不到。
原因:Windows 的注册表重定向机制,32 位程序访问 HKLM\Software 会被重定向到 HKLM\Software\Wow6432Node。
解决:这是正常行为,关键是安装包和程序要一致。如果安装包是 32 位的,写注册表也会被重定向到 Wow6432Node,程序读的时候也在同一位置,没问题。但如果安装包是 64 位的,写到了非重定向位置,32 位程序就读不到。所以要么都用 32 位,要么在脚本里用RegDBSetDefaultRoot配合REGDB_OPTION_WOW64_64KEY标志显式指定。老项目一般保持 32 位一致即可。
6. 进阶:用响应文件做静默安装与版本升级
6.1 生成和编辑响应文件
客户现场批量部署时,不可能每台机器都点下一步。InstallShield 支持用响应文件(.iss 或 setup.iss)做静默安装。生成方法:手动运行一次 setup.exe,在命令行加/r参数记录响应文件,装完后会在 Windows 目录下生成 setup.iss。然后把这个文件放到 setup.exe 同目录,用/s参数静默安装。
# 记录响应文件 setup.exe /r # 静默安装(读取同目录 setup.iss) setup.exe /s # 指定响应文件路径 setup.exe /s /f1"D:\deploy\setup.iss" # 静默卸载 setup.exe /s /uninstall参数说明:/r记录,/s静默,/f1指定响应文件路径,/uninstall触发卸载。注意:响应文件里记录了安装路径、序列号、组件选择等信息,批量部署前要按实际环境改好。如果安装包有自定义对话框,响应文件里也会有对应字段,改的时候要对应上。
6.2 版本升级与覆盖安装
VC++ 6.0 项目的版本升级,常见做法是直接覆盖安装。InstallShield 默认会检测已安装版本,如果版本号相同或更低,可能提示“已安装”。要支持升级,需要在工程设置里改 Product Version,并设置升级行为。
操作:在 Installation Designer → Project Assistant → Application Information 里改版本号。然后在 Upgrade 节点里配置升级逻辑,比如“如果发现旧版本,先卸载再安装”或“直接覆盖”。老项目建议用“直接覆盖”,因为卸载旧版本可能删掉用户配置。
如果升级时要保留用户配置,可以在脚本里先把配置文件备份到临时目录,安装完再恢复。这个逻辑写在OnFirstUIBefore或OnBegin里,用CopyFile和DeleteFile函数。
6.3 安装日志与失败排查
安装失败时,第一手资料是日志。InstallShield 支持/v参数传日志选项,或者用/l指定日志文件。
# 生成详细安装日志 setup.exe /l"D:\log\install.log" # 带 MSI 日志(如果是 MSI 工程) setup.exe /v"/l*v D:\log\msi.log"日志里会记录每一步的文件拷贝、注册表写入、脚本执行结果。排查时重点看返回值非 0 的调用,以及“Failed”关键字。常见错误码:-1 表示一般错误,-2 表示文件未找到,-3 表示路径未找到。结合脚本里的MessageBox或WriteLog函数,可以定位到具体哪一行。
提示:在脚本里加
WriteLog输出关键变量,比事后猜要高效得多。比如在写注册表前WriteLog("InstallPath=" + szAppPath),日志里就能看到实际路径。
6.4 一个我常用的收尾习惯
每次做完安装包,我都会在干净的虚拟机上做三件事:装一遍、卸一遍、再装一遍。第一遍看有没有缺文件,第二遍看卸载干不干净,第三遍看覆盖安装会不会出问题。这个习惯帮我拦住了至少一半的现场故障。另外,安装包做好后,把 setup.exe 和 data 目录一起压缩,计算 MD5 发给客户,避免传输损坏。希望帮到你。
本文还有配套的精品资源,点击获取