From 999766d31bc647fc02e2b2ca9ae2cfa73ebda4db Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Tue, 8 Feb 2005 16:51:22 +0000 Subject: [PATCH] - Implement CoDisconnectObject. - Change CoLockObjectExternal so that it does the correct action now and eliminate a fair few lines of now redundant code. - Rename OLE32_Dll{Register,Unregister}Server to Dll{Register,Unregister}Server. --- dlls/ole32/compobj.c | 280 ++++++++----------------------------------- dlls/ole32/compobj_private.h | 1 + dlls/ole32/ole32.spec | 4 +- dlls/ole32/regsvr.c | 4 +- dlls/ole32/stubmanager.c | 25 ++++ dlls/ole32/tests/marshal.c | 2 +- 6 files changed, 84 insertions(+), 232 deletions(-) diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index e3a457ea033..454f103a051 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -28,9 +28,6 @@ * * TODO list: (items bunched together depend on each other) * - * - Rewrite the CoLockObjectExternal code, it does totally the wrong - * thing currently (should be controlling the stub manager) - * * - Implement the service control manager (in rpcss) to keep track * of registered class objects: ISCM::ServerRegisterClsid et al * - Implement the OXID resolver so we don't need magic pipe names for @@ -87,7 +84,6 @@ typedef LPCSTR LPCOLESTR16; static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk); static void COM_RevokeAllClasses(void); -static void COM_ExternalLockFreeList(void); const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; @@ -712,9 +708,6 @@ void WINAPI CoUninitialize(void) /* This will free the loaded COM Dlls */ CoFreeAllLibraries(); - /* This will free list of external references to COM objects */ - COM_ExternalLockFreeList(); - /* This ensures we deal with any pending RPCs */ COM_FlushMessageQueue(); } @@ -748,7 +741,31 @@ void WINAPI CoUninitialize(void) */ HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) { - FIXME("(%p, %lx): stub - probably harmless\n",lpUnk,reserved); + HRESULT hr; + IMarshal *marshal; + APARTMENT *apt; + + TRACE("(%p, 0x%08lx)\n", lpUnk, reserved); + + hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal); + if (hr == S_OK) + { + hr = IMarshal_DisconnectObject(marshal, reserved); + IMarshal_Release(marshal); + return hr; + } + + apt = COM_CurrentApt(); + if (!apt) + return CO_E_NOTINITIALIZED; + + apartment_disconnect_object(apt, lpUnk); + + /* Note: native is pretty broken here because it just silently + * fails, without returning an appropriate error code if the object was + * not found, making apps think that the object was disconnected, when + * it actually wasn't */ + return S_OK; } @@ -1983,209 +2000,6 @@ static void COM_RevokeAllClasses() LeaveCriticalSection( &csRegisteredClassList ); } -/**************************************************************************** - * COM External Lock methods implementation - * - * This api provides a linked list to managed external references to - * COM objects. - * - * The public interface consists of three calls: - * COM_ExternalLockAddRef - * COM_ExternalLockRelease - * COM_ExternalLockFreeList - */ - -#define EL_END_OF_LIST 0 -#define EL_NOT_FOUND 0 - -/* - * Declaration of the static structure that manage the - * external lock to COM objects. - */ -typedef struct COM_ExternalLock COM_ExternalLock; -typedef struct COM_ExternalLockList COM_ExternalLockList; - -struct COM_ExternalLock -{ - IUnknown *pUnk; /* IUnknown referenced */ - ULONG uRefCount; /* external lock counter to IUnknown object*/ - COM_ExternalLock *next; /* Pointer to next element in list */ -}; - -struct COM_ExternalLockList -{ - COM_ExternalLock *head; /* head of list */ -}; - -/* - * Declaration and initialization of the static structure that manages - * the external lock to COM objects. - */ -static COM_ExternalLockList elList = { EL_END_OF_LIST }; - -/* - * Private methods used to managed the linked list - */ - - -static COM_ExternalLock* COM_ExternalLockLocate( - COM_ExternalLock *element, - IUnknown *pUnk); - -/**************************************************************************** - * Internal - Insert a new IUnknown* to the linked list - */ -static BOOL COM_ExternalLockInsert( - IUnknown *pUnk) -{ - COM_ExternalLock *newLock = NULL; - COM_ExternalLock *previousHead = NULL; - - /* - * Allocate space for the new storage object - */ - newLock = HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock)); - - if (newLock!=NULL) { - if ( elList.head == EL_END_OF_LIST ) { - elList.head = newLock; /* The list is empty */ - } else { - /* insert does it at the head */ - previousHead = elList.head; - elList.head = newLock; - } - - /* Set new list item data member */ - newLock->pUnk = pUnk; - newLock->uRefCount = 1; - newLock->next = previousHead; - - return TRUE; - } - return FALSE; -} - -/**************************************************************************** - * Internal - Method that removes an item from the linked list. - */ -static void COM_ExternalLockDelete( - COM_ExternalLock *itemList) -{ - COM_ExternalLock *current = elList.head; - - if ( current == itemList ) { - /* this section handles the deletion of the first node */ - elList.head = itemList->next; - HeapFree( GetProcessHeap(), 0, itemList); - } else { - do { - if ( current->next == itemList ){ /* We found the item to free */ - current->next = itemList->next; /* readjust the list pointers */ - HeapFree( GetProcessHeap(), 0, itemList); - break; - } - - /* Skip to the next item */ - current = current->next; - - } while ( current != EL_END_OF_LIST ); - } -} - -/**************************************************************************** - * Internal - Recursivity agent for IUnknownExternalLockList_Find - * - * NOTES: how long can the list be ?? (recursive!!!) - */ -static COM_ExternalLock* COM_ExternalLockLocate( COM_ExternalLock *element, IUnknown *pUnk) -{ - if ( element == EL_END_OF_LIST ) - return EL_NOT_FOUND; - else if ( element->pUnk == pUnk ) /* We found it */ - return element; - else /* Not the right guy, keep on looking */ - return COM_ExternalLockLocate( element->next, pUnk); -} - -/**************************************************************************** - * Public - Method that increments the count for a IUnknown* in the linked - * list. The item is inserted if not already in the list. - */ -static void COM_ExternalLockAddRef(IUnknown *pUnk) -{ - COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk); - - /* - * Add an external lock to the object. If it was already externally - * locked, just increase the reference count. If it was not. - * add the item to the list. - */ - if ( externalLock == EL_NOT_FOUND ) - COM_ExternalLockInsert(pUnk); - else - externalLock->uRefCount++; - - /* - * Add an internal lock to the object - */ - IUnknown_AddRef(pUnk); -} - -/**************************************************************************** - * Public - Method that decrements the count for a IUnknown* in the linked - * list. The item is removed from the list if its count end up at zero or if - * bRelAll is TRUE. - */ -static void COM_ExternalLockRelease( - IUnknown *pUnk, - BOOL bRelAll) -{ - COM_ExternalLock *externalLock = COM_ExternalLockLocate(elList.head, pUnk); - - if ( externalLock != EL_NOT_FOUND ) { - do { - externalLock->uRefCount--; /* release external locks */ - IUnknown_Release(pUnk); /* release local locks as well */ - - if ( bRelAll == FALSE ) break; /* perform single release */ - - } while ( externalLock->uRefCount > 0 ); - - if ( externalLock->uRefCount == 0 ) /* get rid of the list entry */ - COM_ExternalLockDelete(externalLock); - } -} -/**************************************************************************** - * Public - Method that frees the content of the list. - */ -static void COM_ExternalLockFreeList() -{ - COM_ExternalLock *head; - - head = elList.head; /* grab it by the head */ - while ( head != EL_END_OF_LIST ) { - COM_ExternalLockDelete(head); /* get rid of the head stuff */ - head = elList.head; /* get the new head... */ - } -} - -/**************************************************************************** - * Public - Method that dump the content of the list. - */ -void COM_ExternalLockDump() -{ - COM_ExternalLock *current = elList.head; - - DPRINTF("\nExternal lock list contains:\n"); - - while ( current != EL_END_OF_LIST ) { - DPRINTF( "\t%p with %lu references count.\n", current->pUnk, current->uRefCount); - - /* Skip to the next item */ - current = current->next; - } -} - /****************************************************************************** * CoLockObjectExternal [OLE32.@] * @@ -2203,28 +2017,40 @@ void COM_ExternalLockDump() * Failure: HRESULT code. */ HRESULT WINAPI CoLockObjectExternal( - LPUNKNOWN pUnk, /* */ - BOOL fLock, /* [in] do lock */ - BOOL fLastUnlockReleases) /* [in] unlock all */ + LPUNKNOWN pUnk, + BOOL fLock, + BOOL fLastUnlockReleases) { + struct stub_manager *stubmgr; + struct apartment *apt; + TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); - if (fLock) { - /* - * Increment the external lock coutner, COM_ExternalLockAddRef also - * increment the object's internal lock counter. - */ - COM_ExternalLockAddRef( pUnk); - } else { - /* - * Decrement the external lock coutner, COM_ExternalLockRelease also - * decrement the object's internal lock counter. - */ - COM_ExternalLockRelease( pUnk, fLastUnlockReleases); - } + apt = COM_CurrentApt(); + if (!apt) return CO_E_NOTINITIALIZED; + + stubmgr = get_stub_manager_from_object(apt, pUnk); + + if (stubmgr) + { + if (fLock) + stub_manager_ext_addref(stubmgr, 1); + else + stub_manager_ext_release(stubmgr, 1); + + stub_manager_int_release(stubmgr); return S_OK; + } + else + { + WARN("stub object not found %p\n", pUnk); + /* Note: native is pretty broken here because it just silently + * fails, without returning an appropriate error code, making apps + * think that the object was disconnected, when it actually wasn't */ + return S_OK; + } } /*********************************************************************** diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index aee74275fbd..2422509a736 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -185,6 +185,7 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs); struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, BOOL tablemarshal); struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid); struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object); +void apartment_disconnect_object(APARTMENT *apt, void *object); BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid); BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid); HRESULT register_ifstub(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags); diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index c9b4c986b61..0f8a9aa2068 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -92,8 +92,8 @@ @ stdcall DllDebugObjectRPCHook(long ptr) @ stdcall -private DllGetClassObject (ptr ptr ptr) OLE32_DllGetClassObject @ stub DllGetClassObjectWOW -@ stdcall -private DllRegisterServer() OLE32_DllRegisterServer -@ stdcall -private DllUnregisterServer() OLE32_DllUnregisterServer +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() @ stdcall DoDragDrop(ptr ptr long ptr) @ stub EnableHookObject @ stdcall FreePropVariantArray(long ptr) diff --git a/dlls/ole32/regsvr.c b/dlls/ole32/regsvr.c index 7fab1afcbf4..07918c77fdb 100644 --- a/dlls/ole32/regsvr.c +++ b/dlls/ole32/regsvr.c @@ -470,7 +470,7 @@ static struct regsvr_interface const interface_list[] = { /*********************************************************************** * DllRegisterServer (OLE32.@) */ -HRESULT WINAPI OLE32_DllRegisterServer() +HRESULT WINAPI DllRegisterServer() { HRESULT hr; @@ -485,7 +485,7 @@ HRESULT WINAPI OLE32_DllRegisterServer() /*********************************************************************** * DllUnregisterServer (OLE32.@) */ -HRESULT WINAPI OLE32_DllUnregisterServer() +HRESULT WINAPI DllUnregisterServer() { HRESULT hr; diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index 6b10ad0fe01..e66ab83611b 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -138,6 +138,31 @@ struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object) return result; } +/* removes the apartment reference to an object, destroying it when no other + * threads have a reference to it */ +void apartment_disconnect_object(APARTMENT *apt, void *object) +{ + int found = FALSE; + struct stub_manager *stubmgr; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH_ENTRY( stubmgr, &apt->stubmgrs, struct stub_manager, entry ) + { + if (stubmgr->object == object) + { + found = TRUE; + stub_manager_int_release(stubmgr); + break; + } + } + LeaveCriticalSection(&apt->cs); + + if (found) + TRACE("disconnect object %p\n", object); + else + WARN("couldn't find object %p\n", object); +} + /* gets the stub manager associated with an object id - caller must have * a reference to the apartment while a reference to the stub manager is held. * it must also call release on the stub manager when it is no longer needed */ diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index 63efd6117a2..95600fdce9b 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -834,7 +834,7 @@ static void test_disconnect_stub() CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0); - todo_wine { ok_no_locks(); } + ok_no_locks(); } /* tests failure case of a same-thread marshal and unmarshal twice */ -- 2.11.4.GIT