Robert Shearman : ole32: Add support for main-threaded apartments.

Alexandre Julliard julliard at wine.codeweavers.com
Sat Aug 26 13:47:41 CDT 2006


Module: wine
Branch: master
Commit: 986027af9fe3cb8eb7f36acb31a06c84e021a5f7
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=986027af9fe3cb8eb7f36acb31a06c84e021a5f7

Author: Robert Shearman <rob at codeweavers.com>
Date:   Sat Aug 26 12:02:31 2006 +0100

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.

---

 dlls/ole32/compobj.c         |   66 +++++++++++++++++++++++++++++++++++-------
 dlls/ole32/compobj_private.h |    7 +++-
 2 files changed, 60 insertions(+), 13 deletions(-)

diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index 4a61aca..0208bc5 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -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(DW
 
     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_creat
     {
         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_creat
                 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
     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 t
 /* 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(H
         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(H
     /* 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)
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h
index cb4dd64..9052c38 100644
--- a/dlls/ole32/compobj_private.h
+++ b/dlls/ole32/compobj_private.h
@@ -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 */




More information about the wine-cvs mailing list