- Implement CoDisconnectObject.
authorRobert Shearman <rob@codeweavers.com>
Tue, 8 Feb 2005 16:51:22 +0000 (16:51 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 8 Feb 2005 16:51:22 +0000 (16:51 +0000)
- 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
dlls/ole32/compobj_private.h
dlls/ole32/ole32.spec
dlls/ole32/regsvr.c
dlls/ole32/stubmanager.c
dlls/ole32/tests/marshal.c

index e3a457ea0336a8952dd2d7e93f2fc950f8e15269..454f103a0518cf1cdd7add2e694afdd2dc10b269 100644 (file)
@@ -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;
+    }
 }
 
 /***********************************************************************
index aee74275fbd37f3fc3c2cf1dbdfabc3382824bac..2422509a736e96db3f60752a2ca287c4a29a569c 100644 (file)
@@ -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);
index c9b4c986b618f77244051ace4e2389c7fd5efcb5..0f8a9aa20686794922c05e463f4b4c46925f1d51 100644 (file)
@@ -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)
index 7fab1afcbf4d1aa24e15b55362834aa9716fff05..07918c77fdbf34ff8209cfeafe84a12f234ccf61 100644 (file)
@@ -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;
 
index 6b10ad0fe019a01b63168c9cd2f4e2bc74715c5d..e66ab83611b263bea50fae2f5e04868516ae2b28 100644 (file)
@@ -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 */
index 63efd6117a2511a74a736aa984997746aa41d485..95600fdce9b064ab0507ae9d394b86dae494b199 100644 (file)
@@ -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 */