shell32: Make SHGetDesktopFolder use a cached instance of IShellFolder. Take 2

Dmitry Timoshkov dmitry at codeweavers.com
Thu Jun 21 09:50:55 CDT 2007


"Alexandre Julliard" <julliard at winehq.org> wrote:

> You need to initialize the object completely before storing it as
> cached entry.

oops, sorry about that.

---
An application I'm working on at start up calls SHGetDesktopFolder huge amount
of time, and on my system its start up time is 55 seconds. A simple test shows
(attached) that Windows doesn't create IShellFolder over and over again, but
uses a cached interface. This patch reduces start up time of my application
to 35 seconds.

Changelog:
    shell32: Make SHGetDesktopFolder use a cached instance of IShellFolder.

---
 dlls/shell32/shfldr_desktop.c |   63 +++++++++++++++++++----------------------
 1 files changed, 29 insertions(+), 34 deletions(-)

diff --git a/dlls/shell32/shfldr_desktop.c b/dlls/shell32/shfldr_desktop.c
index 3fee311..81aaccf 100644
--- a/dlls/shell32/shfldr_desktop.c
+++ b/dlls/shell32/shfldr_desktop.c
@@ -117,30 +117,12 @@ static HRESULT WINAPI ISF_Desktop_fnQueryInterface(
 
 static ULONG WINAPI ISF_Desktop_fnAddRef (IShellFolder2 * iface)
 {
-    IGenericSFImpl *This = (IGenericSFImpl *)iface;
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE ("(%p)->(count=%u)\n", This, refCount - 1);
-
-    return refCount;
+    return 2; /* non-heap based object */
 }
 
 static ULONG WINAPI ISF_Desktop_fnRelease (IShellFolder2 * iface)
 {
-    IGenericSFImpl *This = (IGenericSFImpl *)iface;
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE ("(%p)->(count=%u)\n", This, refCount + 1);
-
-    if (!refCount)
-    {
-        TRACE ("-- destroying IShellFolder(%p)\n", This);
-        SHFree (This->pidlRoot);
-        SHFree (This->sPathTarget);
-        LocalFree ((HLOCAL) This);
-        return 0;
-    }
-    return refCount;
+    return 1; /* non-heap based object */
 }
 
 /**************************************************************************
@@ -865,7 +847,7 @@ static const IShellFolder2Vtbl vt_MCFldr_ShellFolder2 =
 HRESULT WINAPI ISF_Desktop_Constructor (
                 IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
 {
-    IGenericSFImpl *sf;
+    static IGenericSFImpl *cached_sf;
     WCHAR szMyPath[MAX_PATH];
     HRESULT r;
 
@@ -876,26 +858,39 @@ HRESULT WINAPI ISF_Desktop_Constructor (
     if (pUnkOuter)
         return CLASS_E_NOAGGREGATION;
 
-    if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
-        return E_UNEXPECTED;
+    if (!cached_sf)
+    {
+        IGenericSFImpl *sf;
 
-    sf = LocalAlloc( LMEM_ZEROINIT, sizeof (IGenericSFImpl) );
-    if (!sf)
-        return E_OUTOFMEMORY;
+        if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
+            return E_UNEXPECTED;
+
+        sf = LocalAlloc( LMEM_ZEROINIT, sizeof (IGenericSFImpl) );
+        if (!sf)
+            return E_OUTOFMEMORY;
+
+        sf->ref = 0;
+        sf->lpVtbl = &vt_MCFldr_ShellFolder2;
+        sf->pidlRoot = _ILCreateDesktop();    /* my qualified pidl */
+        sf->sPathTarget = SHAlloc( (lstrlenW(szMyPath) + 1)*sizeof(WCHAR) );
+        lstrcpyW( sf->sPathTarget, szMyPath );
 
-    sf->ref = 0;
-    sf->lpVtbl = &vt_MCFldr_ShellFolder2;
-    sf->pidlRoot = _ILCreateDesktop();    /* my qualified pidl */
-    sf->sPathTarget = SHAlloc( (lstrlenW(szMyPath) + 1)*sizeof(WCHAR) );
-    lstrcpyW( sf->sPathTarget, szMyPath );
+        if (InterlockedCompareExchangePointer((void *)&cached_sf, sf, NULL) != NULL)
+        {
+            /* some other thread already been here */
+            SHFree( sf->pidlRoot );
+            SHFree( sf->sPathTarget );
+            LocalFree( sf );
+        }
+    }
 
-    r = IUnknown_QueryInterface( _IUnknown_(sf), riid, ppv );
+    r = IUnknown_QueryInterface( _IUnknown_(cached_sf), riid, ppv );
     if (!SUCCEEDED (r))
     {
-        IUnknown_Release( _IUnknown_(sf) );
+        IUnknown_Release( _IUnknown_(cached_sf) );
         return r;
     }
 
-    TRACE ("--(%p)\n", sf);
+    TRACE ("--(%p)\n", cached_sf);
     return S_OK;
 }
-- 
1.5.1.6






More information about the wine-patches mailing list