这就是我最终如何做到的。我正在调用排队的自定义操作RemoveExistingProducts
:
<Property Id='ERRORIFFILESFOUND_MESSAGE'>!(loc.OlderVersionNotRemoved)</Property>
<CustomAction Id="CA.ErrorIfFilesFound"
BinaryKey="SetupSupport.dll" DllEntry="ErrorIfFilesFound"
Execute="immediate" Return="check" />
<CustomAction Id='CA.ErrorIfFilesFound.SetDirectory'
Property='ERRORIFFILESFOUND_DIRECTORY' Value='[INSTALLDIR]' />
<InstallExecuteSequence>
<Custom Action='CA.ErrorIfFilesFound.SetDirectory' After='RemoveExistingProducts' />
<Custom Action='CA.ErrorIfFilesFound' After='CA.ErrorIfFilesFound.SetDirectory'>
Not MAJORUPGRADEPROPERTY and Not Installed
</Custom>
</InstallExecuteSequence>
在此之后,如果可能的话,旧的安装会被删除,所以如果目标文件夹中还有文件,那么就有问题了。这一刻发生得相当晚,但我不知道有一种方法可以检测是否要卸载现有文件。自定义操作中的代码仅检查目标文件夹是否存在且不为空,如果存在则调用它退出(ExitOnFailure
为简洁起见,删除了错误处理):
UINT WINAPI ErrorIfFilesFound(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
LPWSTR pwszDirectory = NULL;
LPWSTR pwszMessage = NULL;
hr = ::WcaInitialize(hInstall, "ErrorIfFindFile");
hr = ::WcaGetProperty(L"ERRORIFFILESFOUND_DIRECTORY", &pwszDirectory);
if (PathIsDirectory(pwszDirectory) && !PathIsDirectoryEmpty(pwszDirectory))
{
hr = ::WcaGetProperty(L"ERRORIFFILESFOUND_MESSAGE", &pwszMessage);
ProcessInstallMessage(hInstall,
INSTALLMESSAGE_ERROR, pwszMessage, pwszDirectory);
hr = -1;
}
LExit:
ReleaseStr(pwszMessage);
ReleaseStr(pwszDirectory);
UINT err = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return ::WcaFinalize(err);
}
void ProcessInstallMessage(MSIHANDLE hInstall,
INSTALLMESSAGE type, TCHAR* lpszMessage, TCHAR* lpszParam)
{
UINT rc;
MSIHANDLE hMsg;
UINT uiFieldNumber = lpszParam == NULL ? 0 : 1;
hMsg = MsiCreateRecord(uiFieldNumber);
if (hMsg != 0)
{
if ((rc = MsiRecordSetString(hMsg, 0, lpszMessage)) != ERROR_SUCCESS)
{}
else if (lpszParam != NULL &&
(rc = MsiRecordSetString(hMsg, 1, lpszParam)) != ERROR_SUCCESS)
{}
else
{
rc = MsiProcessMessage(hInstall, type, hMsg);
}
rc = MsiCloseHandle(hMsg);
}
}