summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/inc/spsupp/COMOpenDocuments.hpp1
-rw-r--r--shell/inc/spsupp/COMRefCounted.hpp7
-rw-r--r--shell/inc/spsupp/registrar.hpp21
-rw-r--r--shell/source/win32/spsupp/COMOpenDocuments.cxx55
-rw-r--r--shell/source/win32/spsupp/registrar.cxx281
-rw-r--r--shell/source/win32/spsupp/spsupp.def1
-rw-r--r--shell/source/win32/spsupp/spsuppServ.cxx35
7 files changed, 243 insertions, 158 deletions
diff --git a/shell/inc/spsupp/COMOpenDocuments.hpp b/shell/inc/spsupp/COMOpenDocuments.hpp
index a0f733e16f6d..e6c1f22c59e4 100644
--- a/shell/inc/spsupp/COMOpenDocuments.hpp
+++ b/shell/inc/spsupp/COMOpenDocuments.hpp
@@ -213,7 +213,6 @@ private:
static long m_nObjCount;
static ITypeInfo* m_pTypeInfo;
- static wchar_t m_szLOPath[MAX_PATH];
COMObjectSafety m_aObjectSafety;
};
diff --git a/shell/inc/spsupp/COMRefCounted.hpp b/shell/inc/spsupp/COMRefCounted.hpp
index 230f6c8da517..9647db2fb0aa 100644
--- a/shell/inc/spsupp/COMRefCounted.hpp
+++ b/shell/inc/spsupp/COMRefCounted.hpp
@@ -11,6 +11,7 @@
#define INCLUDED_SHELL_INC_SPSUPP_COMREFCOUNTED_HPP
#include "objbase.h"
+#include "assert.h"
template <class Interface>
class COMRefCounted : public Interface
@@ -28,9 +29,13 @@ public:
ULONG STDMETHODCALLTYPE Release() override
{
+ assert(m_nRef > 0);
if (::InterlockedDecrement(&m_nRef) == 0)
+ {
delete this;
- return (m_nRef > 0) ? static_cast<ULONG>(m_nRef) : 0;
+ return 0;
+ }
+ return static_cast<ULONG>(m_nRef);
}
private:
diff --git a/shell/inc/spsupp/registrar.hpp b/shell/inc/spsupp/registrar.hpp
index ed41c4d04003..21f0c22d9688 100644
--- a/shell/inc/spsupp/registrar.hpp
+++ b/shell/inc/spsupp/registrar.hpp
@@ -12,14 +12,23 @@
#include "windows.h"
-namespace Registrar {
- HRESULT RegisterObject(REFIID riidCLSID,
- REFIID riidTypeLib,
+class Registrar {
+public:
+ explicit Registrar(REFIID riidCLSID);
+ HRESULT RegisterObject(REFIID riidTypeLib,
const wchar_t* sProgram,
const wchar_t* sComponent,
- const wchar_t* Path);
- HRESULT UnRegisterObject(REFIID riidCLSID, const wchar_t* LibId, const wchar_t* ClassId);
-}
+ int nVersion,
+ const wchar_t* Path,
+ bool bSetDefault);
+ HRESULT UnRegisterObject(const wchar_t* sProgram, const wchar_t* sComponent, int nVersion);
+ HRESULT RegisterProgID(const wchar_t* sProgram, const wchar_t* sComponent, int nVersion, bool bSetDefault);
+ HRESULT UnRegisterProgID(const wchar_t* sProgram, const wchar_t* sComponent, int nVersion);
+private:
+ static const size_t nGUIDlen = 40;
+ wchar_t m_sCLSID[nGUIDlen];
+ HRESULT m_ConstructionResult;
+};
#endif
diff --git a/shell/source/win32/spsupp/COMOpenDocuments.cxx b/shell/source/win32/spsupp/COMOpenDocuments.cxx
index f9e5a4bd0340..ece3ba82f2ad 100644
--- a/shell/source/win32/spsupp/COMOpenDocuments.cxx
+++ b/shell/source/win32/spsupp/COMOpenDocuments.cxx
@@ -29,14 +29,24 @@ bool SecurityWarning(const wchar_t* sProgram, const wchar_t* sDocument)
}
// Returns S_OK if successful
-HRESULT LOStart(wchar_t* sCommandLine)
+HRESULT LOStart(const wchar_t* sModeArg, const wchar_t* sFilePath, bool bDoSecurityWarning)
{
+ const wchar_t* sProgram = GetLOPath();
+ if (bDoSecurityWarning && !SecurityWarning(sProgram, sFilePath))
+ {
+ // Return success to avoid downloading in browser
+ return S_OK;
+ }
+
STARTUPINFOW si;
std::memset(&si, 0, sizeof si);
si.cb = sizeof si;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi = {};
+ const size_t cchCommandLine = 32768;
+ wchar_t sCommandLine[cchCommandLine];
+ swprintf(sCommandLine, cchCommandLine, L"\"%s\" %s \"%s\"", sProgram, sModeArg, sFilePath);
if (CreateProcessW(nullptr, sCommandLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi) == FALSE)
{
DWORD dwError = GetLastError();
@@ -133,7 +143,6 @@ HRESULT STDMETHODCALLTYPE COMOpenDocuments::COMObjectSafety::SetInterfaceSafetyO
long COMOpenDocuments::m_nObjCount = 0;
ITypeInfo* COMOpenDocuments::m_pTypeInfo = nullptr;
-wchar_t COMOpenDocuments::m_szLOPath[MAX_PATH] = {0};
COMOpenDocuments::COMOpenDocuments()
: m_aObjectSafety(this)
@@ -299,19 +308,7 @@ STDMETHODIMP COMOpenDocuments::CreateNewDocument2(
VARIANT_BOOL* pbResult) // true if the document creation succeeds; otherwise false
{
// TODO: resolve the program from varProgID (nullptr -> default?)
- const wchar_t* sProgram = GetLOPath();
- if (m_aObjectSafety.GetSafe_forUntrustedCaller() || m_aObjectSafety.GetSafe_forUntrustedData())
- {
- if (!SecurityWarning(sProgram, bstrTemplateLocation))
- {
- // Set result to true and return success to avoid downloading in browser
- *pbResult = TRUE;
- return S_OK;
- }
- }
- wchar_t sCommandLine[32768];
- swprintf(sCommandLine, sizeof(sCommandLine) / sizeof(*sCommandLine), L"\"%s\" -n \"%s\"", sProgram, bstrTemplateLocation);
- HRESULT hr = LOStart(sCommandLine);
+ HRESULT hr = LOStart(L"-n", bstrTemplateLocation, m_aObjectSafety.GetSafe_forUntrustedCaller() || m_aObjectSafety.GetSafe_forUntrustedData());
*pbResult = VARIANT_BOOL(SUCCEEDED(hr));
return hr;
}
@@ -349,19 +346,7 @@ STDMETHODIMP COMOpenDocuments::ViewDocument3(
VARIANT_BOOL *pbResult) // true if the document was successfully opened; otherwise false
{
// TODO: resolve the program from varProgID (nullptr -> default?)
- const wchar_t* sProgram = GetLOPath();
- if (m_aObjectSafety.GetSafe_forUntrustedCaller() || m_aObjectSafety.GetSafe_forUntrustedData())
- {
- if (!SecurityWarning(sProgram, bstrDocumentLocation))
- {
- // Set result to true and return success to avoid downloading in browser
- *pbResult = TRUE;
- return S_OK;
- }
- }
- wchar_t sCommandLine[32768];
- swprintf(sCommandLine, sizeof(sCommandLine) / sizeof(*sCommandLine), L"\"%s\" --view \"%s\"", sProgram, bstrDocumentLocation);
- HRESULT hr = LOStart(sCommandLine);
+ HRESULT hr = LOStart(L"--view", bstrDocumentLocation, m_aObjectSafety.GetSafe_forUntrustedCaller() || m_aObjectSafety.GetSafe_forUntrustedData());
*pbResult = VARIANT_BOOL(SUCCEEDED(hr));
return hr;
}
@@ -423,19 +408,7 @@ STDMETHODIMP COMOpenDocuments::EditDocument3(
VARIANT_BOOL *pbResult) // true if the document was successfully opened; otherwise false
{
// TODO: resolve the program from varProgID (nullptr -> default?)
- const wchar_t* sProgram = GetLOPath();
- if (m_aObjectSafety.GetSafe_forUntrustedCaller() || m_aObjectSafety.GetSafe_forUntrustedData())
- {
- if (!SecurityWarning(sProgram, bstrDocumentLocation))
- {
- // Set result to true and return success to avoid downloading in browser
- *pbResult = TRUE;
- return S_OK;
- }
- }
- wchar_t sCommandLine[32768];
- swprintf(sCommandLine, sizeof(sCommandLine) / sizeof(*sCommandLine), L"\"%s\" -o \"%s\"", sProgram, bstrDocumentLocation);
- HRESULT hr = LOStart(sCommandLine);
+ HRESULT hr = LOStart(L"-o", bstrDocumentLocation, m_aObjectSafety.GetSafe_forUntrustedCaller() || m_aObjectSafety.GetSafe_forUntrustedData());
*pbResult = VARIANT_BOOL(SUCCEEDED(hr));
return hr;
}
diff --git a/shell/source/win32/spsupp/registrar.cxx b/shell/source/win32/spsupp/registrar.cxx
index 2d182cb7b85f..5ece3fcdd2d8 100644
--- a/shell/source/win32/spsupp/registrar.cxx
+++ b/shell/source/win32/spsupp/registrar.cxx
@@ -8,11 +8,18 @@
*/
#include "registrar.hpp"
-#include "stdio.h"
+#include "wchar.h"
namespace {
- HRESULT RegWrite(HKEY hRootKey, const wchar_t* subKey, const wchar_t* keyName, const wchar_t* keyValue, HKEY *hKeyResult = nullptr)
+ HRESULT RegRead(HKEY hRootKey, const wchar_t* subKey, const wchar_t* valName, wchar_t* valData, size_t cchData)
+ {
+ DWORD cbData = cchData * sizeof(valData[0]);
+ long iRetVal = RegGetValue(hRootKey, subKey, valName, RRF_RT_REG_SZ, nullptr, valData, &cbData);
+ 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(
@@ -28,10 +35,10 @@ namespace {
if (iRetVal != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(iRetVal);
- if (keyValue)
+ if (valData)
{
- DWORD cbData = static_cast<DWORD>(wcslen(keyValue)*sizeof(keyValue[0]));
- iRetVal = RegSetValueExW(hKey, keyName, 0, REG_SZ, reinterpret_cast<const BYTE *>(keyValue), cbData);
+ 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))
@@ -48,126 +55,186 @@ namespace {
return HRESULT_FROM_WIN32(iRetVal);
}
- const int nGUIDlen = 40;
-
}
-namespace Registrar {
+// see http://stackoverflow.com/questions/284619
+// see https://msdn.microsoft.com/en-us/library/ms691424
+// see https://msdn.microsoft.com/en-us/library/ms694514
- // 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 RegisterObject(REFIID riidCLSID,
- REFIID riidTypeLib,
- const wchar_t* sProgram,
- const wchar_t* sComponent,
- const wchar_t* Path)
+HRESULT Registrar::RegisterObject(REFIID riidTypeLib,
+ const wchar_t* sProgram,
+ const wchar_t* sComponent,
+ int nVersion,
+ const wchar_t* Path,
+ bool bSetDefault)
+{
+ 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;
{
- if (!wcslen(sComponent) || !wcslen(sProgram))
- return E_INVALIDARG;
-
- wchar_t sCLSID[nGUIDlen];
- if (::StringFromGUID2(riidCLSID, sCLSID, nGUIDlen) == 0)
- return E_UNEXPECTED;
-
- // 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}"
- // \MyLibrary.MyControl
- // \CLSID
- // (default) = "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
-
- wchar_t sBufKey[MAX_PATH];
- wchar_t sBufVal[MAX_PATH];
-
- // CLSID
- swprintf(sBufKey, MAX_PATH, L"CLSID\\%s", sCLSID);
- swprintf(sBufVal, MAX_PATH, L"%s %s Class", sProgram, sComponent);
- HKEY hKeyCLSID;
- HRESULT hr = RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sBufVal, &hKeyCLSID);
+ 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;
{
- 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);
+ HKeyGuard hKeyInProcServer32Guard(hKeyInprocServer32);
+ hr = RegWrite(hKeyInprocServer32, L"", L"ThreadingModel", L"Apartment");
if (FAILED(hr))
return hr;
}
// ProgID
- swprintf(sBufKey, MAX_PATH, L"%s.%s\\CLSID", sProgram, sComponent);
- return RegWrite(HKEY_CLASSES_ROOT, sBufKey, L"", sCLSID);
+ 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;
}
- HRESULT UnRegisterObject(REFIID riidCLSID, const wchar_t* LibId, const wchar_t* ClassId)
+ // ProgID
+ return RegisterProgID(sProgram, sComponent, nVersion, bSetDefault);
+}
+
+HRESULT Registrar::UnRegisterObject(const wchar_t* sProgram, const wchar_t* sComponent, int nVersion)
+{
+ if (FAILED(m_ConstructionResult))
+ return m_ConstructionResult;
+ // ProgID
+ UnRegisterProgID(sProgram, sComponent, nVersion);
+ // 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);
+ return RegDel(HKEY_CLASSES_ROOT, sBuf);
+}
+
+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)
{
- wchar_t sCLSID[nGUIDlen];
- wchar_t sBuf[MAX_PATH];
- if (::StringFromGUID2(riidCLSID, sCLSID, nGUIDlen) == 0)
- return E_UNEXPECTED;
- // ProgID
- swprintf(sBuf, MAX_PATH, L"%s.%s\\CLSID", LibId, ClassId);
- RegDel(HKEY_CLASSES_ROOT, sBuf);
- swprintf(sBuf, MAX_PATH, L"%s.%s", LibId, ClassId);
- RegDel(HKEY_CLASSES_ROOT, sBuf);
- // CLSID
- swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\InProcServer32", sCLSID);
- RegDel(HKEY_CLASSES_ROOT, sBuf);
- swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\ProgId", sCLSID);
- RegDel(HKEY_CLASSES_ROOT, sBuf);
- swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\Programmable", sCLSID);
- RegDel(HKEY_CLASSES_ROOT, sBuf);
- swprintf(sBuf, MAX_PATH, L"CLSID\\%s\\TypeLib", sCLSID);
- RegDel(HKEY_CLASSES_ROOT, sBuf);
- swprintf(sBuf, MAX_PATH, L"CLSID\\%s", sCLSID);
- return RegDel(HKEY_CLASSES_ROOT, sBuf);
+ 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::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;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/shell/source/win32/spsupp/spsupp.def b/shell/source/win32/spsupp/spsupp.def
index 2977aa21d125..f6828a3e8d43 100644
--- a/shell/source/win32/spsupp/spsupp.def
+++ b/shell/source/win32/spsupp/spsupp.def
@@ -5,3 +5,4 @@ EXPORTS
DllUnregisterServer PRIVATE
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
+ DllInstall PRIVATE
diff --git a/shell/source/win32/spsupp/spsuppServ.cxx b/shell/source/win32/spsupp/spsuppServ.cxx
index e5d1f432b2eb..bfa5710b46b8 100644
--- a/shell/source/win32/spsupp/spsuppServ.cxx
+++ b/shell/source/win32/spsupp/spsuppServ.cxx
@@ -20,6 +20,7 @@
#include <memory>
#include "olectl.h"
+#include "wchar.h"
#include "spsuppServ.hpp"
#include "spsuppClassFactory.hpp"
#include "COMOpenDocuments.hpp"
@@ -126,7 +127,7 @@ STDAPI DllRegisterServer(void)
if (FAILED(hr))
return hr;
- return Registrar::RegisterObject(CLSID_spsupp, LIBID_spsupp, L"LOSPSupport", L"OpenDocuments", szFile);
+ return Registrar(CLSID_spsupp).RegisterObject(LIBID_spsupp, L"LOSPSupport", L"OpenDocuments", 1, szFile, true);
}
STDAPI DllUnregisterServer(void)
@@ -146,7 +147,37 @@ STDAPI DllUnregisterServer(void)
if (FAILED(hr))
return hr;
- return Registrar::UnRegisterObject(CLSID_spsupp, L"LOSPSupport", L"OpenDocuments");
+ return Registrar(CLSID_spsupp).UnRegisterObject(L"LOSPSupport", L"OpenDocuments", 1);
+}
+
+// This is called when regsvr32.exe is called with "/i" flag
+// pszCmdLine is the string passed to "/i:<string>"
+// See https://msdn.microsoft.com/library/windows/desktop/bb759846
+STDAPI DllInstall(BOOL bInstall, _In_opt_ PCWSTR pszCmdLine)
+{
+ if (wcscmp(pszCmdLine, L"Substitute_OWSSUPP") == 0)
+ {
+ HRESULT hr;
+ Registrar registrar(CLSID_spsupp);
+ if (bInstall)
+ {
+ hr = registrar.RegisterProgID(L"SharePoint", L"OpenDocuments", 3, true);
+ if (SUCCEEDED(hr))
+ hr = registrar.RegisterProgID(L"SharePoint", L"OpenDocuments", 2, false);
+ if (SUCCEEDED(hr))
+ hr = registrar.RegisterProgID(L"SharePoint", L"OpenDocuments", 1, false);
+ }
+ else
+ {
+ // Try all ProgIDs regardless of error, but make sure to return failure result if at least one failed
+ hr = registrar.UnRegisterProgID(L"SharePoint", L"OpenDocuments", 1);
+ HRESULT hrLast;
+ hr = SUCCEEDED(hrLast = registrar.UnRegisterProgID(L"SharePoint", L"OpenDocuments", 2)) ? hr : hrLast;
+ hr = SUCCEEDED(hrLast = registrar.UnRegisterProgID(L"SharePoint", L"OpenDocuments", 3)) ? hr : hrLast;
+ }
+ return hr;
+ }
+ return E_INVALIDARG;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */