- 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.
This commit is contained in:
Robert Shearman 2005-02-08 16:51:22 +00:00 committed by Alexandre Julliard
parent a82b1bcfe5
commit 999766d31b
6 changed files with 84 additions and 232 deletions

View File

@ -28,9 +28,6 @@
* *
* TODO list: (items bunched together depend on each other) * 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 * - Implement the service control manager (in rpcss) to keep track
* of registered class objects: ISCM::ServerRegisterClsid et al * of registered class objects: ISCM::ServerRegisterClsid et al
* - Implement the OXID resolver so we don't need magic pipe names for * - 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 HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
static void COM_RevokeAllClasses(void); 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} }; 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 */ /* This will free the loaded COM Dlls */
CoFreeAllLibraries(); CoFreeAllLibraries();
/* This will free list of external references to COM objects */
COM_ExternalLockFreeList();
/* This ensures we deal with any pending RPCs */ /* This ensures we deal with any pending RPCs */
COM_FlushMessageQueue(); COM_FlushMessageQueue();
} }
@ -748,7 +741,31 @@ void WINAPI CoUninitialize(void)
*/ */
HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) 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; return S_OK;
} }
@ -1983,209 +2000,6 @@ static void COM_RevokeAllClasses()
LeaveCriticalSection( &csRegisteredClassList ); 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.@] * CoLockObjectExternal [OLE32.@]
* *
@ -2203,28 +2017,40 @@ void COM_ExternalLockDump()
* Failure: HRESULT code. * Failure: HRESULT code.
*/ */
HRESULT WINAPI CoLockObjectExternal( HRESULT WINAPI CoLockObjectExternal(
LPUNKNOWN pUnk, /* */ LPUNKNOWN pUnk,
BOOL fLock, /* [in] do lock */ BOOL fLock,
BOOL fLastUnlockReleases) /* [in] unlock all */ BOOL fLastUnlockReleases)
{ {
struct stub_manager *stubmgr;
struct apartment *apt;
TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n",
pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE");
if (fLock) { apt = COM_CurrentApt();
/* if (!apt) return CO_E_NOTINITIALIZED;
* Increment the external lock coutner, COM_ExternalLockAddRef also
* increment the object's internal lock counter. stubmgr = get_stub_manager_from_object(apt, pUnk);
*/
COM_ExternalLockAddRef( pUnk); if (stubmgr)
} else { {
/* if (fLock)
* Decrement the external lock coutner, COM_ExternalLockRelease also stub_manager_ext_addref(stubmgr, 1);
* decrement the object's internal lock counter. else
*/ stub_manager_ext_release(stubmgr, 1);
COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
} stub_manager_int_release(stubmgr);
return S_OK; 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;
}
} }
/*********************************************************************** /***********************************************************************

View 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 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(APARTMENT *apt, OID oid);
struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object); 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_notify_unmarshal(struct stub_manager *m, const IPID *ipid);
BOOL stub_manager_is_table_marshaled(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); HRESULT register_ifstub(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags);

View File

@ -92,8 +92,8 @@
@ stdcall DllDebugObjectRPCHook(long ptr) @ stdcall DllDebugObjectRPCHook(long ptr)
@ stdcall -private DllGetClassObject (ptr ptr ptr) OLE32_DllGetClassObject @ stdcall -private DllGetClassObject (ptr ptr ptr) OLE32_DllGetClassObject
@ stub DllGetClassObjectWOW @ stub DllGetClassObjectWOW
@ stdcall -private DllRegisterServer() OLE32_DllRegisterServer @ stdcall -private DllRegisterServer()
@ stdcall -private DllUnregisterServer() OLE32_DllUnregisterServer @ stdcall -private DllUnregisterServer()
@ stdcall DoDragDrop(ptr ptr long ptr) @ stdcall DoDragDrop(ptr ptr long ptr)
@ stub EnableHookObject @ stub EnableHookObject
@ stdcall FreePropVariantArray(long ptr) @ stdcall FreePropVariantArray(long ptr)

View File

@ -470,7 +470,7 @@ static struct regsvr_interface const interface_list[] = {
/*********************************************************************** /***********************************************************************
* DllRegisterServer (OLE32.@) * DllRegisterServer (OLE32.@)
*/ */
HRESULT WINAPI OLE32_DllRegisterServer() HRESULT WINAPI DllRegisterServer()
{ {
HRESULT hr; HRESULT hr;
@ -485,7 +485,7 @@ HRESULT WINAPI OLE32_DllRegisterServer()
/*********************************************************************** /***********************************************************************
* DllUnregisterServer (OLE32.@) * DllUnregisterServer (OLE32.@)
*/ */
HRESULT WINAPI OLE32_DllUnregisterServer() HRESULT WINAPI DllUnregisterServer()
{ {
HRESULT hr; HRESULT hr;

View File

@ -138,6 +138,31 @@ struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object)
return result; 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 /* 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. * 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 */ * it must also call release on the stub manager when it is no longer needed */

View File

@ -834,7 +834,7 @@ static void test_disconnect_stub()
CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0); CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
todo_wine { ok_no_locks(); } ok_no_locks();
} }
/* tests failure case of a same-thread marshal and unmarshal twice */ /* tests failure case of a same-thread marshal and unmarshal twice */