- Make MTA dynamically allocated so that proxies and other resources

are freed at the proper time.
- Changed/removed some incorrect comments regarding apartments.
This commit is contained in:
Robert Shearman 2005-01-12 19:27:04 +00:00 committed by Alexandre Julliard
parent b2bb57a484
commit 36f482cb7d
1 changed files with 39 additions and 58 deletions

View File

@ -28,13 +28,11 @@
* *
* TODO list: (items bunched together depend on each other) * TODO list: (items bunched together depend on each other)
* *
* - Switch wine_marshal_id to use IPIDs not IIDs
* - Once that's done, replace wine_marshal_id with STDOBJREF * - Once that's done, replace wine_marshal_id with STDOBJREF
* *
* - 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
* - Free the ReservedForOle data in DllMain(THREAD_DETACH) * - Free the ReservedForOle data in DllMain(THREAD_DETACH)
* *
* - Implement the service control manager (in rpcss) to keep track * - Implement the service control manager (in rpcss) to keep track
@ -106,8 +104,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; APARTMENT *MTA; /* protected by csApartment */
static struct list apts = LIST_INIT( apts ); static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
static CRITICAL_SECTION csApartment; static CRITICAL_SECTION csApartment;
static CRITICAL_SECTION_DEBUG critsect_debug = static CRITICAL_SECTION_DEBUG critsect_debug =
@ -217,50 +215,29 @@ void COMPOBJ_UninitProcess( void )
* Manage apartments. * Manage apartments.
*/ */
/* creates an apartment structure which stores OLE apartment-local
/* The multi-threaded apartment (MTA) contains zero or more threads interacting * information */
with free threaded (ie thread safe) COM objects. There is only ever one MTA
in a process - you can enter it by calling CoInitializeEx(COINIT_MULTITHREADED)
*/
static void COM_InitMTA(void)
{
/* OXIDs are object exporter IDs. Each apartment has an OXID, which is unique
within a network. That is, two different MTAs on different machines will have
different OXIDs.
This method of generating an OXID is therefore wrong as it doesn't work across
a network, but for local RPC only it's OK. We can distinguish between MTAs and
STAs because STAs use the thread ID as well, and no thread can have an ID of zero.
The algorithm Microsoft use is currently unknown.
*/
MTA.oxid = ((OXID)GetCurrentProcessId() << 32);
InitializeCriticalSection(&MTA.cs);
}
static void COM_UninitMTA(void)
{
DeleteCriticalSection(&MTA.cs);
MTA.oxid = 0;
}
/* creates an apartment structure which stores OLE thread-local
* information. Call with COINIT_UNINITIALIZED to create an apartment
* that will be initialized with a model later. Note: do not call
* with COINIT_UNINITIALIZED if the apartment has already been initialized
* with a different COINIT value */
APARTMENT* COM_CreateApartment(DWORD model) APARTMENT* COM_CreateApartment(DWORD model)
{ {
APARTMENT *apt = COM_CurrentApt(); APARTMENT *apt = COM_CurrentApt();
if (!apt) if (!apt)
{ {
if (!(model & COINIT_APARTMENTTHREADED)) /* See note 1 above */ /* The multi-threaded apartment (MTA) contains zero or more threads interacting
* with free threaded (ie thread safe) COM objects. There is only ever one MTA
* in a process
*/
EnterCriticalSection(&csApartment);
if (!(model & COINIT_APARTMENTTHREADED) && MTA) /* See note 1 above */
{ {
TRACE("thread 0x%lx is entering the multithreaded apartment\n", GetCurrentThreadId()); TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid));
COM_CurrentInfo()->apt = &MTA; apt = MTA;
return COM_CurrentInfo()->apt; COM_ApartmentAddRef(apt);
LeaveCriticalSection(&csApartment);
COM_CurrentInfo()->apt = apt;
return apt;
} }
TRACE("creating new apartment, model=%ld\n", model); TRACE("creating new apartment, model=%ld\n", model);
@ -279,19 +256,23 @@ APARTMENT* COM_CreateApartment(DWORD model)
apt->model = model; apt->model = model;
/* we don't ref the apartment as CoInitializeEx will do it for us */
if (model & COINIT_APARTMENTTHREADED) if (model & COINIT_APARTMENTTHREADED)
{ {
/* FIXME: how does windoze create OXIDs? */ /* FIXME: should be randomly generated by in an RPC call to rpcss */
apt->oxid = MTA.oxid | GetCurrentThreadId(); apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId();
TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
apt->win = CreateWindowA(aptWinClass, NULL, 0, apt->win = CreateWindowA(aptWinClass, NULL, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, OLE32_hInstance, NULL); 0, 0, OLE32_hInstance, NULL);
} }
else
{
/* FIXME: should be randomly generated by in an RPC call to rpcss */
apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe;
MTA = apt;
}
TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
EnterCriticalSection(&csApartment);
list_add_head(&apts, &apt->entry); list_add_head(&apts, &apt->entry);
LeaveCriticalSection(&csApartment); LeaveCriticalSection(&csApartment);
@ -310,15 +291,22 @@ DWORD COM_ApartmentRelease(struct apartment *apt)
{ {
DWORD ret; DWORD ret;
EnterCriticalSection(&csApartment);
ret = InterlockedDecrement(&apt->refs); ret = InterlockedDecrement(&apt->refs);
/* destruction stuff that needs to happen under csApartment CS */
if (ret == 0)
{
if (apt == MTA) MTA = NULL;
list_remove(&apt->entry);
}
LeaveCriticalSection(&csApartment);
if (ret == 0) if (ret == 0)
{ {
TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid));
EnterCriticalSection(&csApartment);
list_remove(&apt->entry);
LeaveCriticalSection(&csApartment);
MARSHAL_Disconnect_Proxies(apt); MARSHAL_Disconnect_Proxies(apt);
if (apt->win) DestroyWindow(apt->win); if (apt->win) DestroyWindow(apt->win);
@ -330,12 +318,9 @@ DWORD COM_ApartmentRelease(struct apartment *apt)
if (apt->filter) IUnknown_Release(apt->filter); if (apt->filter) IUnknown_Release(apt->filter);
DeleteCriticalSection(&apt->cs); DeleteCriticalSection(&apt->cs);
CloseHandle(apt->thread); CloseHandle(apt->thread);
HeapFree(GetProcessHeap(), 0, apt); HeapFree(GetProcessHeap(), 0, apt);
apt = NULL;
} }
return ret; return ret;
@ -541,8 +526,6 @@ HRESULT WINAPI CoInitializeEx(
*/ */
TRACE("() - Initializing the COM libraries\n"); TRACE("() - Initializing the COM libraries\n");
COM_InitMTA();
/* we may need to defer this until after apartment initialisation */ /* we may need to defer this until after apartment initialisation */
RunningObjectTableImpl_Initialize(); RunningObjectTableImpl_Initialize();
} }
@ -653,8 +636,6 @@ void WINAPI CoUninitialize(void)
/* This ensures we deal with any pending RPCs */ /* This ensures we deal with any pending RPCs */
COM_FlushMessageQueue(); COM_FlushMessageQueue();
COM_UninitMTA();
} }
else if (lCOMRefCnt<1) { else if (lCOMRefCnt<1) {
ERR( "CoUninitialize() - not CoInitialized.\n" ); ERR( "CoUninitialize() - not CoInitialized.\n" );