diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 662b42a8dba..e0bcea8bad2 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -181,6 +181,7 @@ struct apartment_loaded_dll { struct list entry; OpenDll *dll; + DWORD unload_time; }; static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ', @@ -188,7 +189,7 @@ static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r',' static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, REFCLSID rclsid, REFIID riid, void **ppv); -static void apartment_freeunusedlibraries(struct apartment *apt); +static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay); static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret); static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name); @@ -403,7 +404,7 @@ DWORD apartment_release(struct apartment *apt) if (apt->filter) IUnknown_Release(apt->filter); /* free as many unused libraries as possible... */ - apartment_freeunusedlibraries(apt); + apartment_freeunusedlibraries(apt, 0); /* ... and free the memory for the apartment loaded dll entry and * release the dll list reference without freeing the library for the @@ -779,6 +780,7 @@ static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, hr = E_OUTOFMEMORY; if (SUCCEEDED(hr)) { + apartment_loaded_dll->unload_time = 0; hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll ); if (FAILED(hr)) HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); @@ -805,7 +807,7 @@ static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, return hr; } -static void apartment_freeunusedlibraries(struct apartment *apt) +static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) { struct apartment_loaded_dll *entry, *next; EnterCriticalSection(&apt->cs); @@ -813,10 +815,17 @@ static void apartment_freeunusedlibraries(struct apartment *apt) { if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK)) { - list_remove(&entry->entry); - COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE); - HeapFree(GetProcessHeap(), 0, entry); + if (!delay || (entry->unload_time && (entry->unload_time < GetTickCount()))) + { + list_remove(&entry->entry); + COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE); + HeapFree(GetProcessHeap(), 0, entry); + } + else + entry->unload_time = GetTickCount() + delay; } + else if (entry->unload_time) + entry->unload_time = 0; } LeaveCriticalSection(&apt->cs); } @@ -2482,6 +2491,42 @@ void WINAPI CoFreeAllLibraries(void) /* NOP */ } +/*********************************************************************** + * CoFreeUnusedLibrariesEx [OLE32.@] + * + * Frees any previously unused libraries whose delay has expired and marks + * currently unused libraries for unloading. Unused are identified as those that + * return S_OK from their DllCanUnloadNow function. + * + * PARAMS + * dwUnloadDelay [I] Unload delay in milliseconds. + * dwReserved [I] Reserved. Set to 0. + * + * RETURNS + * Nothing. + * + * SEE ALSO + * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary + */ +void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved) +{ + struct apartment *apt = COM_CurrentApt(); + if (!apt) + { + ERR("apartment not initialised\n"); + return; + } + + if (dwUnloadDelay == INFINITE) + { + if (apt->multi_threaded) + dwUnloadDelay = 10 * 60 * 1000; /* 10 minutes */ + else + dwUnloadDelay = 0; + } + + apartment_freeunusedlibraries(apt, dwUnloadDelay); +} /*********************************************************************** * CoFreeUnusedLibraries [OLE32.@] @@ -2498,14 +2543,7 @@ void WINAPI CoFreeAllLibraries(void) */ void WINAPI CoFreeUnusedLibraries(void) { - struct apartment *apt = COM_CurrentApt(); - if (!apt) - { - ERR("apartment not initialised\n"); - return; - } - - apartment_freeunusedlibraries(apt); + CoFreeUnusedLibrariesEx(INFINITE, 0); } /*********************************************************************** diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index e018b0fbe50..0b6299554d9 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -20,6 +20,7 @@ @ stdcall CoFreeAllLibraries() @ stdcall CoFreeLibrary(long) @ stdcall CoFreeUnusedLibraries() +@ stdcall CoFreeUnusedLibrariesEx(long long) @ stdcall CoGetCallContext(ptr ptr) @ stub CoGetCallerTID @ stdcall CoGetClassObject(ptr long ptr ptr ptr) diff --git a/include/objbase.h b/include/objbase.h index 4d94c0509cf..33fe4c9df89 100644 --- a/include/objbase.h +++ b/include/objbase.h @@ -329,6 +329,7 @@ HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree); void WINAPI CoFreeAllLibraries(void); void WINAPI CoFreeLibrary(HINSTANCE hLibrary); void WINAPI CoFreeUnusedLibraries(void); +void WINAPI CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved); HRESULT WINAPI CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv); HRESULT WINAPI CoCreateInstanceEx(REFCLSID rclsid,