如何在Visual Studio引导程序中获取MSI安装项目的内置安装目录
我之前在做VS安装项目的引导程序时,也碰到过一模一样的问题——明明设置了DefaultLocation,但实际安装路径偶尔会有偏差,想在引导程序里启动刚装的软件,总怕找错地方。给你几个亲测有效的办法,不用怕路径不准,也不用傻乎乎搜整个AppData:
方法一:用后期生成事件保留ARPINSTALLLOCATION设置
你之前改ARPINSTALLLOCATION被VS重建删除的问题,其实可以用后期生成事件自动把这个设置加回去,每次编译后自动生效,不会丢。具体步骤:
- 打开你的VS安装项目(.vdproj)的属性页
- 找到生成事件 -> 后期生成事件命令行
- 输入一段PowerShell脚本,自动修改vdproj文件:
(Get-Content "$(ProjectDir)$(ProjectName).vdproj") -replace '("ARPINSTALLLOCATION" = "8:.*")', '"ARPINSTALLLOCATION" = "8:[INSTALLDIR]"' | Set-Content "$(ProjectDir)$(ProjectName).vdproj"
这个脚本会在每次编译完成后,自动把ARPINSTALLLOCATION绑定到[INSTALLDIR]。之后引导程序就能通过注册表拿到安装路径:
- 每机器安装:去
HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\[你的产品ProductCode]下找InstallLocation键 - 每用户安装:去
HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\[你的产品ProductCode]下找对应键
方法二:直接读取MSI数据库里的INSTALLDIR属性
MSI本质是个数据库文件,你可以在引导程序里直接读取它的Property表,拿到内置的INSTALLDIR值,这是最准确的,完全不受用户修改安装路径的影响。比如用C#结合Windows Installer相关API实现:
- 引用
Microsoft.Deployment.WindowsInstaller库(VS环境一般默认支持) - 用以下代码读取MSI的内置安装目录:
using (var database = new Database("你的MSI文件路径", DatabaseOpenMode.ReadOnly)) { var view = database.OpenView("SELECT Value FROM Property WHERE Property = 'INSTALLDIR'"); view.Execute(); var record = view.Fetch(); if (record != null) { string installDir = record.GetString(1); // 这里拿到的就是MSI实际使用的安装目录 } }
方法三:在安装项目里手动加注册表项存安装路径
如果不想搞脚本或者读MSI数据库,还有个更简单的办法:在VS安装项目里手动加一个注册表项,把[INSTALLDIR]存进去,引导程序直接读注册表就行:
- 打开你的VS安装项目,右键添加注册表项
- 选择一个合适的路径,比如
HKCU\Software\[Manufacturer]\[ProductName](对应你项目属性里的制造商和产品名) - 新建一个字符串值,比如叫
InstallPath,把它的值设为[INSTALLDIR] - 保存项目,这个设置不会被VS重建删除,因为是你手动添加的自定义项
之后引导程序只要去这个注册表路径读InstallPath,就能拿到准确的安装目录了。
方法四:用Windows Installer API直接查已安装产品的路径
如果你的引导程序是在MSI安装完成后才需要路径,那可以用Windows Installer的MsiGetProductInfo函数,直接通过产品的ProductCode查询安装位置:
比如在C#里可以这么调用(需要引用msi.dll):
[DllImport("msi.dll", CharSet = CharSet.Unicode)] static extern uint MsiGetProductInfo(string productCode, string property, StringBuilder valueBuf, ref int valueBufSize); // 调用示例 string productCode = "你的MSI产品的ProductCode"; StringBuilder pathBuf = new StringBuilder(1024); int bufSize = pathBuf.Capacity; MsiGetProductInfo(productCode, "InstallLocation", pathBuf, ref bufSize); string installDir = pathBuf.ToString().TrimEnd('\0');
这个方法读的是系统里已安装产品的真实信息,完全准确,不会有偏差。
最后说一句,你担心DefaultLocation不准是对的——用户在安装时完全可以手动修改路径,所以DefaultLocation只是默认值,实际安装路径肯定以MSI的INSTALLDIR为准。上面这几个方法都能拿到真实的内置路径,不用去搜整个AppData文件夹,效率和准确性都高多了。




