    /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     */

    #include <memory>
    #include <string>
    #include <sstream>
    #include <iomanip>

    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
    #include <Shlobj.h>
    #include <Wuerror.h>
    #include <msiquery.h>

    namespace
    {
    template <typename IntType> std::string Num2Hex(IntType n)
    {
        std::stringstream sMsg;
        sMsg << "0x" << std::uppercase << std::setfill('0') << std::setw(sizeof(n) * 2) << std::hex
             << n;
        return sMsg.str();
    }

    template <typename IntType> std::string Num2Dec(IntType n)
    {
        std::stringstream sMsg;
        sMsg << n;
        return sMsg.str();
    }

    void ThrowHResult(const char* sFunc, HRESULT hr)
    {
        std::stringstream sMsg;
        sMsg << sFunc << " failed (HRESULT = " << Num2Hex(hr) << ")!";

        throw std::exception(sMsg.str().c_str());
    }

    void CheckHResult(const char* sFunc, HRESULT hr)
    {
        if (FAILED(hr))
            ThrowHResult(sFunc, hr);
    }

    void ThrowWin32Error(const char* sFunc, DWORD nWin32Error)
    {
        std::stringstream sMsg;
        sMsg << sFunc << " failed with Win32 error code " << Num2Hex(nWin32Error) << "!";

        throw std::exception(sMsg.str().c_str());
    }

    void ThrowLastError(const char* sFunc) { ThrowWin32Error(sFunc, GetLastError()); }

    void CheckWin32Error(const char* sFunc, DWORD nWin32Error)
    {
        if (nWin32Error != ERROR_SUCCESS)
            ThrowWin32Error(sFunc, nWin32Error);
    }

    std::wstring GetKnownFolder(const KNOWNFOLDERID& rfid)
    {
        PWSTR sPath = nullptr;
        HRESULT hr = SHGetKnownFolderPath(rfid, KF_FLAG_DEFAULT, nullptr, &sPath);
        CheckHResult("SHGetKnownFolderPath", hr);
        std::wstring sResult(sPath);
        CoTaskMemFree(sPath);
        return sResult;
    }

    void WriteLogElem(MSIHANDLE hInst, MSIHANDLE hRecord, std::ostringstream& sTmpl, UINT)
    {
        MsiRecordSetStringA(hRecord, 0, sTmpl.str().c_str());
        MsiProcessMessage(hInst, INSTALLMESSAGE_INFO, hRecord);
    }

    void RecSetString(MSIHANDLE hRec, UINT nField, LPCSTR sVal)
    {
        MsiRecordSetStringA(hRec, nField, sVal);
    }

    void RecSetString(MSIHANDLE hRec, UINT nField, LPCWSTR sVal)
    {
        MsiRecordSetStringW(hRec, nField, sVal);
    }

    template <class Ch, class... SOther>
    void WriteLogElem(MSIHANDLE hInst, MSIHANDLE hRec, std::ostringstream& sTmpl, UINT nField,
                      const Ch* elem, const SOther&... others)
    {
        sTmpl << " [" << nField << "]";
        RecSetString(hRec, nField, elem);
        WriteLogElem(hInst, hRec, sTmpl, nField + 1, others...);
    }

    template <class S1, class... SOther>
    void WriteLogElem(MSIHANDLE hInst, MSIHANDLE hRec, std::ostringstream& sTmpl, UINT nField,
                      const S1& elem, const SOther&... others)
    {
        WriteLogElem(hInst, hRec, sTmpl, nField, elem.c_str(), others...);
    }

    static std::string sLogPrefix;

    template <class... StrType> void WriteLog(MSIHANDLE hInst, const StrType&... elements)
    {
        PMSIHANDLE hRec = MsiCreateRecord(sizeof...(elements));
        if (!hRec)
            return;

        std::ostringstream sTemplate;
        sTemplate << sLogPrefix;
        WriteLogElem(hInst, hRec, sTemplate, 1, elements...);
    }

    typedef std::unique_ptr<void, decltype(&CloseHandle)> CloseHandleGuard;
    CloseHandleGuard Guard(HANDLE h) { return CloseHandleGuard(h, CloseHandle); }

    typedef std::unique_ptr<const wchar_t, decltype(&DeleteFileW)> DeleteFileGuard;
    DeleteFileGuard Guard(const wchar_t* sFileName) { return DeleteFileGuard(sFileName, DeleteFileW); }

    typedef std::unique_ptr<SC_HANDLE__, decltype(&CloseServiceHandle)> CloseServiceHandleGuard;
    CloseServiceHandleGuard Guard(SC_HANDLE h)
    {
        return CloseServiceHandleGuard(h, CloseServiceHandle);
    }

    std::wstring GetTempFile()
    {
        wchar_t sPath[MAX_PATH + 1];
        DWORD nResult = GetTempPathW(sizeof(sPath) / sizeof(*sPath), sPath);
        if (!nResult)
            ThrowLastError("GetTempPathW");

        wchar_t sFile[MAX_PATH + 1];
        nResult = GetTempFileNameW(sPath, L"TMP", 0, sFile);
        if (!nResult)
            ThrowLastError("GetTempFileNameW");
        return sFile;
    }

    bool IsWow64Process()
    {
    #if !defined _WIN64
        BOOL bResult = FALSE;
        typedef BOOL(WINAPI * LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
        LPFN_ISWOW64PROCESS fnIsWow64Process = reinterpret_cast<LPFN_ISWOW64PROCESS>(
            GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process"));

        if (fnIsWow64Process)
        {
            if (!fnIsWow64Process(GetCurrentProcess(), &bResult))
                ThrowLastError("IsWow64Process");
        }

        return bResult;
    #else
        return false;
    #endif
    }

    // Checks if Windows Update service is disabled, and if it is, enables it temporarily.
    class WUServiceEnabler
    {
    public:
        WUServiceEnabler(MSIHANDLE hInstall)
            : mhInstall(hInstall)
            , mhService(EnableWUService(hInstall))
        {
        }

        ~WUServiceEnabler()
        {
            try
            {
                if (mhService)
                {
                    EnsureServiceEnabled(mhInstall, mhService.get(), false);
                    StopService(mhInstall, mhService.get());
                }
            }
            catch (std::exception& e)
            {
                WriteLog(mhInstall, e.what());
            }
        }

    private:
        static CloseServiceHandleGuard EnableWUService(MSIHANDLE hInstall)
        {
            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;
        }

        // Returns if the service configuration was actually changed
        static bool EnsureServiceEnabled(MSIHANDLE hInstall, SC_HANDLE hService, bool bEnabled)
        {
            bool bConfigChanged = false;

            DWORD nCbRequired = 0;
            if (!QueryServiceConfigW(hService, nullptr, 0, &nCbRequired))
            {
                DWORD nError = GetLastError();
                if (nError != ERROR_INSUFFICIENT_BUFFER)
                    ThrowLastError("QueryServiceConfigW");
            }
            std::unique_ptr<char[]> pBuf(new char[nCbRequired]);
            LPQUERY_SERVICE_CONFIGW pConfig = reinterpret_cast<LPQUERY_SERVICE_CONFIGW>(pBuf.get());
            if (!QueryServiceConfigW(hService, pConfig, nCbRequired, &nCbRequired))
                ThrowLastError("QueryServiceConfigW");
            WriteLog(hInstall, "Obtained service config");

            DWORD eNewStartType = 0;
            if (bEnabled && pConfig->dwStartType == SERVICE_DISABLED)
            {
                bConfigChanged = true;
                eNewStartType = SERVICE_DEMAND_START;
                WriteLog(hInstall, "Service is disabled, and requested to enable");
            }
            else if (!bEnabled && pConfig->dwStartType != SERVICE_DISABLED)
            {
                bConfigChanged = true;
                eNewStartType = SERVICE_DISABLED;
                WriteLog(hInstall, "Service is enabled, and requested to disable");
            }

            if (bConfigChanged)
            {
                if (!ChangeServiceConfigW(hService, SERVICE_NO_CHANGE, eNewStartType, SERVICE_NO_CHANGE,
                                          nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
                                          nullptr))
                    ThrowLastError("ChangeServiceConfigW");
                WriteLog(hInstall, "WU service config successfully changed");
            }
            else
                WriteLog(hInstall, "No need to modify service config");

            return bConfigChanged;
        }

        static DWORD ServiceStatus(MSIHANDLE hInstall, SC_HANDLE hService)
        {
            SERVICE_STATUS aServiceStatus{};
            if (!QueryServiceStatus(hService, &aServiceStatus))
                ThrowLastError("QueryServiceStatus");

            std::string sStatus;
            switch (aServiceStatus.dwCurrentState)
            {
                case SERVICE_STOPPED:
                    sStatus = "SERVICE_STOPPED";
                    break;
                case SERVICE_START_PENDING:
                    sStatus = "SERVICE_START_PENDING";
                    break;
                case SERVICE_STOP_PENDING:
                    sStatus = "SERVICE_STOP_PENDING";
                    break;
                case SERVICE_RUNNING:
                    sStatus = "SERVICE_RUNNING";
                    break;
                case SERVICE_CONTINUE_PENDING:
                    sStatus = "SERVICE_CONTINUE_PENDING";
                    break;
                case SERVICE_PAUSE_PENDING:
                    sStatus = "SERVICE_PAUSE_PENDING";
                    break;
                case SERVICE_PAUSED:
                    sStatus = "SERVICE_PAUSED";
                    break;
                default:
                    sStatus = Num2Hex(aServiceStatus.dwCurrentState);
            }
            WriteLog(hInstall, "Service status is", sStatus);

            return aServiceStatus.dwCurrentState;
        }

        static void StopService(MSIHANDLE hInstall, SC_HANDLE hService)
        {
            if (ServiceStatus(hInstall, hService) != SERVICE_STOPPED)
            {
                SERVICE_STATUS aServiceStatus{};
                if (!ControlService(hService, SERVICE_CONTROL_STOP, &aServiceStatus))
                    ThrowLastError("ControlService");
                WriteLog(hInstall,
                         "Successfully sent SERVICE_CONTROL_STOP code to Windows Update service");
                // No need to wait for the service stopped
            }
            else
                WriteLog(hInstall, "Windows Update service is not running");
        }

        MSIHANDLE mhInstall;
        CloseServiceHandleGuard mhService;
    };
    }

    // Immediate action "unpack_msu" that has access to installation database and properties; checks
    // "InstMSUBinary" property and unpacks the binary with that name to a temporary file; sets
    // "cleanup_msu" and "inst_msu" properties to the full name of the extracted temporary file. These
    // properties will become "CustomActionData" property inside relevant deferred actions.
    extern "C" UINT __stdcall UnpackMSUForInstall(MSIHANDLE hInstall)
    {
        try
        {
            sLogPrefix = "UnpackMSUForInstall:";
            WriteLog(hInstall, "started");

            WriteLog(hInstall, "Checking value of InstMSUBinary");
            wchar_t sBinaryName[MAX_PATH + 1];
            DWORD nCCh = sizeof(sBinaryName) / sizeof(*sBinaryName);
            CheckWin32Error("MsiGetPropertyW",
                            MsiGetPropertyW(hInstall, L"InstMSUBinary", sBinaryName, &nCCh));
            WriteLog(hInstall, "Got InstMSUBinary value:", sBinaryName);

            PMSIHANDLE hDatabase = MsiGetActiveDatabase(hInstall);
            if (!hDatabase)
                ThrowLastError("MsiGetActiveDatabase");
            WriteLog(hInstall, "MsiGetActiveDatabase succeeded");

            std::wstringstream sQuery;
            sQuery << "SELECT `Data` FROM `Binary` WHERE `Name`='" << sBinaryName << "'";

            PMSIHANDLE hBinaryView;
            CheckWin32Error("MsiDatabaseOpenViewW",
                            MsiDatabaseOpenViewW(hDatabase, sQuery.str().c_str(), &hBinaryView));
            WriteLog(hInstall, "MsiDatabaseOpenViewW succeeded");

            CheckWin32Error("MsiViewExecute", MsiViewExecute(hBinaryView, 0));
            WriteLog(hInstall, "MsiViewExecute succeeded");

            PMSIHANDLE hBinaryRecord;
            CheckWin32Error("MsiViewFetch", MsiViewFetch(hBinaryView, &hBinaryRecord));
            WriteLog(hInstall, "MsiViewFetch succeeded");

            const std::wstring sBinary = GetTempFile();
            auto aDeleteFileGuard(Guard(sBinary.c_str()));
            WriteLog(hInstall, "Temp file path:", sBinary.c_str());

            CheckWin32Error("MsiSetPropertyW",
                            MsiSetPropertyW(hInstall, L"cleanup_msu", sBinary.c_str()));

            {
                HANDLE hFile = CreateFileW(sBinary.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
                                           FILE_ATTRIBUTE_NORMAL, nullptr);
                if (hFile == INVALID_HANDLE_VALUE)
                    ThrowLastError("CreateFileW");
                auto aFileHandleGuard(Guard(hFile));

                const DWORD nBufSize = 1024 * 1024;
                std::unique_ptr<char[]> buf(new char[nBufSize]);
                DWORD nTotal = 0;
                DWORD nRead;
                do
                {
                    nRead = nBufSize;
                    CheckWin32Error("MsiRecordReadStream",
                                    MsiRecordReadStream(hBinaryRecord, 1, buf.get(), &nRead));

                    if (nRead > 0)
                    {
                        DWORD nWritten;
                        if (!WriteFile(hFile, buf.get(), nRead, &nWritten, nullptr))
                            ThrowLastError("WriteFile");
                        nTotal += nWritten;
                    }
                } while (nRead == nBufSize);

                WriteLog(hInstall, "Successfully wrote", Num2Dec(nTotal), "bytes");
            }

            CheckWin32Error("MsiSetPropertyW", MsiSetPropertyW(hInstall, L"inst_msu", sBinary.c_str()));

            // Don't delete the file: it will be done by following actions (inst_msu or cleanup_msu)
            aDeleteFileGuard.release();
            return ERROR_SUCCESS;
        }
        catch (std::exception& e)
        {
            WriteLog(hInstall, e.what());
        }
        return ERROR_INSTALL_FAILURE;
    }

    // Deferred action "inst_msu" that must be run from system account. Receives the tempfile name from
    // "CustomActionData" property, and runs wusa.exe to install it. Waits for it and checks exit code.
    extern "C" UINT __stdcall InstallMSU(MSIHANDLE hInstall)
    {
        try
        {
            sLogPrefix = "InstallMSU:";
            WriteLog(hInstall, "started");

            WriteLog(hInstall, "Checking value of CustomActionData");
            wchar_t sBinaryName[MAX_PATH + 1];
            DWORD nCCh = sizeof(sBinaryName) / sizeof(*sBinaryName);
            CheckWin32Error("MsiGetPropertyW",
                            MsiGetPropertyW(hInstall, L"CustomActionData", sBinaryName, &nCCh));
            WriteLog(hInstall, "Got CustomActionData value:", sBinaryName);
            auto aDeleteFileGuard(Guard(sBinaryName));

            // In case the Windows Update service is disabled, we temporarily enable it here
            WUServiceEnabler aWUServiceEnabler(hInstall);

            const bool bWow64Process = IsWow64Process();
            WriteLog(hInstall, "Is Wow64 Process:", bWow64Process ? "YES" : "NO");
            std::wstring sWUSAPath = bWow64Process ? GetKnownFolder(FOLDERID_Windows) + L"\\SysNative"
                                                   : GetKnownFolder(FOLDERID_System);
            sWUSAPath += L"\\wusa.exe";
            WriteLog(hInstall, "Prepared wusa path:", sWUSAPath);

            std::wstring sWUSACmd
                = L"\"" + sWUSAPath + L"\" \"" + sBinaryName + L"\" /quiet /norestart";
            WriteLog(hInstall, "Prepared wusa command:", sWUSACmd);

            STARTUPINFOW si{};
            si.cb = sizeof(si);
            PROCESS_INFORMATION pi{};
            if (!CreateProcessW(sWUSAPath.c_str(), const_cast<LPWSTR>(sWUSACmd.c_str()), nullptr,
                                nullptr, FALSE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi))
                ThrowLastError("CreateProcessW");
            auto aCloseProcHandleGuard(Guard(pi.hProcess));
            WriteLog(hInstall, "CreateProcessW succeeded");

            DWORD nWaitResult = WaitForSingleObject(pi.hProcess, INFINITE);
            if (nWaitResult != WAIT_OBJECT_0)
                ThrowWin32Error("WaitForSingleObject", nWaitResult);

            DWORD nExitCode = 0;
            if (!GetExitCodeProcess(pi.hProcess, &nExitCode))
                ThrowLastError("GetExitCodeProcess");

            HRESULT hr = static_cast<HRESULT>(nExitCode);
            if (hr == HRESULT_FROM_WIN32(ERROR_SUCCESS_REBOOT_REQUIRED))
                hr = WU_S_REBOOT_REQUIRED;

            switch (hr)
            {
                case S_OK:
                case S_FALSE:
                case WU_S_ALREADY_INSTALLED:
                case WU_E_NOT_APPLICABLE: // Windows could lie us about its version, etc.
                case ERROR_SUCCESS_REBOOT_REQUIRED:
                case WU_S_REBOOT_REQUIRED:
                    WriteLog(hInstall, "wusa.exe succeeded with exit code", Num2Hex(nExitCode));
                    return ERROR_SUCCESS;

                default:
                    ThrowWin32Error("Execution of wusa.exe", nExitCode);
            }
        }
        catch (std::exception& e)
        {
            WriteLog(hInstall, e.what());
        }
        return ERROR_INSTALL_FAILURE;
    }

    // Rollback deferred action "cleanup_msu" that is executed on error or cancel.
    // It removes the temporary file created by UnpackMSUForInstall action.
    // MUST be placed IMMEDIATELY AFTER "unpack_msu" in execute sequence.
    extern "C" UINT __stdcall CleanupMSU(MSIHANDLE hInstall)
    {
        try
        {
            sLogPrefix = "CleanupMSU:";
            WriteLog(hInstall, "started");

            WriteLog(hInstall, "Checking value of CustomActionData");
            wchar_t sBinaryName[MAX_PATH + 1];
            DWORD nCCh = sizeof(sBinaryName) / sizeof(*sBinaryName);
            CheckWin32Error("MsiGetPropertyW",
                            MsiGetPropertyW(hInstall, L"CustomActionData", sBinaryName, &nCCh));
            WriteLog(hInstall, "Got CustomActionData value:", sBinaryName);

            if (!DeleteFileW(sBinaryName))
                ThrowLastError("DeleteFileW");
            WriteLog(hInstall, "File successfully removed");
        }
        catch (std::exception& e)
        {
            WriteLog(hInstall, e.what());
        }
        // Always return success - we don't want rollback to fail.
        return ERROR_SUCCESS;
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V530 The return value of function 'release' is required to be utilized.