Kaydet (Commit) 7f0ef81c authored tarafından Mike Kaganski's avatar Mike Kaganski Kaydeden (comit) Aron Budea

Register spsupp*.dll during installation

This registers SharePoint integration libraries using regsvr.exe.
Both 32-bit and 64-bit libraries are registered; registration of
SharePoint.OpenDocuments is unconditional (subject to ActiveX
feature install state), substituting respective MSO component.

This only works for 32-bit MSI, because in case of 64-bit MSI, only
64-bit SharePoint DLL is included; this makes the library ~useless
in case of 64-bit MSI, because IE needs 32-bit component absent there.
Proper solution will be created for master branch.

Change-Id: Ic5bf9e7090acfaa17d47cb72b9ebfd483242f656
Reviewed-on: https://gerrit.libreoffice.org/72801Reviewed-by: 's avatarAron Budea <aron.budea@collabora.com>
Tested-by: 's avatarAron Budea <aron.budea@collabora.com>
üst 17fdf034
...@@ -668,6 +668,7 @@ $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_OOO,ooobinaryta ...@@ -668,6 +668,7 @@ $(eval $(call gb_Helper_register_libraries_for_install,PLAINLIBS_OOO,ooobinaryta
instooofiltmsi \ instooofiltmsi \
inst_msu_msi \ inst_msu_msi \
qslnkmsi \ qslnkmsi \
reg_dlls \
reg4allmsdoc \ reg4allmsdoc \
sdqsmsi \ sdqsmsi \
sellangmsi \ sellangmsi \
......
...@@ -74,7 +74,7 @@ Module gid_Module_Prg_Calc_MSO_Reg ...@@ -74,7 +74,7 @@ Module gid_Module_Prg_Calc_MSO_Reg
Name = "gid_Module_Prg_Calc_MSO_Reg"; Name = "gid_Module_Prg_Calc_MSO_Reg";
Description = "gid_Module_Prg_Calc_MSO_Reg"; Description = "gid_Module_Prg_Calc_MSO_Reg";
Styles = (HIDDEN_ROOT); Styles = (HIDDEN_ROOT);
Default = YES; Default = NO;
End End
Module gid_Module_Prg_Calc_Other_Reg Module gid_Module_Prg_Calc_Other_Reg
......
...@@ -64,7 +64,7 @@ Module gid_Module_Prg_Draw_MSO_Reg ...@@ -64,7 +64,7 @@ Module gid_Module_Prg_Draw_MSO_Reg
Name = "gid_Module_Prg_Draw_MSO_Reg"; Name = "gid_Module_Prg_Draw_MSO_Reg";
Description = "gid_Module_Prg_Draw_MSO_Reg"; Description = "gid_Module_Prg_Draw_MSO_Reg";
Styles = (HIDDEN_ROOT); Styles = (HIDDEN_ROOT);
Default = YES; Default = NO;
End End
Module gid_Module_Prg_Draw_Other_Reg Module gid_Module_Prg_Draw_Other_Reg
......
...@@ -66,7 +66,7 @@ Module gid_Module_Prg_Impress_MSO_Reg ...@@ -66,7 +66,7 @@ Module gid_Module_Prg_Impress_MSO_Reg
Name = "gid_Module_Prg_Impress_MSO_Reg"; Name = "gid_Module_Prg_Impress_MSO_Reg";
Description = "gid_Module_Prg_Impress_MSO_Reg"; Description = "gid_Module_Prg_Impress_MSO_Reg";
Styles = (HIDDEN_ROOT); Styles = (HIDDEN_ROOT);
Default = YES; Default = NO;
End End
Module gid_Module_Prg_Impress_Other_Reg Module gid_Module_Prg_Impress_Other_Reg
......
...@@ -221,3 +221,44 @@ WindowsCustomAction gid_Customaction_RegisterSomeExtensions ...@@ -221,3 +221,44 @@ WindowsCustomAction gid_Customaction_RegisterSomeExtensions
End End
#endif /* HAVE_WINDOWS_SDK */ #endif /* HAVE_WINDOWS_SDK */
/* Deferred not-impersonated actions that will call regsvr32 to (un)register DLLs.
Custom action type 1 (msidbCustomActionTypeDll + msidbCustomActionTypeBinaryData)
+ 64 (msidbCustomActionTypeContinue) + 1024 (msidbCustomActionTypeInScript)
+ 2048 (msidbCustomActionTypeNoImpersonate).
Since deferred actions don't have access to current DB, the actions depend on
immediate-executed action prep_reg_unreg_dlls (see below) that precedes it, and
sets this action's CustomActionData property.
*/
WindowsCustomAction gid_Customaction_reg_dlls
Name = "reg_dlls";
Typ = "3137";
Source = "reg_dlls.dll";
Target = "RegDLLs";
Inbinarytable = 1;
Assignment1 = ("InstallExecuteSequence", "reg_dlls", "InstallFinalize");
End
WindowsCustomAction gid_Customaction_unreg_dlls
Name = "unreg_dlls";
Typ = "3137";
Source = "reg_dlls.dll";
Target = "UnregDLLs";
Inbinarytable = 1;
Assignment1 = ("InstallExecuteSequence", "unreg_dlls", "UnpublishComponents");
End
/* Immediately-executed action that adds registration command lines for spsupp[_x64].dll
to "[un]reg_dlls" properties.
Custom action type 1 (msidbCustomActionTypeDll + msidbCustomActionTypeBinaryData)
+ 64 (msidbCustomActionTypeContinue).
*/
WindowsCustomAction gid_Customaction_prep_reg_dlls
Name = "prep_reg_unreg_dlls";
Typ = "65";
Source = "reg_dlls.dll";
Target = "PrepRegUnregDLLs";
Inbinarytable = 1;
Assignment1 = ("InstallExecuteSequence", "", "behind_CostFinalize");
End
...@@ -65,7 +65,7 @@ Module gid_Module_Prg_Wrt_MSO_Reg ...@@ -65,7 +65,7 @@ Module gid_Module_Prg_Wrt_MSO_Reg
Name = "gid_Module_Prg_Wrt_MSO_Reg"; Name = "gid_Module_Prg_Wrt_MSO_Reg";
Description = "gid_Module_Prg_Wrt_MSO_Reg"; Description = "gid_Module_Prg_Wrt_MSO_Reg";
Styles = (HIDDEN_ROOT); Styles = (HIDDEN_ROOT);
Default = YES; Default = NO;
End End
Module gid_Module_Prg_Wrt_Other_Reg Module gid_Module_Prg_Wrt_Other_Reg
......
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# 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/.
#
$(eval $(call gb_Library_Library,reg_dlls))
$(eval $(call gb_Library_add_defs,reg_dlls,\
-U_DLL \
))
$(eval $(call gb_Library_add_cxxflags,reg_dlls,\
$(if $(MSVC_USE_DEBUG_RUNTIME),/MTd,/MT) \
))
$(eval $(call gb_Library_add_ldflags,reg_dlls,\
/DEF:$(SRCDIR)/setup_native/source/win32/customactions/reg_dlls/reg_dlls.def \
/NODEFAULTLIB \
))
$(eval $(call gb_Library_add_exception_objects,reg_dlls,\
setup_native/source/win32/customactions/reg_dlls/reg_dlls \
))
$(eval $(call gb_Library_use_system_win32_libs,reg_dlls,\
libcmt \
libcpmt \
libucrt \
libvcruntime \
kernel32 \
Ole32 \
Shell32 \
Msi \
))
# vim: set noet sw=4 ts=4:
...@@ -26,6 +26,7 @@ $(eval $(call gb_Module_add_targets,setup_native,\ ...@@ -26,6 +26,7 @@ $(eval $(call gb_Module_add_targets,setup_native,\
Library_instooofiltmsi \ Library_instooofiltmsi \
Library_inst_msu_msi \ Library_inst_msu_msi \
Library_qslnkmsi \ Library_qslnkmsi \
Library_reg_dlls \
Library_reg4allmsdoc \ Library_reg4allmsdoc \
Library_regactivex \ Library_regactivex \
Library_sdqsmsi \ Library_sdqsmsi \
......
/* -*- 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 <iomanip>
#include <memory>
#include <string>
#include <sstream>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Shlobj.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();
}
std::string Win32ErrorMessage(const char* sFunc, DWORD nWin32Error)
{
std::stringstream sMsg;
sMsg << sFunc << " failed with Win32 error code " << Num2Hex(nWin32Error) << "!";
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)
{
throw std::exception(Win32ErrorMessage(sFunc, nWin32Error).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...);
}
std::wstring MsiGetPropertyW(MSIHANDLE hInst, LPCWSTR szName)
{
std::wstring sResult;
DWORD nSz = 0;
UINT nRet = ::MsiGetPropertyW(hInst, szName, L"", &nSz);
if (nRet == ERROR_MORE_DATA)
{
++nSz;
auto buf = std::make_unique<wchar_t[]>(nSz);
CheckWin32Error("MsiGetPropertyW", ::MsiGetPropertyW(hInst, szName, buf.get(), &nSz));
sResult = buf.get();
WriteLog(hInst, "Property", szName, "=", sResult);
}
else
CheckWin32Error("MsiGetPropertyW", nRet);
return sResult;
}
typedef std::unique_ptr<void, decltype(&CloseHandle)> CloseHandleGuard;
CloseHandleGuard Guard(HANDLE h) { return CloseHandleGuard(h, CloseHandle); }
void RegDLL(MSIHANDLE hInst, const std::wstring& sArgs, bool bUnreg)
{
static std::wstring sRegSvr32 = GetKnownFolder(FOLDERID_System) + L"\\regsvr32.exe";
try
{
std::wstring sCmd = L"\"" + sRegSvr32 + L"\" /s ";
if (bUnreg)
sCmd += L"/u ";
sCmd += sArgs;
WriteLog(hInst, "Prepared regsvr32 command:", sCmd);
STARTUPINFOW si{ sizeof(si) };
PROCESS_INFORMATION pi{};
if (!CreateProcessW(sRegSvr32.c_str(), const_cast<LPWSTR>(sCmd.c_str()), nullptr, nullptr,
FALSE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi))
ThrowLastError("CreateProcessW");
auto aCloseProcHandleGuard(Guard(pi.hProcess));
WriteLog(hInst, "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");
WriteLog(hInst, "regsvr32 returned:", Num2Dec(nExitCode));
}
catch (std::exception& e)
{
WriteLog(hInst, e.what());
}
}
void ProcessCustomActionData(MSIHANDLE hInst, bool bUnreg)
{
WriteLog(hInst, "Checking value of CustomActionData");
std::wstring sCustomActionData = MsiGetPropertyW(hInst, L"CustomActionData");
WriteLog(hInst, "Got CustomActionData value:", sCustomActionData);
std::wstringstream ss(sCustomActionData);
std::wstring sToken;
while (std::getline(ss, sToken, L'|'))
{
if (!sToken.empty())
{
RegDLL(hInst, sToken, bUnreg);
}
}
}
} // namespace
// Deferred action "reg_dlls" that must be run from system account. Receives a list of regsvr32
// arguments: DLLs which need registering, and possibly /i argument with its parameter.
extern "C" __declspec(dllexport) UINT __stdcall RegDLLs(MSIHANDLE hInstall)
{
sLogPrefix = "RegDLLs:";
WriteLog(hInstall, "started");
ProcessCustomActionData(hInstall, false);
return ERROR_SUCCESS;
}
// Deferred action "unreg_dlls" that must be run from system account. Receives a list of regsvr32
// arguments: DLLs which need registering, and possibly /i argument with its parameter.
extern "C" __declspec(dllexport) UINT __stdcall UnregDLLs(MSIHANDLE hInstall)
{
sLogPrefix = "UnregDLLs:";
WriteLog(hInstall, "started");
ProcessCustomActionData(hInstall, true);
return ERROR_SUCCESS;
}
// Immediate action "prep_reg_unreg_dlls". Checks states of the features to prepare custom action data
// for reg_dlls and unreg_dlls deferred actions.
extern "C" __declspec(dllexport) UINT __stdcall PrepRegUnregDLLs(MSIHANDLE hInstall)
{
sLogPrefix = "PrepRegUnregDLLs:";
WriteLog(hInstall, "started");
try
{
INSTALLSTATE current_state;
INSTALLSTATE future_state;
CheckWin32Error("MsiGetFeatureStateW", MsiGetFeatureStateW(hInstall, L"gm_o_Activexcontrol",
&current_state, &future_state));
const bool bRegActiveX
= future_state == INSTALLSTATE_LOCAL
|| (current_state == INSTALLSTATE_LOCAL && (future_state == INSTALLSTATE_UNKNOWN
|| future_state == INSTALLSTATE_DEFAULT));
const bool bUnregActiveX = current_state == INSTALLSTATE_LOCAL
&& future_state != INSTALLSTATE_UNKNOWN
&& future_state != INSTALLSTATE_LOCAL
&& future_state != INSTALLSTATE_DEFAULT;
if (!bRegActiveX && !bUnregActiveX)
return ERROR_SUCCESS;
// For now, do that unconditionally; TODO: move the component to own feature
std::wstring sRegData = L"/i:Substitute_OWSSUPP \"[#spsupp.dll]\"|/i:Substitute_OWSSUPP "
L"\"[#spsupp_x64.dll]\"";
auto SetFormattedPropW = [&](LPCWSTR sProp, LPCWSTR sVal) {
PMSIHANDLE hRec = MsiCreateRecord(0);
if (!hRec)
throw std::exception("MsiCreateRecord failed!");
MsiRecordSetStringW(hRec, 0, sVal);
DWORD nSz = 0;
if (MsiFormatRecordW(hInstall, hRec, L"", &nSz) == ERROR_MORE_DATA)
{
++nSz;
auto buf = std::make_unique<wchar_t[]>(nSz);
CheckWin32Error("MsiFormatRecordW",
MsiFormatRecordW(hInstall, hRec, buf.get(), &nSz));
CheckWin32Error("MsiSetPropertyW", MsiSetPropertyW(hInstall, sProp, buf.get()));
}
};
if (bRegActiveX)
SetFormattedPropW(L"reg_dlls", sRegData.c_str());
if (bUnregActiveX)
SetFormattedPropW(L"unreg_dlls", sRegData.c_str());
}
catch (std::exception& e)
{
WriteLog(hInstall, e.what());
}
return ERROR_SUCCESS;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
LIBRARY "r.dll"
EXPORTS
RegDLLs
UnregDLLs
PrepRegUnregDLLs
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment