calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / setup_native / source / win32 / customactions / reg_dlls / reg_dlls.cxx
blobb1e204a80d12a8dc21d7851c3d3eef1c7adba3ad
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <iomanip>
11 #include <memory>
12 #include <string>
13 #include <sstream>
15 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
17 #include <Shlobj.h>
18 #include <msiquery.h>
20 namespace
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
26 << n;
27 return sMsg.str();
30 template <typename IntType> std::string Num2Dec(IntType n)
32 std::stringstream sMsg;
33 sMsg << n;
34 return sMsg.str();
37 std::string Win32ErrorMessage(const char* sFunc, DWORD nWin32Error)
39 std::stringstream sMsg;
40 sMsg << sFunc << " failed with Win32 error code " << Num2Hex(nWin32Error) << "!";
42 return sMsg.str();
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)
55 if (FAILED(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);
78 CoTaskMemFree(sPath);
79 return sResult;
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));
123 if (!hRec)
124 return;
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;
134 DWORD nSz = 0;
135 UINT nRet = ::MsiGetPropertyW(hInst, szName, const_cast<wchar_t*>(L""), &nSz);
136 if (nRet == ERROR_MORE_DATA)
138 ++nSz;
139 auto buf = std::make_unique<wchar_t[]>(nSz);
140 CheckWin32Error("MsiGetPropertyW", ::MsiGetPropertyW(hInst, szName, buf.get(), &nSz));
141 sResult = buf.get();
142 WriteLog(hInst, "Property", szName, "=", sResult);
144 else
145 CheckWin32Error("MsiGetPropertyW", nRet);
147 return sResult;
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 ";
160 if (bUnreg)
161 sCmd += L"/u ";
162 sCmd += sArgs;
163 WriteLog(hInst, "Prepared regsvr32 command:", sCmd);
165 STARTUPINFOW si{};
166 si.cb = sizeof(si);
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);
178 DWORD nExitCode = 0;
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);
196 std::wstring sToken;
197 while (std::getline(ss, sToken, L'|'))
199 if (!sToken.empty())
201 RegDLL(hInst, sToken, bUnreg);
205 } // namespace
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 &current_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 &current_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
268 const bool bRegMain
269 = (current_state_Main == INSTALLSTATE_ABSENT && future_state_Main == INSTALLSTATE_LOCAL)
270 || (bUnregSubstMSO && !bUnregMain);
272 std::wstring sUnregStr;
273 if (bUnregSubstMSO)
275 sUnregStr = L"/i:Substitute_OWSSUPP \"[#spsupp_x86.dll]\"|"
276 L"/i:Substitute_OWSSUPP \"[#spsupp_x64.dll]\"";
278 else if (bUnregMain)
280 sUnregStr = L"\"[#spsupp_x86.dll]\"|\"[#spsupp_x64.dll]\"";
283 std::wstring sRegStr;
284 if (bRegSubstMSO)
286 sRegStr = L"/i:Substitute_OWSSUPP \"[#spsupp_x86.dll]\"|"
287 L"/i:Substitute_OWSSUPP \"[#spsupp_x64.dll]\"";
289 else if (bRegMain)
291 sRegStr = L"\"[#spsupp_x86.dll]\"|\"[#spsupp_x64.dll]\"";
294 auto SetFormattedPropW = [&](LPCWSTR sProp, const std::wstring& sVal) {
295 PMSIHANDLE hRec = MsiCreateRecord(0);
296 if (!hRec)
297 throw std::exception("MsiCreateRecord failed!");
298 MsiRecordSetStringW(hRec, 0, sVal.c_str());
299 DWORD nSz = 0;
300 if (MsiFormatRecordW(hInstall, hRec, const_cast<wchar_t*>(L""), &nSz)
301 == ERROR_MORE_DATA)
303 ++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: */