summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2018-12-10 16:20:42 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2018-12-16 15:10:47 +0100
commit0b6884b9f1f60db48983de6c5bd53e25e1f68eeb (patch)
treed8688db48e2e2bca83d9ac3cedf0e0c9169b0a27
parent7e7e203c26f0b22973aa65f163a8590d8313250d (diff)
tdf#121987 follow-up: never fail MSU install; warn instead.
This replaces commit 53058090beede6a399e2f408f62c28a2921ff8ab. Now not only failure to start WU service, but also other errors during MSU installation won't break installation. E.g., running WU service as Guest does not prevent the service from starting; but installing updates fail, which makes previous solution incomplete. Instead, show a warning in those rare cases when an error happens, and continue. It will allow users to see the reason if they see "api-ms-win-*.dll missing" message later after installation. Of course, some small percentage of these warnings will be false, e.g. those on Windows 10. But those false messages must be really small minority, because only when (1) the installation fails (2) on a system with the component already present, such a message would be false. And it will not prevent the installation. This will not block unattended installations, since in those cases, MsiProcessMessage() will do nothing. Change-Id: I3a9e681e9d6701d092bd5c18bb4b68b4f77170f3 Reviewed-on: https://gerrit.libreoffice.org/64874 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r--instsetoo_native/inc_openoffice/windows/msi_languages/Error.ulf3
-rw-r--r--instsetoo_native/inc_openoffice/windows/msi_templates/Error.idt1
-rw-r--r--scp2/source/ooo/ucrt.scp15
-rw-r--r--setup_native/source/win32/customactions/inst_msu/inst_msu.cxx114
4 files changed, 69 insertions, 64 deletions
diff --git a/instsetoo_native/inc_openoffice/windows/msi_languages/Error.ulf b/instsetoo_native/inc_openoffice/windows/msi_languages/Error.ulf
index a14f45e0cd54..315e35fe0b33 100644
--- a/instsetoo_native/inc_openoffice/windows/msi_languages/Error.ulf
+++ b/instsetoo_native/inc_openoffice/windows/msi_languages/Error.ulf
@@ -406,4 +406,7 @@ en-US = "This setup requires Internet Information Server 4.0 or higher for confi
[OOO_ERROR_130]
en-US = "This setup requires Administrator privileges for configuring IIS Virtual Roots."
+[OOO_ERROR_131]
+en-US = "Installing a pre-requisite KB2999226 failed. You might need to manually install it from Microsoft site to be able to run the product. [2]"
+
diff --git a/instsetoo_native/inc_openoffice/windows/msi_templates/Error.idt b/instsetoo_native/inc_openoffice/windows/msi_templates/Error.idt
index 2f3a5912817d..52cc797c643e 100644
--- a/instsetoo_native/inc_openoffice/windows/msi_templates/Error.idt
+++ b/instsetoo_native/inc_openoffice/windows/msi_templates/Error.idt
@@ -131,3 +131,4 @@ i2 L0
1932 OOO_ERROR_128
1933 OOO_ERROR_129
1934 OOO_ERROR_130
+25000 OOO_ERROR_131
diff --git a/scp2/source/ooo/ucrt.scp b/scp2/source/ooo/ucrt.scp
index ae2eb27a4dbe..8cba6cfc3cd0 100644
--- a/scp2/source/ooo/ucrt.scp
+++ b/scp2/source/ooo/ucrt.scp
@@ -85,11 +85,14 @@ WindowsCustomAction gid_Customaction_cleanup_msu
Assignment1 = ("InstallExecuteSequence", "Not Installed And cleanup_msu", "inst_msu");
End
+/* The "InstMSUBinary" property contains an error message number and a binary name, separated by "|".
+ The former is used when installing the MSU fails.
+*/
WindowsCustomAction gid_Customaction_check_win7x64_ucrt
Name = "check_win7x64_ucrt";
Typ = "51";
Source = "InstMSUBinary";
- Target = "Windows61-KB2999226-x64msu";
+ Target = "25000|Windows61-KB2999226-x64msu";
Inbinarytable = 0;
Assignment1 = ("InstallExecuteSequence", "Not Installed And VersionNT = 601 And VersionNT64", "FileCost");
Styles = "NO_FILE";
@@ -99,7 +102,7 @@ WindowsCustomAction gid_Customaction_check_win8x64_ucrt
Name = "check_win8x64_ucrt";
Typ = "51";
Source = "InstMSUBinary";
- Target = "Windows8-RT-KB2999226-x64msu";
+ Target = "25000|Windows8-RT-KB2999226-x64msu";
Inbinarytable = 0;
Assignment1 = ("InstallExecuteSequence", "Not Installed And VersionNT = 602 And VersionNT64", "check_win7x64_ucrt");
Styles = "NO_FILE";
@@ -109,7 +112,7 @@ WindowsCustomAction gid_Customaction_check_win81x64_ucrt
Name = "check_win81x64_ucrt";
Typ = "51";
Source = "InstMSUBinary";
- Target = "Windows81-KB2999226-x64msu";
+ Target = "25000|Windows81-KB2999226-x64msu";
Inbinarytable = 0;
Assignment1 = ("InstallExecuteSequence", "Not Installed And VersionNT = 603 And VersionNT64", "check_win8x64_ucrt");
Styles = "NO_FILE";
@@ -125,7 +128,7 @@ WindowsCustomAction gid_Customaction_check_win7x32_ucrt
Name = "check_win7x32_ucrt";
Typ = "51";
Source = "InstMSUBinary";
- Target = "Windows61-KB2999226-x86msu";
+ Target = "25000|Windows61-KB2999226-x86msu";
Inbinarytable = 0;
Assignment1 = ("InstallExecuteSequence", "Not Installed And VersionNT = 601 And Not VersionNT64", "check_win81x64_ucrt");
Styles = "NO_FILE";
@@ -135,7 +138,7 @@ WindowsCustomAction gid_Customaction_check_win8x32_ucrt
Name = "check_win8x32_ucrt";
Typ = "51";
Source = "InstMSUBinary";
- Target = "Windows8-RT-KB2999226-x86msu";
+ Target = "25000|Windows8-RT-KB2999226-x86msu";
Inbinarytable = 0;
Assignment1 = ("InstallExecuteSequence", "Not Installed And VersionNT = 602 And Not VersionNT64", "check_win7x32_ucrt");
Styles = "NO_FILE";
@@ -145,7 +148,7 @@ WindowsCustomAction gid_Customaction_check_win81x32_ucrt
Name = "check_win81x32_ucrt";
Typ = "51";
Source = "InstMSUBinary";
- Target = "Windows81-KB2999226-x86msu";
+ Target = "25000|Windows81-KB2999226-x86msu";
Inbinarytable = 0;
Assignment1 = ("InstallExecuteSequence", "Not Installed And VersionNT = 603 And Not VersionNT64", "check_win8x32_ucrt");
Styles = "NO_FILE";
diff --git a/setup_native/source/win32/customactions/inst_msu/inst_msu.cxx b/setup_native/source/win32/customactions/inst_msu/inst_msu.cxx
index 96fb88f4b889..5df2b26431d7 100644
--- a/setup_native/source/win32/customactions/inst_msu/inst_msu.cxx
+++ b/setup_native/source/win32/customactions/inst_msu/inst_msu.cxx
@@ -120,6 +120,17 @@ template <class... StrType> void WriteLog(MSIHANDLE hInst, const StrType&... ele
WriteLogElem(hInst, hRec, sTemplate, 1, elements...);
}
+void ShowWarning(MSIHANDLE hInst, const std::wstring& sErrNo, const char* sMessage)
+{
+ PMSIHANDLE hRec = MsiCreateRecord(2);
+ // To show a message from Error table, record's Field 0 must be null
+ MsiRecordSetStringW(hRec, 1, sErrNo.c_str());
+ std::string s("\n");
+ s += sMessage;
+ MsiRecordSetStringA(hRec, 2, s.c_str());
+ MsiProcessMessage(hInst, INSTALLMESSAGE_WARNING, hRec);
+}
+
typedef std::unique_ptr<void, decltype(&CloseHandle)> CloseHandleGuard;
CloseHandleGuard Guard(HANDLE h) { return CloseHandleGuard(h, CloseHandle); }
@@ -166,16 +177,6 @@ bool IsWow64Process()
#endif
}
-// An exception class to differentiate a non-fatal exception
-class nonfatal_exception : public std::exception
-{
-public:
- nonfatal_exception(const std::exception& e)
- : std::exception(e)
- {
- }
-};
-
// Checks if Windows Update service is disabled, and if it is, enables it temporarily.
class WUServiceEnabler
{
@@ -205,37 +206,27 @@ public:
private:
static CloseServiceHandleGuard EnableWUService(MSIHANDLE hInstall)
{
- try
- {
- auto hSCM = Guard(OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS));
- if (!hSCM)
- ThrowLastError("OpenSCManagerW");
- WriteLog(hInstall, "Opened service control manager");
-
- auto hService = Guard(OpenServiceW(hSCM.get(), L"wuauserv",
- SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG
- | SERVICE_QUERY_STATUS | SERVICE_STOP));
- if (!hService)
- ThrowLastError("OpenServiceW");
- WriteLog(hInstall, "Obtained WU service handle");
-
- if (ServiceStatus(hInstall, hService.get()) == SERVICE_RUNNING
- || !EnsureServiceEnabled(hInstall, hService.get(), true))
- {
- // No need to restore anything back, since we didn't change config
- hService.reset();
- WriteLog(hInstall, "Service configuration is unchanged");
- }
-
- return hService;
- }
- catch (const std::exception& e)
+ auto hSCM = Guard(OpenSCManagerW(nullptr, nullptr, SC_MANAGER_ALL_ACCESS));
+ if (!hSCM)
+ ThrowLastError("OpenSCManagerW");
+ WriteLog(hInstall, "Opened service control manager");
+
+ auto hService = Guard(OpenServiceW(hSCM.get(), L"wuauserv",
+ SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG
+ | SERVICE_QUERY_STATUS | SERVICE_STOP));
+ if (!hService)
+ ThrowLastError("OpenServiceW");
+ WriteLog(hInstall, "Obtained WU service handle");
+
+ if (ServiceStatus(hInstall, hService.get()) == SERVICE_RUNNING
+ || !EnsureServiceEnabled(hInstall, hService.get(), true))
{
- // Allow errors opening service to be logged, but not interrupt installation.
- // They are likely to happen in situations where people hard-disable WU service,
- // and for these cases, let people deal with install logs instead of failing.
- throw nonfatal_exception(e);
+ // No need to restore anything back, since we didn't change config
+ hService.reset();
+ WriteLog(hInstall, "Service configuration is unchanged");
}
+
+ return hService;
}
// Returns if the service configuration was actually changed
@@ -354,11 +345,18 @@ extern "C" __declspec(dllexport) UINT __stdcall UnpackMSUForInstall(MSIHANDLE hI
WriteLog(hInstall, "started");
WriteLog(hInstall, "Checking value of InstMSUBinary");
- wchar_t sBinaryName[MAX_PATH + 1];
- DWORD nCCh = sizeof(sBinaryName) / sizeof(*sBinaryName);
+ wchar_t sInstMSUBinary[MAX_PATH + 10];
+ DWORD nCCh = sizeof(sInstMSUBinary) / sizeof(*sInstMSUBinary);
CheckWin32Error("MsiGetPropertyW",
- MsiGetPropertyW(hInstall, L"InstMSUBinary", sBinaryName, &nCCh));
- WriteLog(hInstall, "Got InstMSUBinary value:", sBinaryName);
+ MsiGetPropertyW(hInstall, L"InstMSUBinary", sInstMSUBinary, &nCCh));
+ WriteLog(hInstall,
+ "Got InstMSUBinary value:", sInstMSUBinary); // 123|Windows61-KB2999226-x64msu
+ const wchar_t* sBinaryName = wcschr(sInstMSUBinary, L'|');
+ if (!sBinaryName)
+ throw std::exception("No error code in InstMSUBinary!");
+ // "123" - # of the message in Error table to be shown on failure
+ const std::wstring sErrNo(sInstMSUBinary, sBinaryName - sInstMSUBinary);
+ ++sBinaryName;
PMSIHANDLE hDatabase = MsiGetActiveDatabase(hInstall);
if (!hDatabase)
@@ -415,8 +413,9 @@ extern "C" __declspec(dllexport) UINT __stdcall UnpackMSUForInstall(MSIHANDLE hI
WriteLog(hInstall, "Successfully wrote", Num2Dec(nTotal), "bytes");
}
-
- CheckWin32Error("MsiSetPropertyW", MsiSetPropertyW(hInstall, L"inst_msu", sBinary.c_str()));
+ const std::wstring s_inst_msu = sErrNo + L"|" + sBinary;
+ CheckWin32Error("MsiSetPropertyW",
+ MsiSetPropertyW(hInstall, L"inst_msu", s_inst_msu.c_str()));
// Don't delete the file: it will be done by following actions (inst_msu or cleanup_msu)
(void)aDeleteFileGuard.release();
@@ -433,17 +432,23 @@ extern "C" __declspec(dllexport) UINT __stdcall UnpackMSUForInstall(MSIHANDLE hI
// "CustomActionData" property, and runs wusa.exe to install it. Waits for it and checks exit code.
extern "C" __declspec(dllexport) UINT __stdcall InstallMSU(MSIHANDLE hInstall)
{
+ std::wstring sErrNo; // "123" - # of the message in Error table to be shown on failure
try
{
sLogPrefix = "InstallMSU:";
WriteLog(hInstall, "started");
WriteLog(hInstall, "Checking value of CustomActionData");
- wchar_t sBinaryName[MAX_PATH + 1];
- DWORD nCCh = sizeof(sBinaryName) / sizeof(*sBinaryName);
+ wchar_t sCustomActionData[MAX_PATH + 10]; // "123|C:\Temp\binary.tmp"
+ DWORD nCCh = sizeof(sCustomActionData) / sizeof(*sCustomActionData);
CheckWin32Error("MsiGetPropertyW",
- MsiGetPropertyW(hInstall, L"CustomActionData", sBinaryName, &nCCh));
- WriteLog(hInstall, "Got CustomActionData value:", sBinaryName);
+ MsiGetPropertyW(hInstall, L"CustomActionData", sCustomActionData, &nCCh));
+ WriteLog(hInstall, "Got CustomActionData value:", sCustomActionData);
+ const wchar_t* sBinaryName = wcschr(sCustomActionData, L'|');
+ if (!sBinaryName)
+ throw std::exception("No error code in CustomActionData!");
+ sErrNo = std::wstring(sCustomActionData, sBinaryName - sCustomActionData);
+ ++sBinaryName;
auto aDeleteFileGuard(Guard(sBinaryName));
// In case the Windows Update service is disabled, we temporarily enable it here
@@ -496,19 +501,12 @@ extern "C" __declspec(dllexport) UINT __stdcall InstallMSU(MSIHANDLE hInstall)
ThrowWin32Error("Execution of wusa.exe", nExitCode);
}
}
- catch (nonfatal_exception& e)
- {
- // An error that should not interrupt installation
- WriteLog(hInstall, e.what());
- WriteLog(hInstall, "Installation of MSU package failed, but installation of product will "
- "continue. You may need to install the required update manually");
- return ERROR_SUCCESS;
- }
catch (std::exception& e)
{
WriteLog(hInstall, e.what());
+ ShowWarning(hInstall, sErrNo, e.what());
}
- return ERROR_INSTALL_FAILURE;
+ return ERROR_SUCCESS; // Do not break on MSU installation errors
}
// Rollback deferred action "cleanup_msu" that is executed on error or cancel.