225 lines
5.7 KiB
C++
225 lines
5.7 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
/*
|
|
* 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 <sal/config.h>
|
|
|
|
#include <algorithm>
|
|
#include <cstddef>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <msiquery.h>
|
|
|
|
#include <pathhash.h>
|
|
|
|
// Replacements for functions used in
|
|
// workdir/UnpackedTarball/onlineupdate/onlineupdate/source/update/common/pathhash.cpp but not
|
|
// available here:
|
|
|
|
extern "C" wchar_t* _wcslwr(wchar_t* str)
|
|
{
|
|
for (auto p = str; *p != L'\0'; ++p)
|
|
{
|
|
if (*p >= L'A' && *p <= L'Z')
|
|
{
|
|
*p += L'a' - L'A';
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
|
|
extern "C" wchar_t* wcsncpy(wchar_t* strDest, wchar_t const* strSource, std::size_t count)
|
|
{
|
|
for (std::size_t i = 0; i != count; ++i)
|
|
{
|
|
strDest[i] = *strSource;
|
|
if (*strSource != L'\0')
|
|
{
|
|
++strSource;
|
|
}
|
|
}
|
|
return strDest;
|
|
}
|
|
|
|
namespace
|
|
{
|
|
bool getProperty(MSIHANDLE handle, wchar_t const* name, std::wstring* value)
|
|
{
|
|
DWORD n = 0;
|
|
if (MsiGetPropertyW(handle, name, const_cast<wchar_t*>(L""), &n) != ERROR_MORE_DATA
|
|
|| n == std::numeric_limits<DWORD>::max())
|
|
{
|
|
return false;
|
|
}
|
|
++n;
|
|
auto buf = std::make_unique<wchar_t[]>(n);
|
|
if (MsiGetPropertyW(handle, name, buf.get(), &n) != ERROR_SUCCESS)
|
|
{
|
|
return false;
|
|
}
|
|
if (n != 0 && buf[n - 1] == L'\\')
|
|
{
|
|
--n;
|
|
}
|
|
value->assign(buf.get(), n);
|
|
return true;
|
|
}
|
|
|
|
typedef std::unique_ptr<void, decltype(&CloseHandle)> CloseHandleGuard;
|
|
|
|
CloseHandleGuard guard(HANDLE handle) { return CloseHandleGuard(handle, CloseHandle); }
|
|
|
|
bool runExecutable(std::wstring const& installLocation, wchar_t const* argument)
|
|
{
|
|
std::wstring cmdline(L"\"");
|
|
cmdline += installLocation;
|
|
cmdline += L"\\program\\update_service.exe\" ";
|
|
cmdline += argument;
|
|
auto const n = cmdline.size() + 1;
|
|
auto const buf = std::make_unique<wchar_t[]>(n);
|
|
std::copy_n(cmdline.data(), n, buf.get());
|
|
STARTUPINFOW si{};
|
|
si.cb = sizeof(si);
|
|
PROCESS_INFORMATION pi{};
|
|
if (!CreateProcessW(nullptr, buf.get(), nullptr, nullptr, FALSE, CREATE_NO_WINDOW, nullptr,
|
|
nullptr, &si, &pi))
|
|
{
|
|
return false;
|
|
}
|
|
auto const g(guard(pi.hProcess));
|
|
DWORD res = WaitForSingleObject(pi.hProcess, INFINITE);
|
|
if (res != WAIT_OBJECT_0)
|
|
{
|
|
return false;
|
|
}
|
|
DWORD ec = 0;
|
|
if (!GetExitCodeProcess(pi.hProcess, &ec))
|
|
{
|
|
return false;
|
|
}
|
|
if (ec != 0)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool writeRegistry(std::wstring const& installLocation)
|
|
{
|
|
WCHAR path[MAX_PATH + 1];
|
|
if (!CalculateRegistryPathFromFilePath(installLocation.c_str(), path))
|
|
{
|
|
return false;
|
|
}
|
|
HKEY key;
|
|
if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, (std::wstring(path) + L"\\0").c_str(), 0, nullptr,
|
|
REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_WOW64_64KEY, nullptr, &key,
|
|
nullptr)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
return false;
|
|
}
|
|
auto ok = true;
|
|
if (RegSetValueExW(key, L"issuer", 0, REG_SZ,
|
|
reinterpret_cast<BYTE const*>(L"Certum Code Signing 2021 CA"),
|
|
sizeof L"Certum Code Signing 2021 CA")
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
ok = false;
|
|
}
|
|
if (RegSetValueExW(key, L"name", 0, REG_SZ,
|
|
reinterpret_cast<BYTE const*>(L"The Document Foundation"),
|
|
sizeof L"The Document Foundation")
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
ok = false;
|
|
}
|
|
if (RegCloseKey(key) != ERROR_SUCCESS)
|
|
{
|
|
ok = false;
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool deleteRegistry(std::wstring const& installLocation)
|
|
{
|
|
WCHAR path[MAX_PATH + 1];
|
|
if (!CalculateRegistryPathFromFilePath(installLocation.c_str(), path))
|
|
{
|
|
return false;
|
|
}
|
|
if (RegDeleteTreeW(HKEY_LOCAL_MACHINE, path) != ERROR_SUCCESS)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) UINT __stdcall PrepareUpdateservice(MSIHANDLE handle)
|
|
{
|
|
std::wstring loc;
|
|
if (!getProperty(handle, L"INSTALLLOCATION", &loc))
|
|
{
|
|
return ERROR_INSTALL_FAILURE;
|
|
}
|
|
auto ok = true;
|
|
if (MsiSetPropertyW(handle, L"install_updateservice", loc.c_str()) != ERROR_SUCCESS)
|
|
{
|
|
ok = false;
|
|
}
|
|
if (MsiSetPropertyW(handle, L"uninstall_updateservice", loc.c_str()) != ERROR_SUCCESS)
|
|
{
|
|
ok = false;
|
|
}
|
|
return ok ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) UINT __stdcall InstallUpdateservice(MSIHANDLE handle)
|
|
{
|
|
std::wstring loc;
|
|
if (!getProperty(handle, L"CustomActionData", &loc))
|
|
{
|
|
return ERROR_INSTALL_FAILURE;
|
|
}
|
|
auto ok = true;
|
|
if (!runExecutable(loc, L"install"))
|
|
{
|
|
ok = false;
|
|
}
|
|
if (!writeRegistry(loc))
|
|
{
|
|
ok = false;
|
|
}
|
|
return ok ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
|
}
|
|
|
|
extern "C" __declspec(dllexport) UINT __stdcall UninstallUpdateservice(MSIHANDLE handle)
|
|
{
|
|
std::wstring loc;
|
|
if (!getProperty(handle, L"CustomActionData", &loc))
|
|
{
|
|
return ERROR_INSTALL_FAILURE;
|
|
}
|
|
auto ok = true;
|
|
if (!runExecutable(loc, L"uninstall"))
|
|
{
|
|
ok = false;
|
|
}
|
|
if (!deleteRegistry(loc))
|
|
{
|
|
ok = false;
|
|
}
|
|
return ok ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|