cid#1607171 Data race condition
[LibreOffice.git] / shell / source / win32 / spsupp / registrar.cxx
blob1d647f3a556c06aa1e5e622c15ea2d16dce485e6
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 <registrar.hpp>
11 #include <wchar.h>
12 #include <objbase.h>
14 namespace {
16 HRESULT RegRead(HKEY hRootKey, const wchar_t* subKey, const wchar_t* valName, wchar_t* valData, size_t cchData)
18 HKEY hKey;
19 LSTATUS iRetVal = RegCreateKeyExW(
20 hRootKey,
21 subKey,
23 nullptr,
24 REG_OPTION_NON_VOLATILE,
25 KEY_READ,
26 nullptr,
27 &hKey,
28 nullptr);
29 if (iRetVal != ERROR_SUCCESS)
30 return HRESULT_FROM_WIN32(iRetVal);
32 DWORD cbData = cchData * sizeof(valData[0]);
33 DWORD dwType;
34 iRetVal = RegQueryValueExW(hKey, valName, nullptr, &dwType, reinterpret_cast<LPBYTE>(valData), &cbData);
35 RegCloseKey(hKey);
36 if ((iRetVal == ERROR_SUCCESS) && (dwType != REG_SZ))
38 return E_FAIL;
40 return HRESULT_FROM_WIN32(iRetVal);
43 HRESULT RegWrite(HKEY hRootKey, const wchar_t* subKey, const wchar_t* valName, const wchar_t* valData, HKEY *hKeyResult = nullptr)
45 HKEY hKey;
46 LSTATUS iRetVal = RegCreateKeyExW(
47 hRootKey,
48 subKey,
50 nullptr,
51 REG_OPTION_NON_VOLATILE,
52 KEY_WRITE,
53 nullptr,
54 &hKey,
55 nullptr);
56 if (iRetVal != ERROR_SUCCESS)
57 return HRESULT_FROM_WIN32(iRetVal);
59 if (valData)
61 DWORD cbData = static_cast<DWORD>(wcslen(valData)*sizeof(valData[0]));
62 iRetVal = RegSetValueExW(hKey, valName, 0, REG_SZ, reinterpret_cast<const BYTE *>(valData), cbData);
65 if (hKeyResult && (iRetVal == ERROR_SUCCESS))
66 *hKeyResult = hKey;
67 else
68 RegCloseKey(hKey);
70 return HRESULT_FROM_WIN32(iRetVal);
73 HRESULT RegDel(HKEY hRootKey, const wchar_t* subKey)
75 LSTATUS iRetVal = RegDeleteKeyW(hRootKey, subKey);
76 return HRESULT_FROM_WIN32(iRetVal);
79 } // namespace
81 // see http://stackoverflow.com/questions/284619
82 // see https://msdn.microsoft.com/en-us/library/ms691424
83 // see https://msdn.microsoft.com/en-us/library/ms694514
85 Registrar::Registrar(REFIID riidCLSID)
87 m_ConstructionResult = (StringFromGUID2(riidCLSID, m_sCLSID, nGUIDlen) == 0) ?
88 E_UNEXPECTED: S_OK;
91 HRESULT Registrar::RegisterObject(REFIID riidTypeLib, const wchar_t* sProgram,
92 const wchar_t* sComponent, std::initializer_list<int> aVersions,
93 const wchar_t* Path)
95 if (!wcslen(sComponent) || !wcslen(sProgram))
96 return E_INVALIDARG;
98 if (FAILED(m_ConstructionResult))
99 return m_ConstructionResult;
101 // HKEY_CLASSES_ROOT
102 // \CLSID
103 // \{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
104 // (default) = "MyLibrary MyControl Class"
105 // \InprocServer32
106 // (default) = "c:\foo\control.dll"
107 // ThreadingModel = "Apartment"
108 // \ProgID
109 // (default) = "MyLibrary.MyControl"
110 // \Programmable
111 // \TypeLib
112 // (default) = "{YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY}"
114 wchar_t sBufKey[MAX_PATH];
115 wchar_t sBufVal[MAX_PATH];
117 // CLSID
118 swprintf(sBufKey, MAX_PATH, L"CLSID\\%s", m_sCLSID);
119 swprintf(sBufVal, MAX_PATH, L"%s %s Class", sProgram, sComponent);
120 HKEY hKeyCLSID;
121 HRESULT hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal, &hKeyCLSID);
122 if (FAILED(hr))
123 return hr;
125 class HKeyGuard {
126 public:
127 HKeyGuard(HKEY aKey) : m_hKey(aKey) {}
128 ~HKeyGuard() { RegCloseKey(m_hKey); }
129 private:
130 HKEY m_hKey;
133 HKeyGuard hKeyCLSIDGuard(hKeyCLSID);
135 // InprocServer32
136 HKEY hKeyInprocServer32;
137 hr = RegWrite(hKeyCLSID, L"InprocServer32", L"", Path, &hKeyInprocServer32);
138 if (FAILED(hr))
139 return hr;
141 HKeyGuard hKeyInProcServer32Guard(hKeyInprocServer32);
142 hr = RegWrite(hKeyInprocServer32, L"", L"ThreadingModel", L"Apartment");
143 if (FAILED(hr))
144 return hr;
147 // ProgID
148 swprintf(sBufVal, MAX_PATH, L"%s.%s", sProgram, sComponent);
149 hr = RegWrite(hKeyCLSID, L"ProgID", L"", sBufVal);
150 if (FAILED(hr))
151 return hr;
153 // Programmable
154 hr = RegWrite(hKeyCLSID, L"Programmable", nullptr, nullptr);
155 if (FAILED(hr))
156 return hr;
158 // TypeLib
159 if (::StringFromGUID2(riidTypeLib, sBufVal, nGUIDlen) == 0)
160 return E_UNEXPECTED;
161 hr = RegWrite(hKeyCLSID, L"TypeLib", L"", sBufVal);
162 if (FAILED(hr))
163 return hr;
166 // ProgID
167 return RegisterProgIDs(sProgram, sComponent, aVersions);
170 HRESULT Registrar::UnRegisterObject(const wchar_t* sProgram, const wchar_t* sComponent,
171 std::initializer_list<int> aVersions)
173 if (FAILED(m_ConstructionResult))
174 return m_ConstructionResult;
175 // ProgID
176 UnRegisterProgIDs(sProgram, sComponent, aVersions);
177 // CLSID
178 wchar_t sBuf[MAX_PATH];
179 swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\InProcServer32", m_sCLSID);
180 RegDel(HKEY_CLASSES_ROOT, sBuf);
181 swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\ProgId", m_sCLSID);
182 RegDel(HKEY_CLASSES_ROOT, sBuf);
183 swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\Programmable", m_sCLSID);
184 RegDel(HKEY_CLASSES_ROOT, sBuf);
185 swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\TypeLib", m_sCLSID);
186 RegDel(HKEY_CLASSES_ROOT, sBuf);
187 swprintf(sBuf, MAX_PATH, L"CLSID\\%s", m_sCLSID);
188 RegDel(HKEY_CLASSES_ROOT, sBuf);
189 return S_OK;
192 HRESULT Registrar::RegisterProgID(const wchar_t* sProgram, const wchar_t* sComponent, int nVersion, bool bSetDefault)
194 // HKEY_CLASSES_ROOT
195 // \MyLibrary.MyControl
196 // (default) = "MyLibrary MyControl Class"
197 // \CurVer
198 // (default) = "MyLibrary.MyControl.1"
199 // \MyLibrary.MyControl.1
200 // (default) = "MyLibrary MyControl Class"
201 // \CLSID
202 // (default) = "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
203 if (FAILED(m_ConstructionResult))
204 return m_ConstructionResult;
205 wchar_t sBufKey[MAX_PATH];
206 swprintf(sBufKey, MAX_PATH, L"%s.%s.%d", sProgram, sComponent, nVersion);
207 wchar_t sBufVal[MAX_PATH];
208 swprintf(sBufVal, MAX_PATH, L"%s %s Class", sProgram, sComponent);
209 RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal);
210 swprintf(sBufKey, MAX_PATH, L"%s.%s.%d\\CLSID", sProgram, sComponent, nVersion);
211 HRESULT hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", m_sCLSID);
212 if (SUCCEEDED(hr) && bSetDefault)
214 swprintf(sBufKey, MAX_PATH, L"%s.%s", sProgram, sComponent);
215 swprintf(sBufVal, MAX_PATH, L"%s %s Class", sProgram, sComponent);
216 hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal);
217 swprintf(sBufKey, MAX_PATH, L"%s.%s\\CurVer", sProgram, sComponent);
218 swprintf(sBufVal, MAX_PATH, L"%s.%s.%d", sProgram, sComponent, nVersion);
219 hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal);
221 return hr;
224 HRESULT Registrar::RegisterProgIDs(const wchar_t* sProgram, const wchar_t* sComponent,
225 std::initializer_list<int> aVersions)
227 HRESULT hr = S_OK;
228 bool bDefaultRegistered = false;
229 for (int nVersion : aVersions)
231 if (SUCCEEDED(hr))
233 hr = RegisterProgID(sProgram, sComponent, nVersion, !bDefaultRegistered);
234 bDefaultRegistered = true;
237 return hr;
240 HRESULT Registrar::UnRegisterProgID(const wchar_t* sProgram, const wchar_t* sComponent, int nVersion)
242 if (FAILED(m_ConstructionResult))
243 return m_ConstructionResult;
244 wchar_t sBuf[MAX_PATH];
245 swprintf(sBuf, MAX_PATH, L"%s.%s.%d\\CLSID", sProgram, sComponent, nVersion);
246 wchar_t sCurCLSID[nGUIDlen];
247 HRESULT hr = RegRead(HKEY_CLASSES_ROOT, sBuf, L"", sCurCLSID, nGUIDlen);
248 if (FAILED(hr))
249 return hr;
250 if (wcsncmp(sCurCLSID, m_sCLSID, nGUIDlen) != 0)
252 // The ProgID points to a different CLSID; most probably it's intercepted
253 // by a different application, so don't remove it
254 return S_FALSE;
256 RegDel(HKEY_CLASSES_ROOT, sBuf);
257 swprintf(sBuf, MAX_PATH, L"%s.%s.%d", sProgram, sComponent, nVersion);
258 hr = RegDel(HKEY_CLASSES_ROOT, sBuf);
260 wchar_t sBufKey[MAX_PATH];
261 swprintf(sBufKey, MAX_PATH, L"%s.%s\\CurVer", sProgram, sComponent);
262 wchar_t sBufVal[MAX_PATH];
263 if (SUCCEEDED(RegRead(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal, MAX_PATH)) && (wcsncmp(sBufVal, sBuf, MAX_PATH) == 0))
265 // Only unreg default if this version is current default
266 RegDel(HKEY_CLASSES_ROOT, sBufKey);
267 swprintf(sBuf, MAX_PATH, L"%s.%s", sProgram, sComponent);
268 HRESULT hr1 = RegDel(HKEY_CLASSES_ROOT, sBuf);
269 // Always return a failure result if we failed somewhere
270 if (FAILED(hr1))
271 hr = hr1;
273 return hr;
276 HRESULT Registrar::UnRegisterProgIDs(const wchar_t* sProgram, const wchar_t* sComponent,
277 std::initializer_list<int> aVersions)
279 HRESULT hr = S_OK;
280 // Try all ProgIDs regardless of error, but make sure to return failure result if some failed
281 for (int nVersion : aVersions)
283 HRESULT hrLast = UnRegisterProgID(sProgram, sComponent, nVersion);
284 if (SUCCEEDED(hr))
285 hr = hrLast;
287 return hr;
290 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */