shell32: Make SHGetDesktopFolder use a cached instance of IShellFolder

Dmitry Timoshkov dmitry at codeweavers.com
Wed Jun 20 09:06:56 CDT 2007


Hello,

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.

---
#include <stdio.h>

#define COBJMACROS

#include <windows.h>
#include <shlobj.h>

int main(void)
{
    HRESULT hres;
    IShellFolder *sf = NULL;
    LONG ref;

    hres = SHGetDesktopFolder(&sf);
    if (hres || !sf)
    {
        printf("SHGetDesktopFolder error %lx\n", hres);
        return -1;
    }

    ref = IShellFolder_AddRef(sf);
    printf("ref count %ld\n", ref);
    ref = IShellFolder_AddRef(sf);
    printf("ref count %ld\n", ref);
    ref = IShellFolder_AddRef(sf);
    printf("ref count %ld\n", ref);
    ref = IShellFolder_Release(sf);
    printf("ref count %ld\n", ref);
    ref = IShellFolder_Release(sf);
    printf("ref count %ld\n", ref);
    ref = IShellFolder_Release(sf);
    printf("ref count %ld\n", ref);

    return 0;
}

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

diff --git a/dlls/shell32/shfldr_desktop.c b/dlls/shell32/shfldr_desktop.c
index 3fee311..6359083 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,36 @@ 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->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 = LocalAlloc( LMEM_ZEROINIT, sizeof (IGenericSFImpl) );
+        if (!sf)
+            return E_OUTOFMEMORY;
+
+        if (InterlockedCompareExchangePointer((void *)&cached_sf, sf, NULL) != NULL)
+            LocalFree( sf ); /* some other thread already been here */
+        else
+        {
+            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 );
+        }
+    }
 
-    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