[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-5.3' - shell/inc shell/source

Mike Kaganski mike.kaganski at collabora.com
Tue Apr 11 13:39:02 UTC 2017


 shell/inc/spsupp/COMOpenDocuments.hpp          |    1 
 shell/inc/spsupp/COMRefCounted.hpp             |    7 
 shell/inc/spsupp/registrar.hpp                 |   21 +
 shell/source/win32/spsupp/COMOpenDocuments.cxx |   65 +----
 shell/source/win32/spsupp/registrar.cxx        |  281 +++++++++++++++----------
 shell/source/win32/spsupp/spsupp.def           |    1 
 shell/source/win32/spsupp/spsuppServ.cxx       |   35 ++-
 7 files changed, 249 insertions(+), 162 deletions(-)

New commits:
commit 8d60397310935d5d6d848314bd1faacb586d886b
Author: Mike Kaganski <mike.kaganski at collabora.com>
Date:   Mon Apr 10 22:21:57 2017 +0300

    tdf#103058: allow optional registration for MS ProgIDs
    
    To allow in-place replacement of OWSSUPP.dll, we need to be able
    to handle the same ProgIDs that it handles, namely:
    SharePoint.OpenDocuments and its versions. This allows to use
    the SharePoint integration capabilities of LO without the need to
    reconfigure SharePoint server's DOCICON.xml (the system would
    start the component with same name as MS Office uses).
    
    But this cannot be the default mode, since if MS Office is installed
    on the same system, we would hijack the registration, that could be
    undesirable.
    
    So, this commit adds an option to use
    regsvr32 [/u] /i:Substitute_OWSSUPP path        o\spsupp.dll
    to also [un]register SharePoint.OpenDocuments in addition to normal
    LOSPSupport.OpenDocuments.
    
    Reviewed-on: https://gerrit.libreoffice.org/36389
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    
    (Cherry-picked from commit 88829fd914105a0837ee41d3f00f9178228c19cf)
    
    Change-Id: Icc284f9aa8f97ecf04594dd55b99bc1e3d20740d
    Reviewed-on: https://gerrit.libreoffice.org/36411
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    Tested-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/shell/inc/spsupp/COMOpenDocuments.hpp b/shell/inc/spsupp/COMOpenDocuments.hpp
index 1b2a52999ead..35df90073628 100644
--- a/shell/inc/spsupp/COMOpenDocuments.hpp
+++ b/shell/inc/spsupp/COMOpenDocuments.hpp
@@ -206,7 +206,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 1a60ed372300..d9b9ab87455d 100644
--- a/shell/inc/spsupp/COMRefCounted.hpp
+++ b/shell/inc/spsupp/COMRefCounted.hpp
@@ -11,6 +11,7 @@
 #define _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 00b230e5c624..003fe59f24fa 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 b9d24405aa4f..5f3af74a8be0 100644
--- a/shell/source/win32/spsupp/COMOpenDocuments.cxx
+++ b/shell/source/win32/spsupp/COMOpenDocuments.cxx
@@ -25,12 +25,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)
 {
-    STARTUPINFOW si = { sizeof(si) };
+    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();
@@ -127,7 +139,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)
@@ -293,20 +304,8 @@ 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);
-    *pbResult = SUCCEEDED(hr);
+    HRESULT hr = LOStart(L"-n", bstrTemplateLocation, m_aObjectSafety.GetSafe_forUntrustedCaller() || m_aObjectSafety.GetSafe_forUntrustedData());
+    *pbResult = VARIANT_BOOL(SUCCEEDED(hr));
     return hr;
 }
 
@@ -343,20 +342,8 @@ 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);
-    *pbResult = SUCCEEDED(hr);
+    HRESULT hr = LOStart(L"--view", bstrDocumentLocation, m_aObjectSafety.GetSafe_forUntrustedCaller() || m_aObjectSafety.GetSafe_forUntrustedData());
+    *pbResult = VARIANT_BOOL(SUCCEEDED(hr));
     return hr;
 }
 
@@ -417,20 +404,8 @@ 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);
-    *pbResult = SUCCEEDED(hr);
+    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 c71ba10b9d78..979517951535 100644
--- a/shell/source/win32/spsupp/spsuppServ.cxx
+++ b/shell/source/win32/spsupp/spsuppServ.cxx
@@ -12,6 +12,7 @@
 
 #include <memory>
 #include "olectl.h"
+#include "wchar.h"
 #include "spsuppServ.hpp"
 #include "spsuppClassFactory.hpp"
 #include "COMOpenDocuments.hpp"
@@ -114,7 +115,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)
@@ -134,7 +135,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: */


More information about the Libreoffice-commits mailing list