summaryrefslogtreecommitdiffstats
path: root/shell/source/win32/spsupp/registrar.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--shell/source/win32/spsupp/registrar.cxx290
1 files changed, 290 insertions, 0 deletions
diff --git a/shell/source/win32/spsupp/registrar.cxx b/shell/source/win32/spsupp/registrar.cxx
new file mode 100644
index 000000000..008c2ac59
--- /dev/null
+++ b/shell/source/win32/spsupp/registrar.cxx
@@ -0,0 +1,290 @@
+/* -*- 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 <registrar.hpp>
+#include <wchar.h>
+#include <objbase.h>
+
+namespace {
+
+ HRESULT RegRead(HKEY hRootKey, const wchar_t* subKey, const wchar_t* valName, wchar_t* valData, size_t cchData)
+ {
+ HKEY hKey;
+ long iRetVal = RegCreateKeyExW(
+ hRootKey,
+ subKey,
+ 0,
+ nullptr,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ,
+ nullptr,
+ &hKey,
+ nullptr);
+ if (iRetVal != ERROR_SUCCESS)
+ return HRESULT_FROM_WIN32(iRetVal);
+
+ DWORD cbData = cchData * sizeof(valData[0]);
+ DWORD dwType;
+ iRetVal = RegQueryValueExW(hKey, valName, nullptr, &dwType, reinterpret_cast<LPBYTE>(valData), &cbData);
+ RegCloseKey(hKey);
+ if ((iRetVal == ERROR_SUCCESS) && (dwType != REG_SZ))
+ {
+ return E_FAIL;
+ }
+ return HRESULT_FROM_WIN32(iRetVal);
+ }
+
+ HRESULT RegWrite(HKEY hRootKey, const wchar_t* subKey, const wchar_t* valName, const wchar_t* valData, HKEY *hKeyResult = nullptr)
+ {
+ HKEY hKey;
+ long iRetVal = RegCreateKeyExW(
+ hRootKey,
+ subKey,
+ 0,
+ nullptr,
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE,
+ nullptr,
+ &hKey,
+ nullptr);
+ if (iRetVal != ERROR_SUCCESS)
+ return HRESULT_FROM_WIN32(iRetVal);
+
+ if (valData)
+ {
+ DWORD cbData = static_cast<DWORD>(wcslen(valData)*sizeof(valData[0]));
+ iRetVal = RegSetValueExW(hKey, valName, 0, REG_SZ, reinterpret_cast<const BYTE *>(valData), cbData);
+ }
+
+ if (hKeyResult && (iRetVal == ERROR_SUCCESS))
+ *hKeyResult = hKey;
+ else
+ RegCloseKey(hKey);
+
+ return HRESULT_FROM_WIN32(iRetVal);
+ }
+
+ HRESULT RegDel(HKEY hRootKey, const wchar_t* subKey)
+ {
+ long iRetVal = RegDeleteKeyW(hRootKey, subKey);
+ return HRESULT_FROM_WIN32(iRetVal);
+ }
+
+} // namespace
+
+// see http://stackoverflow.com/questions/284619
+// see https://msdn.microsoft.com/en-us/library/ms691424
+// see https://msdn.microsoft.com/en-us/library/ms694514
+
+Registrar::Registrar(REFIID riidCLSID)
+{
+ m_ConstructionResult = (StringFromGUID2(riidCLSID, m_sCLSID, nGUIDlen) == 0) ?
+ E_UNEXPECTED: S_OK;
+}
+
+HRESULT Registrar::RegisterObject(REFIID riidTypeLib, const wchar_t* sProgram,
+ const wchar_t* sComponent, std::initializer_list<int> aVersions,
+ const wchar_t* Path)
+{
+ if (!wcslen(sComponent) || !wcslen(sProgram))
+ return E_INVALIDARG;
+
+ if (FAILED(m_ConstructionResult))
+ return m_ConstructionResult;
+
+ // HKEY_CLASSES_ROOT
+ // \CLSID
+ // \{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
+ // (default) = "MyLibrary MyControl Class"
+ // \InprocServer32
+ // (default) = "c:\foo\control.dll"
+ // ThreadingModel = "Apartment"
+ // \ProgID
+ // (default) = "MyLibrary.MyControl"
+ // \Programmable
+ // \TypeLib
+ // (default) = "{YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY}"
+
+ wchar_t sBufKey[MAX_PATH];
+ wchar_t sBufVal[MAX_PATH];
+
+ // CLSID
+ swprintf(sBufKey, MAX_PATH, L"CLSID\\%s", m_sCLSID);
+ swprintf(sBufVal, MAX_PATH, L"%s %s Class", sProgram, sComponent);
+ HKEY hKeyCLSID;
+ HRESULT hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal, &hKeyCLSID);
+ if (FAILED(hr))
+ return hr;
+ {
+ class HKeyGuard {
+ public:
+ HKeyGuard(HKEY aKey) : m_hKey(aKey) {}
+ ~HKeyGuard() { RegCloseKey(m_hKey); }
+ private:
+ HKEY m_hKey;
+ };
+
+ HKeyGuard hKeyCLSIDGuard(hKeyCLSID);
+
+ // InprocServer32
+ HKEY hKeyInprocServer32;
+ hr = RegWrite(hKeyCLSID, L"InprocServer32", L"", Path, &hKeyInprocServer32);
+ if (FAILED(hr))
+ return hr;
+ {
+ HKeyGuard hKeyInProcServer32Guard(hKeyInprocServer32);
+ hr = RegWrite(hKeyInprocServer32, L"", L"ThreadingModel", L"Apartment");
+ if (FAILED(hr))
+ return hr;
+ }
+
+ // ProgID
+ swprintf(sBufVal, MAX_PATH, L"%s.%s", sProgram, sComponent);
+ hr = RegWrite(hKeyCLSID, L"ProgID", L"", sBufVal);
+ if (FAILED(hr))
+ return hr;
+
+ // Programmable
+ hr = RegWrite(hKeyCLSID, L"Programmable", nullptr, nullptr);
+ if (FAILED(hr))
+ return hr;
+
+ // TypeLib
+ if (::StringFromGUID2(riidTypeLib, sBufVal, nGUIDlen) == 0)
+ return E_UNEXPECTED;
+ hr = RegWrite(hKeyCLSID, L"TypeLib", L"", sBufVal);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ // ProgID
+ return RegisterProgIDs(sProgram, sComponent, aVersions);
+}
+
+HRESULT Registrar::UnRegisterObject(const wchar_t* sProgram, const wchar_t* sComponent,
+ std::initializer_list<int> aVersions)
+{
+ if (FAILED(m_ConstructionResult))
+ return m_ConstructionResult;
+ // ProgID
+ UnRegisterProgIDs(sProgram, sComponent, aVersions);
+ // CLSID
+ wchar_t sBuf[MAX_PATH];
+ swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\InProcServer32", m_sCLSID);
+ RegDel(HKEY_CLASSES_ROOT, sBuf);
+ swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\ProgId", m_sCLSID);
+ RegDel(HKEY_CLASSES_ROOT, sBuf);
+ swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\Programmable", m_sCLSID);
+ RegDel(HKEY_CLASSES_ROOT, sBuf);
+ swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\TypeLib", m_sCLSID);
+ RegDel(HKEY_CLASSES_ROOT, sBuf);
+ swprintf(sBuf, MAX_PATH, L"CLSID\\%s", m_sCLSID);
+ RegDel(HKEY_CLASSES_ROOT, sBuf);
+ return S_OK;
+}
+
+HRESULT Registrar::RegisterProgID(const wchar_t* sProgram, const wchar_t* sComponent, int nVersion, bool bSetDefault)
+{
+ // HKEY_CLASSES_ROOT
+ // \MyLibrary.MyControl
+ // (default) = "MyLibrary MyControl Class"
+ // \CurVer
+ // (default) = "MyLibrary.MyControl.1"
+ // \MyLibrary.MyControl.1
+ // (default) = "MyLibrary MyControl Class"
+ // \CLSID
+ // (default) = "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
+ if (FAILED(m_ConstructionResult))
+ return m_ConstructionResult;
+ wchar_t sBufKey[MAX_PATH];
+ swprintf(sBufKey, MAX_PATH, L"%s.%s.%d", sProgram, sComponent, nVersion);
+ wchar_t sBufVal[MAX_PATH];
+ swprintf(sBufVal, MAX_PATH, L"%s %s Class", sProgram, sComponent);
+ RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal);
+ swprintf(sBufKey, MAX_PATH, L"%s.%s.%d\\CLSID", sProgram, sComponent, nVersion);
+ HRESULT hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", m_sCLSID);
+ if (SUCCEEDED(hr) && bSetDefault)
+ {
+ swprintf(sBufKey, MAX_PATH, L"%s.%s", sProgram, sComponent);
+ swprintf(sBufVal, MAX_PATH, L"%s %s Class", sProgram, sComponent);
+ hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal);
+ swprintf(sBufKey, MAX_PATH, L"%s.%s\\CurVer", sProgram, sComponent);
+ swprintf(sBufVal, MAX_PATH, L"%s.%s.%d", sProgram, sComponent, nVersion);
+ hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal);
+ }
+ return hr;
+}
+
+HRESULT Registrar::RegisterProgIDs(const wchar_t* sProgram, const wchar_t* sComponent,
+ std::initializer_list<int> aVersions)
+{
+ HRESULT hr = S_OK;
+ bool bDefaultRegistered = false;
+ for (int nVersion : aVersions)
+ {
+ if (SUCCEEDED(hr))
+ {
+ hr = RegisterProgID(sProgram, sComponent, nVersion, !bDefaultRegistered);
+ bDefaultRegistered = true;
+ }
+ }
+ return hr;
+}
+
+HRESULT Registrar::UnRegisterProgID(const wchar_t* sProgram, const wchar_t* sComponent, int nVersion)
+{
+ if (FAILED(m_ConstructionResult))
+ return m_ConstructionResult;
+ wchar_t sBuf[MAX_PATH];
+ swprintf(sBuf, MAX_PATH, L"%s.%s.%d\\CLSID", sProgram, sComponent, nVersion);
+ wchar_t sCurCLSID[nGUIDlen];
+ HRESULT hr = RegRead(HKEY_CLASSES_ROOT, sBuf, L"", sCurCLSID, nGUIDlen);
+ if (FAILED(hr))
+ return hr;
+ if (wcsncmp(sCurCLSID, m_sCLSID, nGUIDlen) != 0)
+ {
+ // The ProgID points to a different CLSID; most probably it's intercepted
+ // by a different application, so don't remove it
+ return S_FALSE;
+ }
+ RegDel(HKEY_CLASSES_ROOT, sBuf);
+ swprintf(sBuf, MAX_PATH, L"%s.%s.%d", sProgram, sComponent, nVersion);
+ hr = RegDel(HKEY_CLASSES_ROOT, sBuf);
+
+ wchar_t sBufKey[MAX_PATH];
+ swprintf(sBufKey, MAX_PATH, L"%s.%s\\CurVer", sProgram, sComponent);
+ wchar_t sBufVal[MAX_PATH];
+ if (SUCCEEDED(RegRead(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal, MAX_PATH)) && (wcsncmp(sBufVal, sBuf, MAX_PATH) == 0))
+ {
+ // Only unreg default if this version is current default
+ RegDel(HKEY_CLASSES_ROOT, sBufKey);
+ swprintf(sBuf, MAX_PATH, L"%s.%s", sProgram, sComponent);
+ HRESULT hr1 = RegDel(HKEY_CLASSES_ROOT, sBuf);
+ // Always return a failure result if we failed somewhere
+ if (FAILED(hr1))
+ hr = hr1;
+ }
+ return hr;
+}
+
+HRESULT Registrar::UnRegisterProgIDs(const wchar_t* sProgram, const wchar_t* sComponent,
+ std::initializer_list<int> aVersions)
+{
+ HRESULT hr = S_OK;
+ // Try all ProgIDs regardless of error, but make sure to return failure result if some failed
+ for (int nVersion : aVersions)
+ {
+ HRESULT hrLast = UnRegisterProgID(sProgram, sComponent, nVersion);
+ if (SUCCEEDED(hr))
+ hr = hrLast;
+ }
+ return hr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */