http://bugs.winehq.org/show_bug.cgi?id=8130
------- Additional Comments From focht@gmx.net 2007-13-05 14:11 ------- Hello,
--- quote --- Perhaps this is just a race that is rarely hit on Windows because of different code in ole32 or perhaps there is something when running on Windows that keeps the DLL loaded.
I think the patch that apparantly caused the regression is correct though. --- quote ---
Sorry, but this is neither a race condition nor "bad" code. I wrote a simple test client (http://bugs.winehq.org/show_bug.cgi?id=8159) to simulate the problem.
Basically said: You cant unload ole servers when destroying apartment without looking at the ole server refcount itself. A client *may* still hold and use a reference. That's an information only the ole server has.
One solution would be to ask the server in COMPOBJ_DllList_ReleaseRef(). Beware: This is meant as quick fix, non-intrusive as possible (but working).
--- snip dlls/ole32/compobj.c --- static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry) { if (!InterlockedDecrement(&entry->refs)) { EnterCriticalSection(&csOpenDllList); list_remove(&entry->entry); LeaveCriticalSection(&csOpenDllList);
if( entry->DllCanUnloadNow() == S_OK) { TRACE("freeing %p\n", entry->library); FreeLibrary(entry->library); } else { WARN("unload skipped, client still holds refs to %s (%p)\n", debugstr_w(entry->library_name), entry->library); } HeapFree(GetProcessHeap(), 0, entry->library_name); HeapFree(GetProcessHeap(), 0, entry); } } --- snip dlls/ole32/compobj.c ---
Though the general problem remains: with the last apartment data/list (module entries) gone, there is no way to free com servers thereafter (except if the client forces creation/destruction of apartment again with all interface refcounts released) To overcome this problem, ole server data structures which are used to track lifetime have to be managed across apartments (e.g. at global scope).
Regards