- Make apartment access thread-safe by introducing refcounting and

wider usage of the apartment lock.
- Rework OLE TLS management to eliminate uninitialised apartments and
  parent chaining.
This commit is contained in:
Mike Hearn 2005-01-05 17:14:33 +00:00 committed by Alexandre Julliard
parent a790b2d1c5
commit a6a416cb4e
6 changed files with 230 additions and 181 deletions

View File

@ -30,6 +30,8 @@
* - Rewrite the CoLockObjectExternal code, it does totally the wrong * - Rewrite the CoLockObjectExternal code, it does totally the wrong
* thing currently (should be controlling the stub manager) * thing currently (should be controlling the stub manager)
* *
* - Make the MTA dynamically allocated and refcounted
*
* - 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
@ -99,7 +101,8 @@ 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} };
APARTMENT MTA, *apts; APARTMENT MTA;
struct list apts = LIST_INIT( apts );
static CRITICAL_SECTION csApartment; static CRITICAL_SECTION csApartment;
static CRITICAL_SECTION_DEBUG critsect_debug = static CRITICAL_SECTION_DEBUG critsect_debug =
@ -236,6 +239,7 @@ static void COM_UninitMTA(void)
MTA.oxid = 0; MTA.oxid = 0;
} }
/* creates an apartment structure which stores OLE thread-local /* creates an apartment structure which stores OLE thread-local
* information. Call with COINIT_UNINITIALIZED to create an apartment * information. Call with COINIT_UNINITIALIZED to create an apartment
* that will be initialized with a model later. Note: do not call * that will be initialized with a model later. Note: do not call
@ -243,100 +247,138 @@ static void COM_UninitMTA(void)
* with a different COINIT value */ * with a different COINIT value */
APARTMENT* COM_CreateApartment(DWORD model) APARTMENT* COM_CreateApartment(DWORD model)
{ {
APARTMENT *apt; APARTMENT *apt = COM_CurrentApt();
BOOL create = (NtCurrentTeb()->ReservedForOle == NULL);
if (create) if (!apt)
{ {
if (model & COINIT_MULTITHREADED)
{
TRACE("thread 0x%lx is entering the multithreaded apartment\n", GetCurrentThreadId());
COM_CurrentInfo()->apt = &MTA;
return apt;
}
TRACE("creating new apartment, model=%ld\n", model);
apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT)); apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT));
apt->tid = GetCurrentThreadId(); apt->tid = GetCurrentThreadId();
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
GetCurrentProcess(), &apt->thread, GetCurrentProcess(), &apt->thread,
THREAD_ALL_ACCESS, FALSE, 0); THREAD_ALL_ACCESS, FALSE, 0);
}
else
apt = NtCurrentTeb()->ReservedForOle;
list_init(&apt->proxies); list_init(&apt->proxies);
list_init(&apt->stubmgrs); list_init(&apt->stubmgrs);
apt->oidc = 1; apt->oidc = 1;
apt->refs = 1;
apt->model = model; InitializeCriticalSection(&apt->cs);
if (model & COINIT_APARTMENTTHREADED) {
/* FIXME: how does windoze create OXIDs? */ apt->model = model;
apt->oxid = MTA.oxid | GetCurrentThreadId();
apt->win = CreateWindowA(aptWinClass, NULL, 0, /* we don't ref the apartment as CoInitializeEx will do it for us */
0, 0, 0, 0,
0, 0, OLE32_hInstance, NULL); if (model & COINIT_APARTMENTTHREADED)
InitializeCriticalSection(&apt->cs); {
} /* FIXME: how does windoze create OXIDs? */
else if (!(model & COINIT_UNINITIALIZED)) { apt->oxid = MTA.oxid | GetCurrentThreadId();
apt->parent = &MTA; apt->win = CreateWindowA(aptWinClass, NULL, 0,
apt->oxid = MTA.oxid; 0, 0, 0, 0,
0, 0, OLE32_hInstance, NULL);
}
EnterCriticalSection(&csApartment);
list_add_head(&apts, &apt->entry);
LeaveCriticalSection(&csApartment);
COM_CurrentInfo()->apt = apt;
} }
return apt;
}
DWORD COM_ApartmentAddRef(struct apartment *apt)
{
return InterlockedIncrement(&apt->refs);
}
DWORD COM_ApartmentRelease(struct apartment *apt)
{
DWORD ret;
EnterCriticalSection(&csApartment); EnterCriticalSection(&csApartment);
if (create)
ret = InterlockedDecrement(&apt->refs);
if (ret == 0)
{ {
if (apts) apts->prev = apt; TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
apt->next = apts;
apts = apt; 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");
}
if (apt->filter) IUnknown_Release(apt->filter);
DeleteCriticalSection(&apt->cs);
CloseHandle(apt->thread);
HeapFree(GetProcessHeap(), 0, apt);
apt = NULL;
} }
LeaveCriticalSection(&csApartment); LeaveCriticalSection(&csApartment);
NtCurrentTeb()->ReservedForOle = apt;
return apt; return ret;
} }
static void COM_DestroyApartment(APARTMENT *apt) /* The given OXID must be local to this process: you cannot use
* apartment windows to send RPCs to other processes. This all needs
* to move to rpcrt4.
*
* The ref parameter is here mostly to ensure people remember that
* they get one, you should normally take a ref for thread safety.
*/
APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref)
{ {
EnterCriticalSection(&csApartment); APARTMENT *result = NULL;
if (apt->prev) apt->prev->next = apt->next; struct list *cursor;
if (apt->next) apt->next->prev = apt->prev;
if (apts == apt) apts = apt->next;
apt->prev = NULL; apt->next = NULL;
LeaveCriticalSection(&csApartment);
if (apt->model & COINIT_APARTMENTTHREADED) {
/* disconnect proxies to release the corresponding stubs.
* It is confirmed in "Essential COM" in the sub-chapter on
* "Lifecycle Management and Marshalling" that the native version also
* disconnects proxies in this function. */
/* FIXME: this should also be called for MTA destruction, but that
* requires restructuring how apartments work slightly. */
MARSHAL_Disconnect_Proxies(apt);
if (apt->win) DestroyWindow(apt->win);
DeleteCriticalSection(&apt->cs);
}
CloseHandle(apt->thread);
HeapFree(GetProcessHeap(), 0, apt);
}
/* The given OXID must be local to this process: you cannot use apartment
windows to send RPCs to other processes. This all needs to move to rpcrt4 */
APARTMENT *COM_ApartmentFromOXID(OXID oxid)
{
APARTMENT *apt = NULL;
EnterCriticalSection(&csApartment); EnterCriticalSection(&csApartment);
apt = apts; LIST_FOR_EACH( cursor, &apts )
while (apt && apt->oxid != oxid) apt = apt->next; {
struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry );
if (apt->oxid == oxid)
{
result = apt;
if (ref) COM_ApartmentAddRef(result);
break;
}
}
LeaveCriticalSection(&csApartment); LeaveCriticalSection(&csApartment);
return apt; return result;
} }
HWND COM_GetApartmentWin(OXID oxid) HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
{ {
APARTMENT *apt = COM_ApartmentFromOXID(oxid); APARTMENT *apt;
return apt ? apt->win : NULL; apt = COM_ApartmentFromOXID(oxid, ref);
if (!apt) return NULL;
return apt->win;
} }
/* Currently inter-thread marshalling is not fully implemented, so this does nothing */ /* Currently inter-thread marshalling is not fully implemented, so this does nothing */
static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
return DefWindowProcA(hWnd, msg, wParam, lParam); return DefWindowProcA(hWnd, msg, wParam, lParam);
} }
/***************************************************************************** /*****************************************************************************
* This section contains OpenDllList implemantation * This section contains OpenDllList implemantation
@ -467,8 +509,7 @@ HRESULT WINAPI CoInitialize(
* CoUninitialize * CoUninitialize
*/ */
HRESULT WINAPI CoInitializeEx( HRESULT WINAPI CoInitializeEx(
LPVOID lpReserved, /* [in] pointer to win32 malloc interface LPVOID lpReserved, /* [in] pointer to win32 malloc interface (obsolete, should be NULL) */
(obsolete, should be NULL) */
DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */ DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */
) )
{ {
@ -482,21 +523,6 @@ HRESULT WINAPI CoInitializeEx(
ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved); ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved);
} }
apt = NtCurrentTeb()->ReservedForOle;
if (apt && !(apt->model == COINIT_UNINITIALIZED))
{
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);
return RPC_E_CHANGED_MODE;
}
hr = S_FALSE;
}
else
hr = S_OK;
/* /*
* Check the lock count. If this is the first time going through the initialize * Check the lock count. If this is the first time going through the initialize
* process, we have to initialize the libraries. * process, we have to initialize the libraries.
@ -512,13 +538,27 @@ HRESULT WINAPI CoInitializeEx(
COM_InitMTA(); COM_InitMTA();
/* we may need to defer this until after apartment initialisation */
RunningObjectTableImpl_Initialize(); RunningObjectTableImpl_Initialize();
} }
if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit); if (!(apt = COM_CurrentInfo()->apt))
{
apt = COM_CreateApartment(dwCoInit);
}
else
{
InterlockedIncrement(&apt->refs);
}
InterlockedIncrement(&apt->inits); if (dwCoInit != apt->model)
if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt; {
/* 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);
return RPC_E_CHANGED_MODE;
}
return hr; return hr;
} }
@ -529,14 +569,20 @@ HRESULT WINAPI CoInitializeEx(
void COM_FlushMessageQueue(void) void COM_FlushMessageQueue(void)
{ {
MSG message; MSG message;
APARTMENT *apt = NtCurrentTeb()->ReservedForOle; APARTMENT *apt = COM_CurrentApt();
if (!apt || !apt->win) return; if (!apt || !apt->win) return;
TRACE("Flushing STA message queue\n"); TRACE("Flushing STA message queue\n");
while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) { while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE))
if (message.hwnd != apt->win) continue; {
if (message.hwnd != apt->win)
{
WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd);
continue;
}
TranslateMessage(&message); TranslateMessage(&message);
DispatchMessageA(&message); DispatchMessageA(&message);
} }
@ -561,17 +607,11 @@ void COM_FlushMessageQueue(void)
void WINAPI CoUninitialize(void) void WINAPI CoUninitialize(void)
{ {
LONG lCOMRefCnt; LONG lCOMRefCnt;
APARTMENT *apt;
TRACE("()\n"); TRACE("()\n");
apt = NtCurrentTeb()->ReservedForOle; if (!COM_ApartmentRelease(COM_CurrentInfo()->apt))
if (!apt) return; COM_CurrentInfo()->apt = NULL;
if (InterlockedDecrement(&apt->inits)==0) {
NtCurrentTeb()->ReservedForOle = NULL;
COM_DestroyApartment(apt);
apt = NULL;
}
/* /*
* Decrease the reference count. * Decrease the reference count.
@ -1134,14 +1174,14 @@ end:
/****************************************************************************** /******************************************************************************
* CoRegisterClassObject [OLE32.@] * CoRegisterClassObject [OLE32.@]
* *
* Registers the class object for a given class ID. Servers housed in EXE * Registers the class object for a given class ID. Servers housed in EXE
* files use this method instead of exporting DllGetClassObject to allow * files use this method instead of exporting DllGetClassObject to allow
* other code to connect to their objects. * other code to connect to their objects.
* *
* RETURNS * RETURNS
* S_OK on success, * S_OK on success,
* E_INVALIDARG if lpdwRegister or pUnk are NULL, * E_INVALIDARG if lpdwRegister or pUnk are NULL,
* CO_E_OBJISREG if the object is already registered. We should not return this. * CO_E_OBJISREG if the object is already registered. We should not return this.
* *
* SEE ALSO * SEE ALSO
@ -1217,7 +1257,7 @@ HRESULT WINAPI CoRegisterClassObject(
if (dwClsContext & CLSCTX_LOCAL_SERVER) { if (dwClsContext & CLSCTX_LOCAL_SERVER) {
IClassFactory *classfac; IClassFactory *classfac;
hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory, hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory,
(LPVOID*)&classfac); (LPVOID*)&classfac);
if (hr) return hr; if (hr) return hr;
@ -1556,7 +1596,7 @@ HRESULT WINAPI CoCreateInstance(
LPCLASSFACTORY lpclf = 0; LPCLASSFACTORY lpclf = 0;
if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED; if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
/* /*
* Sanity check * Sanity check
*/ */
@ -1573,15 +1613,15 @@ HRESULT WINAPI CoCreateInstance(
* Rather than create a class factory, we can just check for it here * Rather than create a class factory, we can just check for it here
*/ */
if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) { if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) {
if (StdGlobalInterfaceTableInstance == NULL) if (StdGlobalInterfaceTableInstance == NULL)
StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct(); StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct();
hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv); hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv);
if (hres) return hres; if (hres) return hres;
TRACE("Retrieved GIT (%p)\n", *ppv); TRACE("Retrieved GIT (%p)\n", *ppv);
return S_OK; return S_OK;
} }
/* /*
* Get a class factory to construct the object we want. * Get a class factory to construct the object we want.
*/ */
@ -2000,19 +2040,19 @@ HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) {
*/ */
HRESULT WINAPI CoGetState(IUnknown ** ppv) HRESULT WINAPI CoGetState(IUnknown ** ppv)
{ {
APARTMENT * apt = COM_CurrentInfo(); HRESULT hr = E_FAIL;
FIXME("\n"); *ppv = NULL;
if(apt && apt->state) { if (COM_CurrentInfo()->state)
IUnknown_AddRef(apt->state); {
*ppv = apt->state; IUnknown_AddRef(COM_CurrentInfo()->state);
FIXME("-- %p\n", *ppv); *ppv = COM_CurrentInfo()->state;
return S_OK; TRACE("apt->state=%p\n", COM_CurrentInfo()->state);
} hr = S_OK;
*ppv = NULL; }
return E_FAIL;
return hr;
} }
/*********************************************************************** /***********************************************************************
@ -2021,22 +2061,17 @@ HRESULT WINAPI CoGetState(IUnknown ** ppv)
*/ */
HRESULT WINAPI CoSetState(IUnknown * pv) HRESULT WINAPI CoSetState(IUnknown * pv)
{ {
APARTMENT * apt = COM_CurrentInfo(); if (pv) IUnknown_AddRef(pv);
if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED); if (COM_CurrentInfo()->state)
{
TRACE("-- release %p now\n", COM_CurrentInfo()->state);
IUnknown_Release(COM_CurrentInfo()->state);
}
FIXME("(%p),stub!\n", pv); COM_CurrentInfo()->state = pv;
if (pv) { return S_OK;
IUnknown_AddRef(pv);
}
if (apt->state) {
TRACE("-- release %p now\n", apt->state);
IUnknown_Release(apt->state);
}
apt->state = pv;
return S_OK;
} }
@ -2191,7 +2226,7 @@ HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew)
done: done:
if (hkey) RegCloseKey(hkey); if (hkey) RegCloseKey(hkey);
return res; return res;
} }
/*********************************************************************** /***********************************************************************

View File

@ -38,12 +38,8 @@
#include "winreg.h" #include "winreg.h"
#include "winternl.h" #include "winternl.h"
/* Windows maps COINIT values to 0x80 for apartment threaded, 0x140 struct apartment;
* for free threaded, and 0 for uninitialized apartments. There is
* no real advantage in us doing this and certainly no release version
* of an app should be poking around with these flags. So we need a
* special value for uninitialized */
#define COINIT_UNINITIALIZED 0x100
/* exported interface */ /* exported interface */
typedef struct tagXIF { typedef struct tagXIF {
@ -59,7 +55,7 @@ typedef struct tagXIF {
/* exported object */ /* exported object */
typedef struct tagXOBJECT { typedef struct tagXOBJECT {
IRpcStubBufferVtbl *lpVtbl; IRpcStubBufferVtbl *lpVtbl;
struct tagAPARTMENT *parent; struct apartment *parent;
struct tagXOBJECT *next; struct tagXOBJECT *next;
LPUNKNOWN obj; /* object identity (IUnknown) */ LPUNKNOWN obj; /* object identity (IUnknown) */
OID oid; /* object ID */ OID oid; /* object ID */
@ -83,7 +79,7 @@ struct ifproxy
struct proxy_manager struct proxy_manager
{ {
const IInternalUnknownVtbl *lpVtbl; const IInternalUnknownVtbl *lpVtbl;
struct tagAPARTMENT *parent; struct apartment *parent;
struct list entry; struct list entry;
LPRPCCHANNELBUFFER chan; /* channel to object */ LPRPCCHANNELBUFFER chan; /* channel to object */
OXID oxid; /* object exported ID */ OXID oxid; /* object exported ID */
@ -93,11 +89,13 @@ struct proxy_manager
CRITICAL_SECTION cs; /* thread safety for this object and children */ CRITICAL_SECTION cs; /* thread safety for this object and children */
}; };
/* apartment */ /* this needs to become a COM object that implements IRemUnknown */
typedef struct tagAPARTMENT { struct apartment
struct tagAPARTMENT *next, *prev, *parent; {
struct list entry;
DWORD refs; /* refcount of the apartment */
DWORD model; /* threading model */ DWORD model; /* threading model */
DWORD inits; /* CoInitialize count */
DWORD tid; /* thread id */ DWORD tid; /* thread id */
HANDLE thread; /* thread handle */ HANDLE thread; /* thread handle */
OXID oxid; /* object exporter ID */ OXID oxid; /* object exporter ID */
@ -107,13 +105,11 @@ typedef struct tagAPARTMENT {
LPMESSAGEFILTER filter; /* message filter */ LPMESSAGEFILTER filter; /* message filter */
XOBJECT *objs; /* exported objects */ XOBJECT *objs; /* exported objects */
struct list proxies; /* imported objects */ struct list proxies; /* imported objects */
LPUNKNOWN state; /* state object (see Co[Get,Set]State) */
LPVOID ErrorInfo; /* thread error info */
DWORD listenertid; /* id of apartment_listener_thread */ DWORD listenertid; /* id of apartment_listener_thread */
struct list stubmgrs; /* stub managers for exported objects */ struct list stubmgrs; /* stub managers for exported objects */
} APARTMENT; };
extern APARTMENT MTA, *apts; typedef struct apartment APARTMENT;
extern void* StdGlobalInterfaceTable_Construct(void); extern void* StdGlobalInterfaceTable_Construct(void);
extern void StdGlobalInterfaceTable_Destroy(void* self); extern void StdGlobalInterfaceTable_Destroy(void* self);
@ -196,26 +192,40 @@ int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id); HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id);
/* compobj.c */
APARTMENT *COM_CreateApartment(DWORD model);
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 */
};
/* /*
* Per-thread values are stored in the TEB on offset 0xF80, * Per-thread values are stored in the TEB on offset 0xF80,
* see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm * see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm
*/ */
static inline APARTMENT* COM_CurrentInfo(void)
/* will create if necessary */
static inline struct oletls *COM_CurrentInfo(void)
{ {
APARTMENT* apt = NtCurrentTeb()->ReservedForOle; if (!NtCurrentTeb()->ReservedForOle)
return apt; NtCurrentTeb()->ReservedForOle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct oletls));
}
static inline APARTMENT* COM_CurrentApt(void) return NtCurrentTeb()->ReservedForOle;
{
APARTMENT* apt = COM_CurrentInfo();
if (apt && apt->parent) apt = apt->parent;
return apt;
} }
/* compobj.c */ static inline APARTMENT* COM_CurrentApt(void)
APARTMENT *COM_CreateApartment(DWORD model); {
HWND COM_GetApartmentWin(OXID oxid); return COM_CurrentInfo()->apt;
APARTMENT *COM_ApartmentFromOXID(OXID oxid); }
#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))

View File

@ -20,7 +20,7 @@
* NOTES: * NOTES:
* *
* The errorinfo is a per-thread object. The reference is stored in the * The errorinfo is a per-thread object. The reference is stored in the
* TEB at offset 0xf80 * TEB at offset 0xf80.
*/ */
#include <stdarg.h> #include <stdarg.h>
@ -483,20 +483,20 @@ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo)
*/ */
HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo) HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
{ {
APARTMENT * apt = COM_CurrentInfo(); TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo);
TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->ErrorInfo);
if(!pperrinfo) return E_INVALIDARG; if(!pperrinfo) return E_INVALIDARG;
if (!apt || !apt->ErrorInfo)
if (!COM_CurrentInfo()->errorinfo)
{ {
*pperrinfo = NULL; *pperrinfo = NULL;
return S_FALSE; return S_FALSE;
} }
*pperrinfo = (IErrorInfo*)(apt->ErrorInfo); *pperrinfo = COM_CurrentInfo()->errorinfo;
/* clear thread error state */ /* clear thread error state */
apt->ErrorInfo = NULL; COM_CurrentInfo()->errorinfo = NULL;
return S_OK; return S_OK;
} }
@ -506,18 +506,16 @@ HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo)
HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo) HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo)
{ {
IErrorInfo * pei; IErrorInfo * pei;
APARTMENT * apt = COM_CurrentInfo();
TRACE("(%ld, %p)\n", dwReserved, perrinfo); TRACE("(%ld, %p)\n", dwReserved, perrinfo);
if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED);
/* release old errorinfo */ /* release old errorinfo */
pei = (IErrorInfo*)apt->ErrorInfo; pei = COM_CurrentInfo()->errorinfo;
if(pei) IErrorInfo_Release(pei); if (pei) IErrorInfo_Release(pei);
/* set to new value */ /* set to new value */
apt->ErrorInfo = perrinfo; COM_CurrentInfo()->errorinfo = perrinfo;
if(perrinfo) IErrorInfo_AddRef(perrinfo); if (perrinfo) IErrorInfo_AddRef(perrinfo);
return S_OK; return S_OK;
} }

