diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 5e731e84130..f9a91727026 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -31,6 +31,7 @@ * thing currently (should be controlling the stub manager) * * - Make the MTA dynamically allocated and refcounted + * - Free the ReservedForOle data in DllMain(THREAD_DETACH) * * - Implement the service control manager (in rpcss) to keep track * of registered class objects: ISCM::ServerRegisterClsid et al @@ -102,7 +103,7 @@ static void COM_ExternalLockFreeList(void); const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; APARTMENT MTA; -struct list apts = LIST_INIT( apts ); +static struct list apts = LIST_INIT( apts ); static CRITICAL_SECTION csApartment; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -304,21 +305,22 @@ DWORD COM_ApartmentRelease(struct apartment *apt) { DWORD ret; - EnterCriticalSection(&csApartment); - ret = InterlockedDecrement(&apt->refs); if (ret == 0) { TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); + EnterCriticalSection(&csApartment); + list_remove(&apt->entry); + LeaveCriticalSection(&csApartment); + MARSHAL_Disconnect_Proxies(apt); - list_remove(&apt->entry); if ((apt->model & COINIT_APARTMENTTHREADED) && apt->win) DestroyWindow(apt->win); if (!list_empty(&apt->stubmgrs)) { - FIXME("PANIC: Apartment being destroyed with outstanding stubs, what do we do now?\n"); + FIXME("Destroy outstanding stubs\n"); } if (apt->filter) IUnknown_Release(apt->filter); @@ -331,8 +333,6 @@ DWORD COM_ApartmentRelease(struct apartment *apt) apt = NULL; } - LeaveCriticalSection(&csApartment); - return ret; } @@ -545,20 +545,18 @@ HRESULT WINAPI CoInitializeEx( if (!(apt = COM_CurrentInfo()->apt)) { apt = COM_CreateApartment(dwCoInit); + if (!apt) return E_OUTOFMEMORY; } - else - { - InterlockedIncrement(&apt->refs); - } - - if (dwCoInit != apt->model) + else if (dwCoInit != apt->model) { /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine code then we are probably using the wrong threading model to implement that API. */ ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit); + COM_ApartmentRelease(apt); return RPC_E_CHANGED_MODE; } - + + COM_CurrentInfo()->inits++; return hr; } @@ -606,12 +604,26 @@ void COM_FlushMessageQueue(void) */ void WINAPI CoUninitialize(void) { + struct oletls * info = COM_CurrentInfo(); LONG lCOMRefCnt; TRACE("()\n"); - if (!COM_ApartmentRelease(COM_CurrentInfo()->apt)) - COM_CurrentInfo()->apt = NULL; + /* will only happen on OOM */ + if (!info) return; + + /* sanity check */ + if (!info->inits) + { + ERR("Mismatched CoUninitialize\n"); + return; + } + + if (!--info->inits) + { + COM_ApartmentRelease(info->apt); + info->apt = NULL; + } /* * Decrease the reference count. diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index bf95482d2b9..e45a54cdf36 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -198,14 +198,13 @@ APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref); DWORD COM_ApartmentAddRef(struct apartment *apt); DWORD COM_ApartmentRelease(struct apartment *apt); -extern CRITICAL_SECTION csApartment; - /* this is what is stored in TEB->ReservedForOle */ struct oletls { struct apartment *apt; IErrorInfo *errorinfo; /* see errorinfo.c */ IUnknown *state; /* see CoSetState */ + DWORD inits; /* number of times CoInitializeEx called */ }; /*