15#define WIN32_LEAN_AND_MEAN
22template <
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
30template <
typename IntType> std::string Num2Dec(IntType
n)
32 std::stringstream sMsg;
37std::string Win32ErrorMessage(
const char* sFunc, DWORD nWin32Error)
39 std::stringstream sMsg;
40 sMsg << sFunc <<
" failed with Win32 error code " <<
Num2Hex(nWin32Error) <<
"!";
45void 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());
53void CheckHResult(
const char* sFunc, HRESULT
hr)
56 ThrowHResult(sFunc,
hr);
61 throw std::exception(Win32ErrorMessage(sFunc, nWin32Error).c_str());
66void CheckWin32Error(
const char* sFunc, DWORD nWin32Error)
68 if (nWin32Error != ERROR_SUCCESS)
72std::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);
82void WriteLogElem(MSIHANDLE hInst, MSIHANDLE hRecord, std::ostringstream& sTmpl, UINT)
84 MsiRecordSetStringA(hRecord, 0, sTmpl.str().c_str());
85 MsiProcessMessage(hInst, INSTALLMESSAGE_INFO, hRecord);
88void RecSetString(MSIHANDLE hRec, UINT nField, LPCSTR sVal)
90 MsiRecordSetStringA(hRec, nField, sVal);
93void RecSetString(MSIHANDLE hRec, UINT nField, LPCWSTR sVal)
95 MsiRecordSetStringW(hRec, nField, sVal);
98template <
class S1,
class... SOther>
99void WriteLogElem(MSIHANDLE hInst, MSIHANDLE hRec, std::ostringstream& sTmpl, UINT nField,
100 const S1& elem,
const SOther&... others);
102template <
class Ch,
class... SOther>
103void 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...);
111template <
class S1,
class... SOther>
112void 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...);
118std::string sLogPrefix;
120template <
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...);
131std::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);
150typedef std::unique_ptr<void,
decltype(&CloseHandle)> CloseHandleGuard;
151CloseHandleGuard Guard(HANDLE
h) {
return CloseHandleGuard(
h, CloseHandle); }
153void 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))
171 auto aCloseProcHandleGuard(Guard(pi.hProcess));
172 WriteLog(hInst,
"CreateProcessW succeeded");
174 DWORD nWaitResult = WaitForSingleObject(pi.hProcess, INFINITE);
175 if (nWaitResult != WAIT_OBJECT_0)
179 if (!GetExitCodeProcess(pi.hProcess, &nExitCode))
182 WriteLog(hInst,
"regsvr32 returned:", Num2Dec(nExitCode));
184 catch (std::exception& e)
186 WriteLog(hInst, e.what());
190void 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);
209extern "C" __declspec(dllexport) UINT __stdcall RegDLLs(MSIHANDLE hInstall)
211 sLogPrefix =
"RegDLLs:";
212 WriteLog(hInstall,
"started");
214 ProcessCustomActionData(hInstall,
false);
215 return ERROR_SUCCESS;
220extern "C" __declspec(dllexport) UINT __stdcall UnregDLLs(MSIHANDLE hInstall)
222 sLogPrefix =
"UnregDLLs:";
223 WriteLog(hInstall,
"started");
225 ProcessCustomActionData(hInstall,
true);
226 return ERROR_SUCCESS;
231extern "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;
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;
__declspec(dllexport) UINT __stdcall RegDLLs(MSIHANDLE hInstall)
std::string Num2Hex(IntType n)
void ThrowLastError(const char *sFunc)
void ThrowWin32Error(const char *sFunc, DWORD nWin32Error)