View File

@ -109,9 +109,13 @@ static HRESULT register_ifstub(wine_marshal_id *mid, IUnknown *obj, IRpcStubBuff
} }
else else
{ {
TRACE("constructing new stub manager\n"); struct apartment *apt;
manager = new_stub_manager(COM_ApartmentFromOXID(mid->oxid), obj); TRACE("constructing new stub manager\n");
apt = COM_ApartmentFromOXID(mid->oxid, TRUE);
manager = new_stub_manager(apt, obj);
COM_ApartmentRelease(apt);
if (!manager) return E_OUTOFMEMORY; if (!manager) return E_OUTOFMEMORY;
if (!tablemarshal) stub_manager_ref(manager, 1); if (!tablemarshal) stub_manager_ref(manager, 1);

View File

@ -308,8 +308,6 @@ PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
if (ref) if (ref)
return ref; return ref;
FIXME("Free all stuff\n");
memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id)); memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id));
pipe = PIPE_FindByMID(&This->mid); pipe = PIPE_FindByMID(&This->mid);
@ -892,7 +890,7 @@ static DWORD WINAPI apartment_listener_thread(LPVOID param)
HANDLE listenPipe; HANDLE listenPipe;
APARTMENT *apt = (APARTMENT *) param; APARTMENT *apt = (APARTMENT *) param;
/* we must join the marshalling threads apartment */ /* we must join the marshalling threads apartment. we already have a ref here */
NtCurrentTeb()->ReservedForOle = apt; NtCurrentTeb()->ReservedForOle = apt;
sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid)); sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid));
@ -926,7 +924,7 @@ static DWORD WINAPI apartment_listener_thread(LPVOID param)
void start_apartment_listener_thread() void start_apartment_listener_thread()
{ {
APARTMENT *apt = COM_CurrentApt(); APARTMENT *apt = COM_CurrentApt();
assert( apt ); assert( apt );
TRACE("apt->listenertid=%ld\n", apt->listenertid); TRACE("apt->listenertid=%ld\n", apt->listenertid);

View File

@ -41,6 +41,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(ole); WINE_DEFAULT_DEBUG_CHANNEL(ole);
/* this refs the apartment on success, otherwise there is no ref */
struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object) struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
{ {
struct stub_manager *sm; struct stub_manager *sm;
@ -71,6 +72,7 @@ struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
list_add_head(&apt->stubmgrs, &sm->entry); list_add_head(&apt->stubmgrs, &sm->entry);
LeaveCriticalSection(&apt->cs); LeaveCriticalSection(&apt->cs);
COM_ApartmentAddRef(apt);
TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object); TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object);
return sm; return sm;
@ -82,7 +84,7 @@ struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object)
struct list *cursor; struct list *cursor;
APARTMENT *apt; APARTMENT *apt;
if (!(apt = COM_ApartmentFromOXID(oxid))) if (!(apt = COM_ApartmentFromOXID(oxid, TRUE)))
{ {
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid)); WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
return NULL; return NULL;
@ -101,6 +103,8 @@ struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object)
} }
LeaveCriticalSection(&apt->cs); LeaveCriticalSection(&apt->cs);
COM_ApartmentRelease(apt);
TRACE("found %p from object %p\n", result, object); TRACE("found %p from object %p\n", result, object);
return result; return result;
@ -112,14 +116,13 @@ struct stub_manager *get_stub_manager(OXID oxid, OID oid)
struct list *cursor; struct list *cursor;
APARTMENT *apt; APARTMENT *apt;
if (!(apt = COM_ApartmentFromOXID(oxid))) if (!(apt = COM_ApartmentFromOXID(oxid, TRUE)))
{ {
WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid)); WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(oxid));
return NULL; return NULL;
} }
EnterCriticalSection(&apt->cs); EnterCriticalSection(&apt->cs);
LIST_FOR_EACH( cursor, &apt->stubmgrs ) LIST_FOR_EACH( cursor, &apt->stubmgrs )
{ {
struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry );
@ -130,9 +133,10 @@ struct stub_manager *get_stub_manager(OXID oxid, OID oid)
break; break;
} }
} }
LeaveCriticalSection(&apt->cs); LeaveCriticalSection(&apt->cs);
COM_ApartmentRelease(apt);
TRACE("found %p from oid %s\n", result, wine_dbgstr_longlong(oid)); TRACE("found %p from oid %s\n", result, wine_dbgstr_longlong(oid));
return result; return result;