简介InstallShield for VC 6.0 是专为 Microsoft Visual C 6 定制的安装包制作工具面向使用 VC6 开发 Windows 应用程序、需要将 Release 版 EXE 打包发布的开发者。它可直接从 VC6 的 Tools 菜单调用 InstallShield Wizard省去单独配置工程与脚本的麻烦适合刚接触安装包制作、希望快速生成标准安装向导的初中级开发者。资源包共 27 个文件约 10.04MB包含 setup.exe、_isdel.exe 等可执行程序_sys1.cab、_user1.cab、data1.cab 等安装数据压缩包setup.ins、setup.lid、setup.ini 等安装脚本与配置以及 dll、dat、htm、gif、bmp 等运行库、说明文档与界面素材覆盖安装向导运行所需的完整组件。目前已有 1174 人学习下载。借助该工具读者可把调试完成的程序快速封装为带界面、带卸载与注册表写入的安装包直接用于项目交付或软件分发省去手工编写安装脚本的环节。1. Installshield for VC 6.0 安装包制作工具老 IDE 的最后一公里手里维护着一套 VC 6.0 编译出来的 MFC 程序代码能跑、功能稳定客户现场却卡在“怎么装”这一步——这是很多工控、医疗设备、老产线软件维护者共同的处境。Installshield for VC 6.0 安装包制作工具说的就是当年随 Visual C 6.0 一起分发的那套 InstallShield 5.x/6.x 版本它能把编译出来的 exe、dll、ocx、ini 打包成一个带向导界面、能写注册表、能注册 COM 组件、能判断系统环境的 setup.exe。今天还在用它的人多半不是怀旧而是新工具链装不进那台只能跑 XP 或 Win7 的现场机器。这篇笔记按“它到底能干什么 → 工程怎么建 → 脚本怎么改 → 坑在哪 → 怎么验证”的顺序讲目标是让你照着能把一个 VC 6.0 的 MFC 工程打成可交付的安装包。2. InstallShield 5.x 工程结构与 VC 6.0 的衔接方式2.1 为什么老项目还在用这套组合VC 6.0 生成的程序有个绕不开的特征它依赖 mfc42.dll、msvcrt.dll、msvcp60.dll 这一批运行库而且很多老工程用的是 MFC 静态链接之外的动态链接方式目标机器上没装对应运行库就直接报“找不到 mfc42.dll”。InstallShield 5.x 的价值在于它自带一套运行库检测和分发机制能在安装阶段把 VC 运行库一起铺到系统目录还能通过Dependency Walker式的扫描把工程依赖的 dll 自动列进安装清单。另一个现实原因是 COM 组件注册。VC 6.0 时代大量功能靠 ocx 和 dll 实现这些组件必须在安装时用regsvr32注册否则程序启动就报“类未注册”。InstallShield 的Self-Registration机制能在文件拷贝完成后自动调用注册逻辑比手写批处理可靠得多。常见做法是在工程里把 ocx 标记为 self-registered安装脚本里不用额外写注册命令。还有一点是安装界面。老项目的交付对象往往是产线工人或医院设备科他们对“解压到某个目录再双击 exe”这种交付方式接受度低需要一个带“下一步”的向导。InstallShield 5.x 的默认模板就能生成这种界面改改公司名和 logo 就能用不需要额外写 UI 代码。2.2 工程目录里每个文件管什么一个典型的 InstallShield 5.x 工程目录长这样理解每个文件的职责是改脚本的前提文件/目录作用改它的场景Setup.rul主安装脚本InstallScript 语言加自定义检测、改安装流程*.ipr工程文件记录文件分组和快捷方式增删要打包的文件File Groups文件分组定义如AppExecutables把新 dll 归到对应组Components组件定义决定哪些文件一起装拆分主程序和帮助文档Setup.ini安装初始化参数改产品名、版本号、默认路径Language多语言资源加中文界面字符串Setup.rul是核心它用的是 InstallScript 语言语法接近 C但有自己的事件函数OnBegin、OnFirstUIBefore、OnMoving、OnEnd。VC 6.0 工程编译出来的文件不会自动进安装包需要在File Groups里手动添加或通过Link方式关联。我一般会把主 exe 和核心 dll 放一个组把 ocx 单独放一个组并勾选 self-registered把配置 ini 放第三个组安装时按组控制覆盖策略。2.3 从 VC 6.0 工程到安装包的最小操作链假设你有一个编译好的 MFC 工程输出目录是Release里面有MainApp.exe、Core.dll、Grid.ocx、config.ini。下面是从零建一个安装工程的步骤。第一步打开 InstallShield 5.x 的Project Wizard选Standard Setup产品名填你的软件名公司名填客户单位版本号按实际填。向导会问是否允许用户改安装路径老项目一般选“允许”因为现场机器盘符不统一。第二步在File Groups面板右键新建三个组AppBin、AppOcx、AppConfig。把MainApp.exe和Core.dll拖进AppBinGrid.ocx拖进AppOcxconfig.ini拖进AppConfig。第三步选中Grid.ocx在属性面板勾选Self-Registered。这一步等价于告诉安装程序拷贝完这个文件后自动调regsvr32。第四步在Components面板新建一个组件MainComponent把三个文件组都挂进去。如果帮助文档要单独装就再建一个组件。第五步打开Setup.rul在OnFirstUIBefore里加一段检测如果目标机器已经装了更高版本提示用户先卸载。InstallScript 里用RegDBGetKeyValueEx读注册表版本号用MessageBox弹提示。// Setup.rul 片段检测已安装版本 function OnFirstUIBefore() NUMBER nResult; STRING szVersion; begin // 读取注册表中已安装版本 RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); nResult RegDBGetKeyValueEx( SOFTWARE\\MyCompany\\MainApp, Version, nType, szVersion, nSize ); if (nResult 0) then // 已安装过比较版本 if (szVersion 2.0.0) then MessageBox(检测到已安装更高版本请先卸载。, SEVERE); abort; endif; endif; // 继续默认安装界面 return 0; end;这段脚本的逻辑是先设注册表根为HKEY_LOCAL_MACHINE读SOFTWARE\MyCompany\MainApp下的Version值。如果读到了且大于等于当前要装的版本就弹框并中止安装。参数说明RegDBGetKeyValueEx的第三个参数是类型第四个是接收值的字符串变量第五个是缓冲区大小。注意 InstallScript 的字符串比较是按字典序版本号最好用固定位数如2.0.0和1.9.9避免10.0被当成小于9.0。第六步编译安装工程。InstallShield 会生成setup.exe和一堆.cab文件。如果选了Single Executable就只出一个 exe但体积会大一些。老项目交付一般选单文件方便拷贝。3. 脚本里必须改的四个地方和对应参数3.1 安装路径默认值与 Program Files 判断InstallShield 默认把路径设成C:\Program Files\公司名\产品名但 XP 和 Win7 的 Program Files 路径可能不同32 位和 64 位系统也不一样。常见做法是在OnFirstUIBefore里用GetSystemInfo判断系统类型再拼路径。// 根据系统类型设置默认安装路径 function OnFirstUIBefore() STRING szDefaultPath; NUMBER nType; begin GetSystemInfo(OS_TYPE, nType); if (nType OS_64BIT) then szDefaultPath C:\\Program Files (x86)\\MyCompany\\MainApp; else szDefaultPath C:\\Program Files\\MyCompany\\MainApp; endif; // 把默认路径写入安装界面 SetInstallDir(szDefaultPath); return 0; end;GetSystemInfo的第一个参数OS_TYPE返回系统类型OS_64BIT是常量。SetInstallDir把路径传给安装向导的路径选择页。注意 InstallScript 里反斜杠要写两个字符串拼接用。如果客户现场有绿色版需求可以把默认路径改成D:\MainApp但要在文档里写清楚。3.2 注册表写入与卸载信息登记安装程序不写卸载信息控制面板里就看不到你的软件客户想卸载只能手动删目录。InstallShield 5.x 在OnEnd里可以写注册表把卸载串登记到Uninstall键下。// 写入卸载信息 function OnEnd() STRING szUninstall; STRING szInstallDir; begin // 获取安装目录 szInstallDir TARGETDIR; // 拼卸载命令 szUninstall szInstallDir ^ setup.exe /uninstall; RegDBSetDefaultRoot(HKEY_LOCAL_MACHINE); RegDBSetKeyValueEx( SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MainApp, DisplayName, REGDB_STRING, MainApp 2.0, -1 ); RegDBSetKeyValueEx( SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MainApp, UninstallString, REGDB_STRING, szUninstall, -1 ); return 0; end;TARGETDIR是 InstallScript 的内置变量保存用户选的安装目录。^是字符串拼接符和 C 的不同。RegDBSetKeyValueEx的最后一个参数-1表示字符串长度自动计算。注意UninstallString指向的setup.exe必须在安装目录里存在所以打包时要把setup.exe本身也放进安装文件否则卸载会找不到程序。3.3 运行库检测与 VC 6.0 依赖分发VC 6.0 程序依赖的mfc42.dll、msvcrt.dll、msvcp60.dll在目标机器上不一定有。InstallShield 5.x 自带一个Redistributable机制但老版本的清单可能不全。我一般手动把这三个 dll 放进AppBin组然后在OnMoving里检测系统目录是否已有更高版本。// 检测系统目录运行库版本 function OnMoving() STRING szSysDir; STRING szDllPath; NUMBER nResult; begin szSysDir GetSystemDir(); szDllPath szSysDir ^ \\mfc42.dll; nResult FileExists(szDllPath); if (nResult 0) then // 系统没有从安装包拷贝 CopyFile(TARGETDIR ^ \\mfc42.dll, szSysDir); endif; return 0; end;GetSystemDir返回系统目录XP 下是C:\Windows\System32。FileExists返回 0 表示不存在。CopyFile把安装目录里的 dll 拷到系统目录。注意这个操作需要管理员权限如果客户是普通用户账户拷贝会失败。替代方案是把 dll 放在程序同目录但 VC 6.0 的 MFC 程序默认从系统目录加载同目录加载需要改 manifest 或注册表老项目一般不折腾直接要求管理员安装。3.4 快捷方式与开始菜单项安装完不建快捷方式用户找不到程序。InstallShield 5.x 在OnEnd里用CreateShortCut建桌面和开始菜单快捷方式。// 创建快捷方式 function OnEnd() STRING szExePath; STRING szShortcut; begin szExePath TARGETDIR ^ \\MainApp.exe; // 桌面快捷方式 szShortcut C:\\Documents and Settings\\All Users\\Desktop\\MainApp.lnk; CreateShortCut(szExePath, szShortcut, , , , 0); // 开始菜单 szShortcut C:\\Documents and Settings\\All Users\\Start Menu\\Programs\\MainApp.lnk; CreateShortCut(szExePath, szShortcut, , , , 0); return 0; end;CreateShortCut的参数依次是目标 exe、快捷方式路径、参数、工作目录、图标路径、图标索引。All Users目录在 XP 下是C:\Documents and Settings\All UsersWin7 下是C:\ProgramData所以这段脚本在 Win7 上会失败。更稳的做法是用GetFolderPath获取系统文件夹路径但 InstallShield 5.x 的GetFolderPath支持有限常见做法是判断系统版本后拼路径。4. 避坑InstallShield 5.x 在 VC 6.0 项目里的五个翻车点4.1 安装包在 Win7 上提示“不是有效的 Win32 应用程序”现象在 XP 上编译好的setup.exe拷到 Win7 上双击报错。原因InstallShield 5.x 生成的安装引擎是 16 位或早期 32 位Win7 64 位不兼容。解决在 InstallShield 工程设置里把Setup Launcher改成 32 位模式或者用 InstallShield 6.x 以上版本重新编译。如果客户只有 Win7 64 位建议直接换 InstallShield 2010 之后的版本但那样就不叫“for VC 6.0”了需要重新做工程。4.2 ocx 注册失败程序启动报“类未注册”现象安装过程没报错但程序启动时弹“Class not registered”。原因Self-Registered勾选了但 ocx 依赖的其他 dll 没一起注册或者注册时权限不够。解决先用regsvr32手动注册一次看报什么错。如果是依赖缺失用Dependency Walker打开 ocx 看缺哪个 dll把缺失的 dll 也放进安装包。如果是权限问题在OnEnd里用LaunchAppAndWait显式调regsvr32并加/s静默参数。4.3 安装路径含中文或空格导致脚本失败现象用户把程序装到D:\我的软件安装完成但快捷方式指向错误。原因InstallScript 对中文路径处理不好TARGETDIR变量里的中文可能变成乱码。解决在OnFirstUIBefore里检测路径是否含非 ASCII 字符如果有就提示用户换路径。或者干脆把默认路径设成纯英文并在文档里写明“不要装到中文目录”。4.4 卸载时残留注册表和文件现象控制面板卸载后注册表里还有SOFTWARE\MyCompany\MainApp安装目录里还有config.ini。原因InstallShield 只删除自己记录的文件用户后来生成的配置文件不在清单里。解决在OnUninstall事件里手动删注册表键和残留目录。InstallScript 用RegDBDeleteKey删键用DeleteDir删目录但DeleteDir只能删空目录需要先DeleteFile删文件。4.5 编译出的 setup.exe 体积过大现象一个 5MB 的程序安装包 50MB。原因InstallShield 默认把运行库、多语言资源全打进去了。解决在File Groups里去掉不需要的语言包在Setup.ini里把Compression设成High在Media设置里选Single Executable并勾选Compress。如果还是大检查是不是把Debug目录的文件也打进去了只打Release目录。5. 验证安装包是否可交付的三个硬指标5.1 在干净虚拟机上跑一遍完整安装卸载装完系统后不打任何补丁直接跑setup.exe看能不能装完、程序能不能启动、卸载后目录和注册表是否干净。这一步能暴露 80% 的依赖问题。我一般用 VMware 建一个 XP SP3 快照每次改完安装脚本就恢复快照重跑一遍。注意虚拟机要设成和客户现场一样的系统版本和位数XP 32 位和 Win7 32 位的表现可能不同。5.2 用 Process Monitor 看安装过程写了哪些注册表安装时开着 Process Monitor过滤RegSetValue和CreateFile看安装程序到底写了哪些键、拷了哪些文件。如果发现写了不该写的键比如覆盖了系统运行库的版本号就要在脚本里加判断。这个工具比看 InstallShield 日志直观适合排查“装完系统变慢”这类玄学问题。5.3 检查安装日志里的错误码InstallShield 会在%TEMP%下生成Setup.log里面记录了每一步的结果。安装失败时先看这个日志搜Error和Fail。常见的错误码-1是文件拷贝失败-2是注册表写入失败-3是权限不足。日志里还会记录TARGETDIR的实际值如果路径不对说明SetInstallDir没生效。5.4 一个我常用的版本号自增技巧每次发版手动改Setup.ini里的版本号容易忘我习惯在 VC 6.0 工程里加一个version.h用宏定义版本号然后在 InstallShield 的Setup.rul里用#include引入这个头文件。InstallScript 支持#include但路径要用相对路径或绝对路径。这样编译安装包时版本号自动和程序一致减少“装完发现版本不对”的返工。// version.h 放在 VC 工程和 InstallShield 工程都能找到的目录 #define APP_VERSION 2.0.3 #define APP_NAME MainApp// Setup.rul 里引用 #include ..\\..\\version.h function OnBegin() STRING szMsg; begin szMsg APP_NAME ^ ^ APP_VERSION ^ 安装程序; SetTitle(szMsg, 0); return 0; end;SetTitle设置安装向导的标题栏文字。#include的路径是相对于Setup.rul所在目录的如果两个工程不在同一目录树就用绝对路径但绝对路径换机器会失效所以最好把version.h放在两个工程都能访问的公共目录比如D:\Project\Common。这套组合我用了很多年最大的体会是InstallShield 5.x 的脚本能力足够应付 VC 6.0 项目的交付但它的坑集中在系统兼容性和权限上每次换客户环境都要重新验证一遍。别信“一次做好到处能装”老 IDE 的安装包没有银弹只有快照和日志。希望帮到你。本文还有配套的精品资源点击获取