- 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:
parent
a82b1bcfe5
commit
999766d31b
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue