ole32: Add support for main-threaded apartments.

A main-threaded apartment is the first single-threaded apartment in the 
process. It was designed to be used for legacy applications that don't 
want to think about threading at all, even if they are always called 
from the same context, as is the case for regular STAs.
This commit is contained in:
Robert Shearman 2006-08-26 12:02:31 +01:00 committed by Alexandre Julliard
parent 83d24a6408
commit 986027af9f
2 changed files with 60 additions and 13 deletions

View File

@ -85,6 +85,7 @@ static void COM_RevokeAllClasses(void);
static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv);
static APARTMENT *MTA; /* protected by csApartment */
static APARTMENT *MainApartment; /* the first STA apartment */
static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
static CRITICAL_SECTION csApartment;
@ -217,7 +218,7 @@ static void COM_TlsDestroy(void)
*/
/* allocates memory and fills in the necessary fields for a new apartment
* object */
* object. must be called inside apartment cs */
static APARTMENT *apartment_construct(DWORD model)
{
APARTMENT *apt;
@ -252,11 +253,7 @@ static APARTMENT *apartment_construct(DWORD model)
TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid));
/* the locking here is not currently needed for the MTA case, but it
* doesn't hurt and makes the code simpler */
EnterCriticalSection(&csApartment);
list_add_head(&apts, &apt->entry);
LeaveCriticalSection(&csApartment);
return apt;
}
@ -272,8 +269,17 @@ static APARTMENT *apartment_get_or_create(DWORD model)
{
if (model & COINIT_APARTMENTTHREADED)
{
EnterCriticalSection(&csApartment);
apt = apartment_construct(model);
COM_CurrentInfo()->apt = apt;
if (!MainApartment)
{
MainApartment = apt;
apt->main = TRUE;
TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid));
}
LeaveCriticalSection(&csApartment);
}
else
{
@ -291,10 +297,10 @@ static APARTMENT *apartment_get_or_create(DWORD model)
MTA = apartment_construct(model);
apt = MTA;
COM_CurrentInfo()->apt = apt;
LeaveCriticalSection(&csApartment);
}
COM_CurrentInfo()->apt = apt;
}
return apt;
@ -324,6 +330,7 @@ DWORD apartment_release(struct apartment *apt)
if (ret == 0)
{
if (apt == MTA) MTA = NULL;
else if (apt == MainApartment) MainApartment = NULL;
list_remove(&apt->entry);
}
@ -431,12 +438,21 @@ APARTMENT *apartment_findfromtid(DWORD tid)
/* gets an apartment which has a given type. The caller must
* release the reference from the apartment as soon as the apartment pointer
* is no longer required. */
static APARTMENT *apartment_findfromtype(BOOL multi_threaded)
static APARTMENT *apartment_findfromtype(BOOL multi_threaded, BOOL main_apartment)
{
APARTMENT *result = NULL;
struct apartment *apt;
EnterCriticalSection(&csApartment);
if (!multi_threaded && main_apartment)
{
result = MainApartment;
if (result) apartment_addref(result);
LeaveCriticalSection(&csApartment);
return result;
}
LIST_FOR_EACH_ENTRY( apt, &apts, struct apartment, entry )
{
if (apt->multi_threaded == multi_threaded)
@ -1750,7 +1766,7 @@ static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID rii
if (apt->multi_threaded)
{
/* try to find an STA */
APARTMENT *host_apt = apartment_findfromtype(FALSE);
APARTMENT *host_apt = apartment_findfromtype(FALSE, FALSE);
if (!host_apt)
FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid));
if (host_apt)
@ -1785,9 +1801,37 @@ static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID rii
/* everything except "Apartment", "Free" and "Both" */
else if (strcmpiW(threading_model, wszBoth))
{
APARTMENT *apt = COM_CurrentApt();
/* everything else is main-threaded */
FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
debugstr_w(threading_model), debugstr_guid(rclsid));
if (threading_model[0])
FIXME("unrecognised threading model %s for object %s, should be main-threaded?\n",
debugstr_w(threading_model), debugstr_guid(rclsid));
if (apt->multi_threaded || !apt->main)
{
/* try to find an STA */
APARTMENT *host_apt = apartment_findfromtype(FALSE, TRUE);
if (!host_apt)
FIXME("create a host apartment for main-threaded object %s\n", debugstr_guid(rclsid));
if (host_apt)
{
struct host_object_params params;
HWND hwnd = apartment_getwindow(host_apt);
params.hkeydll = hkeydll;
params.clsid = *rclsid;
params.iid = *riid;
hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
if (FAILED(hr))
return hr;
hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
if (SUCCEEDED(hr))
hr = CoUnmarshalInterface(params.stream, riid, ppv);
IStream_Release(params.stream);
return hr;
}
}
}
if (COM_RegReadPath(hkeydll, NULL, NULL, dllpath, ARRAYSIZE(dllpath)) != ERROR_SUCCESS)

View File

@ -145,9 +145,7 @@ struct apartment
DWORD tid; /* thread id (RO) */
OXID oxid; /* object exporter ID (RO) */
LONG ipidc; /* interface pointer ID counter, starts at 1 (LOCK) */
HWND win; /* message window (LOCK) */
CRITICAL_SECTION cs; /* thread safety */
LPMESSAGEFILTER filter; /* message filter (CS cs) */
struct list proxies; /* imported objects (CS cs) */
struct list stubmgrs; /* stub managers for exported objects (CS cs) */
BOOL remunk_exported; /* has the IRemUnknown interface for this apartment been created yet? (CS cs) */
@ -156,6 +154,11 @@ struct apartment
/* FIXME: OID's should be given out by RPCSS */
OID oidc; /* object ID counter, starts at 1, zero is invalid OID (CS cs) */
/* STA-only fields */
HWND win; /* message window (LOCK) */
LPMESSAGEFILTER filter; /* message filter (CS cs) */
BOOL main; /* is this a main-threaded-apartment? (RO) */
};
/* this is what is stored in TEB->ReservedForOle */