1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
15 #define WIN32_LEAN_AND_MEAN
22 template <typename IntType
> std::string
Num2Hex(IntType n
)
24 std::stringstream sMsg
;
25 sMsg
<< "0x" << std::uppercase
<< std::setfill('0') << std::setw(sizeof(n
) * 2) << std::hex
30 template <typename IntType
> std::string
Num2Dec(IntType n
)
32 std::stringstream sMsg
;
37 std::string
Win32ErrorMessage(const char* sFunc
, DWORD nWin32Error
)
39 std::stringstream sMsg
;
40 sMsg
<< sFunc
<< " failed with Win32 error code " << Num2Hex(nWin32Error
) << "!";
45 void ThrowHResult(const char* sFunc
, HRESULT hr
)
47 std::stringstream sMsg
;
48 sMsg
<< sFunc
<< " failed (HRESULT = " << Num2Hex(hr
) << ")!";
50 throw std::exception(sMsg
.str().c_str());
53 void CheckHResult(const char* sFunc
, HRESULT hr
)
56 ThrowHResult(sFunc
, hr
);
59 void ThrowWin32Error(const char* sFunc
, DWORD nWin32Error
)
61 throw std::exception(Win32ErrorMessage(sFunc
, nWin32Error
).c_str());
64 void ThrowLastError(const char* sFunc
) { ThrowWin32Error(sFunc
, GetLastError()); }
66 void CheckWin32Error(const char* sFunc
, DWORD nWin32Error
)
68 if (nWin32Error
!= ERROR_SUCCESS
)
69 ThrowWin32Error(sFunc
, nWin32Error
);
72 std::wstring
GetKnownFolder(const KNOWNFOLDERID
& rfid
)
74 PWSTR sPath
= nullptr;
75 HRESULT hr
= SHGetKnownFolderPath(rfid
, KF_FLAG_DEFAULT
, nullptr, &sPath
);
76 CheckHResult("SHGetKnownFolderPath", hr
);
77 std::wstring
sResult(sPath
);
82 void WriteLogElem(MSIHANDLE hInst
, MSIHANDLE hRecord
, std::ostringstream
& sTmpl
, UINT
)
84 MsiRecordSetStringA(hRecord
, 0, sTmpl
.str().c_str());
85 MsiProcessMessage(hInst
, INSTALLMESSAGE_INFO
, hRecord
);
88 void RecSetString(MSIHANDLE hRec
, UINT nField
, LPCSTR sVal
)
90 MsiRecordSetStringA(hRec
, nField
, sVal
);
93 void RecSetString(MSIHANDLE hRec
, UINT nField
, LPCWSTR sVal
)
95 MsiRecordSetStringW(hRec
, nField
, sVal
);
98 template <class S1
, class... SOther
>
99 void WriteLogElem(MSIHANDLE hInst
, MSIHANDLE hRec
, std::ostringstream
& sTmpl
, UINT nField
,
100 const S1
& elem
, const SOther
&... others
);
102 template <class Ch
, class... SOther
>
103 void WriteLogElem(MSIHANDLE hInst
, MSIHANDLE hRec
, std::ostringstream
& sTmpl
, UINT nField
,
104 const Ch
* elem
, const SOther
&... others
)
106 sTmpl
<< " [" << nField
<< "]";
107 RecSetString(hRec
, nField
, elem
);
108 WriteLogElem(hInst
, hRec
, sTmpl
, nField
+ 1, others
...);
111 template <class S1
, class... SOther
>
112 void WriteLogElem(MSIHANDLE hInst
, MSIHANDLE hRec
, std::ostringstream
& sTmpl
, UINT nField
,
113 const S1
& elem
, const SOther
&... others
)
115 WriteLogElem(hInst
, hRec
, sTmpl
, nField
, elem
.c_str(), others
...);
118 std::string sLogPrefix
;
120 template <class... StrType
> void WriteLog(MSIHANDLE hInst
, const StrType
&... elements
)
122 PMSIHANDLE hRec
= MsiCreateRecord(sizeof...(elements
));
126 std::ostringstream sTemplate
;
127 sTemplate
<< sLogPrefix
;
128 WriteLogElem(hInst
, hRec
, sTemplate
, 1, elements
...);
131 std::wstring
MsiGetPropertyW(MSIHANDLE hInst
, LPCWSTR szName
)
133 std::wstring sResult
;
135 UINT nRet
= ::MsiGetPropertyW(hInst
, szName
, const_cast<wchar_t*>(L
""), &nSz
);
136 if (nRet
== ERROR_MORE_DATA
)
139 auto buf
= std::make_unique
<wchar_t[]>(nSz
);
140 CheckWin32Error("MsiGetPropertyW", ::MsiGetPropertyW(hInst
, szName
, buf
.get(), &nSz
));
142 WriteLog(hInst
, "Property", szName
, "=", sResult
);
145 CheckWin32Error("MsiGetPropertyW", nRet
);
150 typedef std::unique_ptr
<void, decltype(&CloseHandle
)> CloseHandleGuard
;
151 CloseHandleGuard
Guard(HANDLE h
) { return CloseHandleGuard(h
, CloseHandle
); }
153 void RegDLL(MSIHANDLE hInst
, const std::wstring
& sArgs
, bool bUnreg
)
155 static std::wstring sRegSvr32
= GetKnownFolder(FOLDERID_System
) + L
"\\regsvr32.exe";
159 std::wstring sCmd
= L
"\"" + sRegSvr32
+ L
"\" /s ";
163 WriteLog(hInst
, "Prepared regsvr32 command:", sCmd
);
167 PROCESS_INFORMATION pi
{};
168 if (!CreateProcessW(sRegSvr32
.c_str(), const_cast<LPWSTR
>(sCmd
.c_str()), nullptr, nullptr,
169 FALSE
, CREATE_NO_WINDOW
, nullptr, nullptr, &si
, &pi
))
170 ThrowLastError("CreateProcessW");
171 auto aCloseProcHandleGuard(Guard(pi
.hProcess
));
172 WriteLog(hInst
, "CreateProcessW succeeded");
174 DWORD nWaitResult
= WaitForSingleObject(pi
.hProcess
, INFINITE
);
175 if (nWaitResult
!= WAIT_OBJECT_0
)
176 ThrowWin32Error("WaitForSingleObject", nWaitResult
);
179 if (!GetExitCodeProcess(pi
.hProcess
, &nExitCode
))
180 ThrowLastError("GetExitCodeProcess");
182 WriteLog(hInst
, "regsvr32 returned:", Num2Dec(nExitCode
));
184 catch (std::exception
& e
)
186 WriteLog(hInst
, e
.what());
190 void ProcessCustomActionData(MSIHANDLE hInst
, bool bUnreg
)
192 WriteLog(hInst
, "Checking value of CustomActionData");
193 std::wstring sCustomActionData
= MsiGetPropertyW(hInst
, L
"CustomActionData");
194 WriteLog(hInst
, "Got CustomActionData value:", sCustomActionData
);
195 std::wstringstream
ss(sCustomActionData
);
197 while (std::getline(ss
, sToken
, L
'|'))
201 RegDLL(hInst
, sToken
, bUnreg
);
207 // Deferred action "reg_dlls" that must be run from system account. Receives a list of regsvr32
208 // arguments: DLLs which need registering, and possibly /i argument with its parameter.
209 extern "C" __declspec(dllexport
) UINT __stdcall
RegDLLs(MSIHANDLE hInstall
)
211 sLogPrefix
= "RegDLLs:";
212 WriteLog(hInstall
, "started");
214 ProcessCustomActionData(hInstall
, false);
215 return ERROR_SUCCESS
;
218 // Deferred action "unreg_dlls" that must be run from system account. Receives a list of regsvr32
219 // arguments: DLLs which need registering, and possibly /i argument with its parameter.
220 extern "C" __declspec(dllexport
) UINT __stdcall
UnregDLLs(MSIHANDLE hInstall
)
222 sLogPrefix
= "UnregDLLs:";
223 WriteLog(hInstall
, "started");
225 ProcessCustomActionData(hInstall
, true);
226 return ERROR_SUCCESS
;
229 // Immediate action "prep_reg_unreg_dlls". Checks states of the features to prepare custom action data
230 // for reg_dlls and unreg_dlls deferred actions.
231 extern "C" __declspec(dllexport
) UINT __stdcall
PrepRegUnregDLLs(MSIHANDLE hInstall
)
233 sLogPrefix
= "PrepRegUnregDLLs:";
234 WriteLog(hInstall
, "started");
238 INSTALLSTATE current_state_SubstMSO
;
239 INSTALLSTATE future_state_SubstMSO
;
240 CheckWin32Error("MsiGetFeatureStateW",
241 MsiGetFeatureStateW(hInstall
, L
"gm_SharePointSupport_SubstMSO",
242 ¤t_state_SubstMSO
, &future_state_SubstMSO
));
244 WriteLog(hInstall
, "gm_SharePointSupport_SubstMSO state:", //
245 "current", std::to_string(current_state_SubstMSO
), //
246 "future", std::to_string(future_state_SubstMSO
)); //
248 INSTALLSTATE current_state_Main
;
249 INSTALLSTATE future_state_Main
;
250 CheckWin32Error("MsiGetFeatureStateW",
251 MsiGetFeatureStateW(hInstall
, L
"gm_o_SharePointSupport",
252 ¤t_state_Main
, &future_state_Main
));
254 WriteLog(hInstall
, "gm_o_SharePointSupport state:", //
255 "current", std::to_string(current_state_Main
), //
256 "future", std::to_string(future_state_Main
)); //
258 const bool bUnregSubstMSO
= current_state_SubstMSO
== INSTALLSTATE_LOCAL
259 && future_state_SubstMSO
== INSTALLSTATE_ABSENT
;
260 const bool bUnregMain
261 = current_state_Main
== INSTALLSTATE_LOCAL
&& future_state_Main
== INSTALLSTATE_ABSENT
;
262 const bool bRegSubstMSO
= current_state_SubstMSO
== INSTALLSTATE_ABSENT
263 && future_state_SubstMSO
== INSTALLSTATE_LOCAL
;
264 // basic registration is needed when either:
265 // 1. gm_o_SharePointSupport is installed;
266 // 2. gm_SharePointSupport_SubstMSO is uninstalled (and unregisters everything), but
267 // gm_o_SharePointSupport is not, so needs to be re-registered
269 = (current_state_Main
== INSTALLSTATE_ABSENT
&& future_state_Main
== INSTALLSTATE_LOCAL
)
270 || (bUnregSubstMSO
&& !bUnregMain
);
272 std::wstring sUnregStr
;
275 sUnregStr
= L
"/i:Substitute_OWSSUPP \"[#spsupp_x86.dll]\"|"
276 L
"/i:Substitute_OWSSUPP \"[#spsupp_x64.dll]\"";
280 sUnregStr
= L
"\"[#spsupp_x86.dll]\"|\"[#spsupp_x64.dll]\"";
283 std::wstring sRegStr
;
286 sRegStr
= L
"/i:Substitute_OWSSUPP \"[#spsupp_x86.dll]\"|"
287 L
"/i:Substitute_OWSSUPP \"[#spsupp_x64.dll]\"";
291 sRegStr
= L
"\"[#spsupp_x86.dll]\"|\"[#spsupp_x64.dll]\"";
294 auto SetFormattedPropW
= [&](LPCWSTR sProp
, const std::wstring
& sVal
) {
295 PMSIHANDLE hRec
= MsiCreateRecord(0);
297 throw std::exception("MsiCreateRecord failed!");
298 MsiRecordSetStringW(hRec
, 0, sVal
.c_str());
300 if (MsiFormatRecordW(hInstall
, hRec
, const_cast<wchar_t*>(L
""), &nSz
)
304 auto buf
= std::make_unique
<wchar_t[]>(nSz
);
305 CheckWin32Error("MsiFormatRecordW",
306 MsiFormatRecordW(hInstall
, hRec
, buf
.get(), &nSz
));
307 CheckWin32Error("MsiSetPropertyW", MsiSetPropertyW(hInstall
, sProp
, buf
.get()));
310 if (!sRegStr
.empty())
311 SetFormattedPropW(L
"reg_dlls", sRegStr
);
312 if (!sUnregStr
.empty())
313 SetFormattedPropW(L
"unreg_dlls", sUnregStr
);
315 catch (std::exception
& e
)
317 WriteLog(hInstall
, e
.what());
320 return ERROR_SUCCESS
;
323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */