[PATCH v2] ole32: Store proxy/stub CLSIDs per process, not per apartment.

Zebediah Figura zfigura at codeweavers.com
Tue Aug 1 16:54:45 CDT 2017


v2: use proper synchronization; add an MTA test (thanks Sebastian)
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/ole32/compobj.c         | 48 ++++++++++++++++++++++++++++++------------
 dlls/ole32/compobj_private.h |  1 -
 dlls/ole32/tests/compobj.c   | 50 ++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 83 insertions(+), 16 deletions(-)

diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index 60244485249..ee904adbc38 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -170,8 +170,20 @@ struct registered_psclsid
     struct list entry;
     IID iid;
     CLSID clsid;
+    OXID apartment_id;
 };
 
+static struct list RegisteredPSCLSIDList = LIST_INIT(RegisteredPSCLSIDList);
+
+static CRITICAL_SECTION csRegisteredPSCLSIDList;
+static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
+{
+    0, 0, &csRegisteredPSCLSIDList,
+    { &psclsid_cs_debug.ProcessLocksList, &psclsid_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": csRegisteredPSCLSIDList") }
+};
+static CRITICAL_SECTION csRegisteredPSCLSIDList = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
+
 /*
  * This is a marshallable object exposing registered local servers.
  * IServiceProvider is used only because it happens meet requirements
@@ -622,7 +634,6 @@ static APARTMENT *apartment_construct(DWORD model)
 
     list_init(&apt->proxies);
     list_init(&apt->stubmgrs);
-    list_init(&apt->psclsids);
     list_init(&apt->loaded_dlls);
     apt->ipidc = 0;
     apt->refs = 1;
@@ -1173,15 +1184,22 @@ DWORD apartment_release(struct apartment *apt)
             stub_manager_int_release(stubmgr);
         }
 
-        LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->psclsids)
+        EnterCriticalSection(&csRegisteredPSCLSIDList);
+
+        LIST_FOR_EACH_SAFE(cursor, cursor2, &RegisteredPSCLSIDList)
         {
             struct registered_psclsid *registered_psclsid =
                 LIST_ENTRY(cursor, struct registered_psclsid, entry);
 
-            list_remove(&registered_psclsid->entry);
-            HeapFree(GetProcessHeap(), 0, registered_psclsid);
+            if (registered_psclsid->apartment_id == apt->oxid)
+            {
+                list_remove(&registered_psclsid->entry);
+                HeapFree(GetProcessHeap(), 0, registered_psclsid);
+            }
         }
 
+        LeaveCriticalSection(&csRegisteredPSCLSIDList);
+
         /* if this assert fires, then another thread took a reference to a
          * stub manager without taking a reference to the containing
          * apartment, which it must do. */
@@ -2580,9 +2598,9 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
     if (!pclsid)
         return E_INVALIDARG;
 
-    EnterCriticalSection(&apt->cs);
+    EnterCriticalSection(&csRegisteredPSCLSIDList);
 
-    LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
+    LIST_FOR_EACH_ENTRY(registered_psclsid, &RegisteredPSCLSIDList, struct registered_psclsid, entry)
         if (IsEqualIID(&registered_psclsid->iid, riid))
         {
             *pclsid = registered_psclsid->clsid;
@@ -2590,7 +2608,7 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
             return S_OK;
         }
 
-    LeaveCriticalSection(&apt->cs);
+    LeaveCriticalSection(&csRegisteredPSCLSIDList);
 
     data.cbSize = sizeof(data);
     if (FindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION,
@@ -2635,6 +2653,9 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid)
  *
  * NOTES
  *
+ * Unlike CoRegisterClassObject(), CLSIDs registered with CoRegisterPSClsid()
+ * will be returned from other apartments in the same process.
+ *
  * This function does not add anything to the registry and the effects are
  * limited to the lifetime of the current process.
  *
@@ -2654,28 +2675,29 @@ HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid)
         return CO_E_NOTINITIALIZED;
     }
 
-    EnterCriticalSection(&apt->cs);
+    EnterCriticalSection(&csRegisteredPSCLSIDList);
 
-    LIST_FOR_EACH_ENTRY(registered_psclsid, &apt->psclsids, struct registered_psclsid, entry)
+    LIST_FOR_EACH_ENTRY(registered_psclsid, &RegisteredPSCLSIDList, struct registered_psclsid, entry)
         if (IsEqualIID(&registered_psclsid->iid, riid))
         {
             registered_psclsid->clsid = *rclsid;
-            LeaveCriticalSection(&apt->cs);
+            LeaveCriticalSection(&csRegisteredPSCLSIDList);
             return S_OK;
         }
 
     registered_psclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(struct registered_psclsid));
     if (!registered_psclsid)
     {
-        LeaveCriticalSection(&apt->cs);
+        LeaveCriticalSection(&csRegisteredPSCLSIDList);
         return E_OUTOFMEMORY;
     }
 
     registered_psclsid->iid = *riid;
     registered_psclsid->clsid = *rclsid;
-    list_add_head(&apt->psclsids, &registered_psclsid->entry);
+    registered_psclsid->apartment_id = apt->oxid;
+    list_add_head(&RegisteredPSCLSIDList, &registered_psclsid->entry);
 
-    LeaveCriticalSection(&apt->cs);
+    LeaveCriticalSection(&csRegisteredPSCLSIDList);
 
     return S_OK;
 }
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h
index 64b67826bef..fd88ed981b4 100644
--- a/dlls/ole32/compobj_private.h
+++ b/dlls/ole32/compobj_private.h
@@ -137,7 +137,6 @@ struct apartment
   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) */
   LONG remoting_started;   /* has the RPC system been started for this apartment? (LOCK) */
-  struct list psclsids;    /* list of registered PS CLSIDs (CS cs) */
   struct list loaded_dlls; /* list of dlls loaded by this apartment (CS cs) */
   DWORD host_apt_tid;      /* thread ID of apartment hosting objects of differing threading model (CS cs) */
   HWND host_apt_hwnd;      /* handle to apartment window of host apartment (CS cs) */
diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c
index feb1d72eace..0b464345696 100644
--- a/dlls/ole32/tests/compobj.c
+++ b/dlls/ole32/tests/compobj.c
@@ -1158,12 +1158,31 @@ static const CLSID CLSID_WineTestPSFactoryBuffer =
     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
 }; /* 52011640-8164-4fd0-a1a2-5d5a3654d3bd */
 
+static DWORD CALLBACK register_ps_clsid_thread(void *context)
+{
+    HRESULT hr;
+    CLSID clsid = {0};
+
+    pCoInitializeEx(NULL, (DWORD) context);
+
+    hr = CoGetPSClsid(&IID_IWineTest, &clsid);
+    ok_ole_success(hr, "CoGetPSClsid");
+    ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
+                   wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
+
+    CoUninitialize();
+
+    return hr;
+}
+
 static void test_CoRegisterPSClsid(void)
 {
     HRESULT hr;
     DWORD dwRegistrationKey;
     IStream *stream;
     CLSID clsid;
+    HANDLE thread;
+    DWORD tid;
 
     hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
     ok(hr == CO_E_NOTINITIALIZED, "CoRegisterPSClsid should have returned CO_E_NOTINITIALIZED instead of 0x%08x\n", hr);
@@ -1177,6 +1196,16 @@ static void test_CoRegisterPSClsid(void)
     hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
     ok_ole_success(hr, "CoRegisterPSClsid");
 
+    hr = CoGetPSClsid(&IID_IWineTest, &clsid);
+    ok_ole_success(hr, "CoGetPSClsid");
+    ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
+                   wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
+
+    thread = CreateThread(NULL, 0, register_ps_clsid_thread, (void *)COINIT_APARTMENTTHREADED, 0, &tid);
+    ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
+    ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
+    CloseHandle(thread);
+
     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
     ok_ole_success(hr, "CreateStreamOnHGlobal");
 
@@ -1196,11 +1225,11 @@ static void test_CoRegisterPSClsid(void)
 
     SET_EXPECT(CreateStub);
     hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, (IUnknown*)&EnumOLEVERB, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
-    ok(hr == S_OK, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
+    ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr);
     CHECK_CALLED(CreateStub);
 
     hr = CoMarshalInterface(stream, &IID_IEnumOLEVERB, &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
-    ok(hr == S_OK, "CoMarshalInterface should have returned E_NOTIMPL instead of 0x%08x\n", hr);
+    ok(hr == S_OK, "CoMarshalInterface should have returned S_OK instead of 0x%08x\n", hr);
 
     IStream_Release(stream);
     IPSFactoryBuffer_Release(ps_factory_buffer);
@@ -1217,6 +1246,23 @@ static void test_CoRegisterPSClsid(void)
     ok(hr == REGDB_E_IIDNOTREG, "CoGetPSClsid should have returned REGDB_E_IIDNOTREG instead of 0x%08x\n", hr);
 
     CoUninitialize();
+
+    pCoInitializeEx(NULL, COINIT_MULTITHREADED);
+
+    hr = CoRegisterPSClsid(&IID_IWineTest, &CLSID_WineTestPSFactoryBuffer);
+    ok_ole_success(hr, "CoRegisterPSClsid");
+
+    hr = CoGetPSClsid(&IID_IWineTest, &clsid);
+    ok_ole_success(hr, "CoGetPSClsid");
+    ok(IsEqualGUID(&clsid, &CLSID_WineTestPSFactoryBuffer), "expected %s, got %s\n",
+                   wine_dbgstr_guid(&CLSID_WineTestPSFactoryBuffer), wine_dbgstr_guid(&clsid));
+
+    thread = CreateThread(NULL, 0, register_ps_clsid_thread, (void *)COINIT_MULTITHREADED, 0, &tid);
+    ok(thread != NULL, "CreateThread failed with error %d\n", GetLastError());
+    ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
+    CloseHandle(thread);
+
+    CoUninitialize();
 }
 
 static void test_CoGetPSClsid(void)
-- 
2.13.3




More information about the wine-patches mailing list