我花了一天时间试图做最简单的事情。 (男人,MSI / WiX很少!)
我的目标非常简单。卸载我的应用程序时,我需要删除安装文件夹。我这样创建它(使用WiX):
<Directory Id='TARGETDIR' Name='SourceDir'>
<Directory Id='ProgramFilesFolder' Name='InstallFolder'>
<Directory Id='idCompany.com' Name='$(var.CompanyName)'>
<Directory Id='INSTALLDIR' Name='$(var.ProductThis)' >
<Component Id='CompIDMyEXE1' Guid='{--GUID1--}'>
<File Id='idMyEXE1' Name='MyExe1.exe' DiskId='1' Source='MyExe1.exe' Vital='yes' KeyPath='yes' />
<ServiceControl Id="idSrvc" Name="SrvcName" Stop="both" Wait="yes" />
</Component>
<Component Id='CompIDMyEXE2' Guid='{--GUID2--}'>
<File Id='idMyEXE2' Name='MyExe2.exe' DiskId='1' Source='MyExe2.exe' Vital='yes' KeyPath='yes' />
</Component>
<!-- and so on -->
</Directory>
</Directory>
</Directory>
我首先尝试使用RemoveFolder WiX关键字,因为它是suggested here,但无论我做了什么,我的安装文件夹都不想去。更糟糕的是,没有办法知道它为什么不起作用。没有看到我的标签,或者是什么...... arghhh!
所以我决定添加一个用C编写的自定义动作并从那里删除该文件夹,因为我会有更多的控制权。所以我这样做了:
<CustomAction Id="CA_SetProperties_UninstallFinalize" Property="CA_msiOnUninstallFinalize" Value="[INSTALLDIR]" />
<CustomAction Id='CA_msiOnUninstallFinalize' BinaryKey='CADll' DllEntry='msiOnUninstallFinalize' Execute='deferred' Impersonate='no' />
<InstallExecuteSequence>
<!-- Need to run it for uninstalls only -->
<Custom Action="CA_SetProperties_UninstallFinalize" Before="InstallFinalize">
NOT REINSTALL AND NOT UPGRADINGPRODUCTCODE AND REMOVE
</Custom>
<Custom Action="CA_msiOnUninstallFinalize" After="CA_SetProperties_UninstallFinalize">
NOT REINSTALL AND NOT UPGRADINGPRODUCTCODE AND REMOVE
</Custom>
<!-- ... -->
</InstallExecuteSequence>
但是当我在空的安装文件夹中使用msiOnUninstallFinalize
方法调用RemoveDirectory API时,它会一直返回ERROR_SHARING_VIOLATION
错误。
所以我在msiOnUninstallFinalize
方法中放了一个休息点(只需添加一个MessageBox
调用)并检查文件夹本身。事实证明,那个时候的文件夹已经是空的,但是当我检查它是否锁定它时,事实证明MSI本身正在持有它:
那么这里有什么问题?怎么做这个简单的任务????
答案 0 :(得分:1)
真是奇怪的问题。事实证明,我创建了一个&#34;卸载&#34;我用来卸载应用程序的快捷方式:
<Shortcut Id="startmenuUninst"
Directory="ProgramMenuDir"
Target="[SystemFolder]msiexec.exe"
Arguments="/x [ProductCode]"
Name="Uninstall $(var.ProductThis)"
WorkingDirectory='INSTALLDIR'
Advertise='no'
Description="Uninstalls $(var.ProductThis)" />
调用WorkingDirectory
进程时,问题恰好是msiexec
属性或Windows工作目录。出于某种原因,如果将其设置为要删除的文件夹(例如,在这种情况下为INSTALLDIR
)msiexec
进程将对其进行内部锁定,因此在此期间不会删除该文件夹卸载。
在我的案例中解决方案非常简单。我需要将INSTALLDIR
替换为任何其他文件夹,例如:WorkingDirectory='SystemFolder'
并自动将其删除,而不需要任何自定义操作,就像我上面显示的那样。
PS。顺便说一句,如果您使用msiexec.exe /x {Product-Code-GUID}
命令从C / C ++调用CreateProcess来卸载应用程序,请确保指定一个工作目录,该目录不是要删除的文件夹。 lpCurrentDirectory
参数。不要使用NULL
因为它可能会导致当前工作目录的歧义,如上所述。