[SHELL32]
authorThomas Faber <thomas.faber@reactos.org>
Sat, 20 Jun 2015 16:54:52 +0000 (16:54 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Sat, 20 Jun 2015 16:54:52 +0000 (16:54 +0000)
- Introduce a CComCreatorSingleton class and use it for CDesktopFolder. Multiple calls to SHGetDesktopFolder will now return the same instance, which provides a massive speedup in many shell operations.
CORE-9839

svn path=/trunk/; revision=68210

reactos/dll/win32/shell32/folders/CDesktopFolder.cpp
reactos/dll/win32/shell32/folders/CDesktopFolder.h
reactos/dll/win32/shell32/shell32.cpp
reactos/include/reactos/shellutils.h

index 08ae19d..9ba5121 100644 (file)
@@ -287,6 +287,7 @@ CDesktopFolder::CDesktopFolder() :
 
 CDesktopFolder::~CDesktopFolder()
 {
+    ASSERT(_CreatorClass::IsTerminated());
 }
 
 HRESULT WINAPI CDesktopFolder::FinalConstruct()
index 27ff584..e1c6ad9 100644 (file)
@@ -34,7 +34,7 @@ class CDesktopFolder :
         /* both paths are parsible from the desktop */
         LPWSTR sPathTarget;     /* complete path to target used for enumeration and ChangeNotify */
         LPITEMIDLIST pidlRoot;  /* absolute pidl */
-        
+
         virtual HRESULT WINAPI _GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut);
 
     public:
@@ -79,7 +79,7 @@ class CDesktopFolder :
         virtual HRESULT WINAPI CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, BOOL bCopy);
 
         DECLARE_REGISTRY_RESOURCEID(IDR_SHELLDESKTOP)
-        DECLARE_NOT_AGGREGATABLE(CDesktopFolder)
+        DECLARE_SINGLETON_NOT_AGGREGATABLE(CDesktopFolder)
 
         DECLARE_PROTECT_FINAL_CONSTRUCT()
 
index 2a775e5..84af50d 100644 (file)
@@ -149,6 +149,11 @@ HRESULT WINAPI SHCreateDefClassObject(
 class CShell32Module : public CComModule
 {
 public:
+    void Term()
+    {
+        CComCreatorSingleton< ATL::CComObject< CDesktopFolder > >::Term();
+        CComModule::Term();
+    }
 };
 
 
index 7e70a5a..ada3152 100644 (file)
@@ -41,6 +41,58 @@ extern "C" {
 } /* extern "C" */
 #endif /* defined(__cplusplus) */
 
+#ifdef __cplusplus
+template <typename T>
+class CComCreatorSingleton
+{
+private:
+    static IUnknown *s_pInstance;
+    static bool s_IsTerminated;
+
+public:
+    static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
+    {
+        *ppv = NULL;
+        if (pv != NULL)
+            return CLASS_E_NOAGGREGATION;
+        if (!s_pInstance)
+        {
+            PVOID pObj;
+            HRESULT hr;
+            hr = ATL::CComCreator< T >::CreateInstance(NULL, IID_IUnknown, &pObj);
+            if (FAILED(hr))
+                return hr;
+            if (InterlockedCompareExchangePointer((PVOID *)&s_pInstance, pObj, NULL))
+                static_cast<IUnknown *>(pObj)->Release();
+        }
+        return s_pInstance->QueryInterface(riid, ppv);
+    }
+    static void Term()
+    {
+        ULONG ref;
+        ASSERT(!s_IsTerminated);
+        s_IsTerminated = true;
+        if (s_pInstance)
+        {
+            ref = s_pInstance->Release();
+            ASSERT(ref == 0);
+            s_pInstance = NULL;
+        }
+    }
+    static bool IsTerminated() { return s_IsTerminated; }
+};
+
+template <typename T>
+IUnknown *CComCreatorSingleton<T>::s_pInstance = NULL;
+
+template <typename T>
+bool CComCreatorSingleton<T>::s_IsTerminated = false;
+
+#define DECLARE_SINGLETON_NOT_AGGREGATABLE(x)                                   \
+public:                                                                         \
+    typedef CComCreatorSingleton< ATL::CComObject<x> > _CreatorClass;
+#endif
+
 #ifdef __cplusplus
 template <class Base>
 class CComDebugObject : public Base