Wix部署Office加载项:替换未加载DLL致崩溃的解决方案咨询
Office加载项MSI部署DLL替换崩溃问题的Wix解决方案
一、Wix中实现「无法替换所有文件则终止更新」的方法
要实现“只要有文件无法替换就不执行任何更新”,需要通过自定义动作检测文件锁定状态,在安装初始化前终止安装流程:
编写自定义检测逻辑
用C#或VBScript实现文件占用检测,遍历所有待更新的DLL路径,检查文件是否被进程锁定。一旦发现有文件被占用,返回错误码触发安装终止。Wix配置自定义动作
将检测逻辑打包为二进制文件或脚本,在Wix中配置为前置检查动作:<!-- 注册自定义动作二进制文件 --> <Binary Id="FileLockChecker" SourceFile="FileLockChecker.dll" /> <!-- 定义自定义动作,立即执行并检查返回值 --> <CustomAction Id="CheckAllDLLsUnlocked" BinaryKey="FileLockChecker" DllEntry="CheckDLLLocks" Execute="immediate" Return="check" /> <!-- 在安装序列中插入检查动作 --> <InstallUISequence> <Custom Action="CheckAllDLLsUnlocked" Before="InstallInitialize" /> </InstallUISequence> <InstallExecuteSequence> <Custom Action="CheckAllDLLsUnlocked" Before="InstallInitialize" /> </InstallExecuteSequence>若使用VBScript,可将脚本直接嵌入Wix:
<CustomAction Id="CheckDLLLocksVBS" Script="vbscript"> <![CDATA[ Function CheckDLLLocks() ' 检测指定DLL是否被占用的逻辑示例 Dim fso, filePath, isLocked filePath = Session.Property("TARGETDIR") & "MyAddin.dll" Set fso = CreateObject("Scripting.FileSystemObject") On Error Resume Next fso.OpenTextFile(filePath, 1, False, 1) ' 尝试以只读方式打开 isLocked = (Err.Number <> 0) On Error GoTo 0 If isLocked Then CheckDLLLocks = 1 ' 返回错误,终止安装 Else CheckDLLLocks = 0 ' 继续安装 End If End Function ]]> </CustomAction> <InstallExecuteSequence> <Custom Action="CheckDLLLocksVBS" Before="InstallInitialize" /> </InstallExecuteSequence>
二、其他解决思路
除了“无法替换则终止”,还有更彻底的方案从根源避免冲突:
1. 版本隔离(Side-by-Side部署)
将不同版本的DLL通过Windows Side-by-Side (WinSxS) 技术隔离,让旧版本加载项加载旧DLL、新版本加载项加载新DLL,互不干扰。Wix中可通过Win32Assembly配置:
<Component Id="MyDLL_v1" Guid="*"> <File Id="MyDLL_v1_File" Source="v1\MyDLL.dll" KeyPath="yes"> <Win32Assembly Id="MyDLL_v1_Assembly" Name="MyDLL" Version="1.0.0.0" Language="0" ProcessorArchitecture="x86" /> </File> </Component> <Component Id="MyDLL_v2" Guid="*"> <File Id="MyDLL_v2_File" Source="v2\MyDLL.dll" KeyPath="yes"> <Win32Assembly Id="MyDLL_v2_Assembly" Name="MyDLL" Version="2.0.0.0" Language="0" ProcessorArchitecture="x86" /> </File> </Component>
加载项代码中通过强命名或版本绑定,确保加载对应版本的DLL。
2. 安装前关闭Office进程
在静默部署场景下,可通过自定义动作检测并终止Office相关进程(如WINWORD.EXE、EXCEL.EXE),确保文件可被替换:
<CustomAction Id="CloseOffice" Script="vbscript"> <![CDATA[ Function CloseOfficeProcesses() Dim objWMIService, colProcesses Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") Set colProcesses = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name='WINWORD.EXE' OR Name='EXCEL.EXE' OR Name='POWERPNT.EXE'") For Each proc In colProcesses proc.Terminate() Next CloseOfficeProcesses = 0 End Function ]]> </CustomAction> <InstallExecuteSequence> <Custom Action="CloseOffice" Before="InstallInitialize" /> </InstallExecuteSequence>
注意:此方法需要部署工具具备足够权限,且可能导致用户未保存的Office文档丢失,需提前告知用户。
3. 安装时备份与回滚
若文件替换失败,自动恢复旧版本DLL。Wix中可通过CopyFile实现备份,结合回滚自定义动作:
<!-- 安装前备份旧DLL --> <Component Id="BackupMyDLL" Guid="*"> <CopyFile Id="BackupMyDLL_Copy" SourceFile="[TARGETDIR]MyDLL.dll" DestinationFile="[TARGETDIR]MyDLL_backup.dll" /> </Component> <!-- 定义回滚动作,替换失败时恢复备份 --> <CustomAction Id="RestoreBackupDLL" Script="vbscript"> <![CDATA[ Dim fso Set fso = CreateObject("Scripting.FileSystemObject") fso.CopyFile Session.Property("TARGETDIR") & "MyDLL_backup.dll", Session.Property("TARGETDIR") & "MyDLL.dll", True ]]> </CustomAction> <InstallExecuteSequence> <Custom Action="RestoreBackupDLL" After="Rollback" /> </InstallExecuteSequence>
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

