1 /*
2  * Marshaling Tests
3  *
4  * Copyright 2004 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #define _WIN32_DCOM
22 #define COBJMACROS
23 #define CONST_VTABLE
24 
25 #include <stdarg.h>
26 #include <stdio.h>
27 
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "olectl.h"
32 #include "shlguid.h"
33 #include "shobjidl.h"
34 
35 #include "wine/test.h"
36 #include "wine/heap.h"
37 
38 #define DEFINE_EXPECT(func) \
39     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
40 
41 #define SET_EXPECT(func) \
42     expect_ ## func = TRUE
43 
44 #define CHECK_EXPECT2(func) \
45     do { \
46         ok(expect_ ##func, "unexpected call " #func "\n"); \
47         called_ ## func = TRUE; \
48     }while(0)
49 
50 #define CHECK_EXPECT(func) \
51     do { \
52         CHECK_EXPECT2(func); \
53         expect_ ## func = FALSE; \
54     }while(0)
55 
56 #define CHECK_CALLED(func) \
57     do { \
58         ok(called_ ## func, "expected " #func "\n"); \
59         expect_ ## func = called_ ## func = FALSE; \
60     }while(0)
61 
62 static const GUID CLSID_WineTestPSFactoryBuffer = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
63 static const GUID CLSID_DfMarshal = { 0x0000030b, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } };
64 
65 /* functions that are not present on all versions of Windows */
66 static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
67 static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID);
68 
69 /* helper macros to make tests a bit leaner */
70 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
71 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
72 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
73 #define ok_non_zero_external_conn() do {if (with_external_conn) ok(external_connections, "got no external connections\n");} while(0);
74 #define ok_zero_external_conn() do {if (with_external_conn) ok(!external_connections, "got %d external connections\n", external_connections);} while(0);
75 #define ok_last_release_closes(b) do {if (with_external_conn) ok(last_release_closes == b, "got %d expected %d\n", last_release_closes, b);} while(0);
76 
77 #define OBJREF_SIGNATURE (0x574f454d)
78 #define OBJREF_STANDARD (0x1)
79 #define OBJREF_CUSTOM (0x4)
80 
81 typedef struct tagDUALSTRINGARRAY {
82     unsigned short wNumEntries;
83     unsigned short wSecurityOffset;
84     unsigned short aStringArray[1];
85 } DUALSTRINGARRAY;
86 
87 typedef UINT64 OXID;
88 typedef UINT64 OID;
89 typedef GUID IPID;
90 
91 typedef struct tagSTDOBJREF {
92     ULONG flags;
93     ULONG cPublicRefs;
94     OXID oxid;
95     OID oid;
96     IPID ipid;
97 } STDOBJREF;
98 
99 typedef struct tagOBJREF {
100     ULONG signature;
101     ULONG flags;
102     GUID iid;
103     union {
104         struct OR_STANDARD {
105             STDOBJREF std;
106             DUALSTRINGARRAY saResAddr;
107         } u_standard;
108         struct OR_HANDLER {
109             STDOBJREF std;
110             CLSID clsid;
111             DUALSTRINGARRAY saResAddr;
112         } u_handler;
113         struct OR_CUSTOM {
114             CLSID clsid;
115             ULONG cbExtension;
116             ULONG size;
117             byte *pData;
118         } u_custom;
119     } u_objref;
120 } OBJREF;
121 
122 static const IID IID_IWineTest =
123 {
124     0x5201163f,
125     0x8164,
126     0x4fd0,
127     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
128 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
129 
130 static const IID IID_IRemUnknown =
131 {
132     0x00000131,
133     0x0000,
134     0x0000,
135     {0xc0,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}
136 };
137 
138 #define EXTENTID_WineTest IID_IWineTest
139 #define CLSID_WineTest IID_IWineTest
140 
141 static const CLSID CLSID_WineOOPTest =
142 {
143     0x5201163f,
144     0x8164,
145     0x4fd0,
146     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
147 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
148 
test_cocreateinstance_proxy(void)149 static void test_cocreateinstance_proxy(void)
150 {
151     IUnknown *pProxy;
152     IMultiQI *pMQI;
153     HRESULT hr;
154 
155     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
156 
157     hr = CoCreateInstance(&CLSID_ShellDesktop, NULL, CLSCTX_INPROC, &IID_IUnknown, (void **)&pProxy);
158     ok_ole_success(hr, CoCreateInstance);
159     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (void **)&pMQI);
160     ok(hr == S_OK, "created object is not a proxy, so was created in the wrong apartment\n");
161     if (hr == S_OK)
162         IMultiQI_Release(pMQI);
163     IUnknown_Release(pProxy);
164 
165     CoUninitialize();
166 }
167 
168 static const LARGE_INTEGER ullZero;
169 static LONG cLocks;
170 
LockModule(void)171 static void LockModule(void)
172 {
173     InterlockedIncrement(&cLocks);
174 }
175 
UnlockModule(void)176 static void UnlockModule(void)
177 {
178     InterlockedDecrement(&cLocks);
179 }
180 
181 static BOOL with_external_conn;
182 static DWORD external_connections;
183 static BOOL last_release_closes;
184 
ExternalConnection_QueryInterface(IExternalConnection * iface,REFIID riid,void ** ppv)185 static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv)
186 {
187     ok(0, "unexpected call\n");
188     *ppv = NULL;
189     return E_NOINTERFACE;
190 }
191 
ExternalConnection_AddRef(IExternalConnection * iface)192 static ULONG WINAPI ExternalConnection_AddRef(IExternalConnection *iface)
193 {
194     return 2;
195 }
196 
ExternalConnection_Release(IExternalConnection * iface)197 static ULONG WINAPI ExternalConnection_Release(IExternalConnection *iface)
198 {
199     return 1;
200 }
201 
ExternalConnection_AddConnection(IExternalConnection * iface,DWORD extconn,DWORD reserved)202 static DWORD WINAPI ExternalConnection_AddConnection(IExternalConnection *iface, DWORD extconn, DWORD reserved)
203 {
204     trace("add connection\n");
205     return ++external_connections;
206 }
207 
208 
ExternalConnection_ReleaseConnection(IExternalConnection * iface,DWORD extconn,DWORD reserved,BOOL fLastReleaseCloses)209 static DWORD WINAPI ExternalConnection_ReleaseConnection(IExternalConnection *iface, DWORD extconn,
210         DWORD reserved, BOOL fLastReleaseCloses)
211 {
212     trace("release connection %d\n", fLastReleaseCloses);
213     last_release_closes = fLastReleaseCloses;
214     return --external_connections;
215 }
216 
217 static const IExternalConnectionVtbl ExternalConnectionVtbl = {
218     ExternalConnection_QueryInterface,
219     ExternalConnection_AddRef,
220     ExternalConnection_Release,
221     ExternalConnection_AddConnection,
222     ExternalConnection_ReleaseConnection
223 };
224 
225 static IExternalConnection ExternalConnection = { &ExternalConnectionVtbl };
226 
227 
Test_IUnknown_QueryInterface(LPUNKNOWN iface,REFIID riid,LPVOID * ppvObj)228 static HRESULT WINAPI Test_IUnknown_QueryInterface(
229     LPUNKNOWN iface,
230     REFIID riid,
231     LPVOID *ppvObj)
232 {
233     if (ppvObj == NULL) return E_POINTER;
234 
235     if (IsEqualGUID(riid, &IID_IUnknown))
236     {
237         *ppvObj = iface;
238         IUnknown_AddRef(iface);
239         return S_OK;
240     }
241 
242     *ppvObj = NULL;
243     return E_NOINTERFACE;
244 }
245 
Test_IUnknown_AddRef(LPUNKNOWN iface)246 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
247 {
248     LockModule();
249     return 2; /* non-heap-based object */
250 }
251 
Test_IUnknown_Release(LPUNKNOWN iface)252 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
253 {
254     UnlockModule();
255     return 1; /* non-heap-based object */
256 }
257 
258 static const IUnknownVtbl TestUnknown_Vtbl =
259 {
260     Test_IUnknown_QueryInterface,
261     Test_IUnknown_AddRef,
262     Test_IUnknown_Release,
263 };
264 
265 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
266 
TestCrash_IUnknown_Release(LPUNKNOWN iface)267 static ULONG WINAPI TestCrash_IUnknown_Release(LPUNKNOWN iface)
268 {
269     UnlockModule();
270     if(!cLocks) {
271         trace("crashing...\n");
272         *(int**)0xc = 0;
273     }
274     return 1; /* non-heap-based object */
275 }
276 
277 static const IUnknownVtbl TestCrashUnknown_Vtbl =
278 {
279     Test_IUnknown_QueryInterface,
280     Test_IUnknown_AddRef,
281     TestCrash_IUnknown_Release,
282 };
283 
284 static IUnknown TestCrash_Unknown = { &TestCrashUnknown_Vtbl };
285 
Test_IClassFactory_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID * ppvObj)286 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
287     LPCLASSFACTORY iface,
288     REFIID riid,
289     LPVOID *ppvObj)
290 {
291     if (ppvObj == NULL) return E_POINTER;
292 
293     if (IsEqualGUID(riid, &IID_IUnknown) ||
294         IsEqualGUID(riid, &IID_IClassFactory) ||
295         /* the only other interface Wine is currently able to marshal (for testing two proxies) */
296         IsEqualGUID(riid, &IID_IRemUnknown))
297     {
298         *ppvObj = iface;
299         IClassFactory_AddRef(iface);
300         return S_OK;
301     }
302 
303     if (with_external_conn && IsEqualGUID(riid, &IID_IExternalConnection))
304     {
305         *ppvObj = &ExternalConnection;
306         return S_OK;
307     }
308 
309     *ppvObj = NULL;
310     return E_NOINTERFACE;
311 }
312 
Test_IClassFactory_AddRef(LPCLASSFACTORY iface)313 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
314 {
315     LockModule();
316     return 2; /* non-heap-based object */
317 }
318 
Test_IClassFactory_Release(LPCLASSFACTORY iface)319 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
320 {
321     UnlockModule();
322     return 1; /* non-heap-based object */
323 }
324 
Test_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)325 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
326     LPCLASSFACTORY iface,
327     LPUNKNOWN pUnkOuter,
328     REFIID riid,
329     LPVOID *ppvObj)
330 {
331     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
332     return IUnknown_QueryInterface(&Test_Unknown, riid, ppvObj);
333 }
334 
Test_IClassFactory_LockServer(LPCLASSFACTORY iface,BOOL fLock)335 static HRESULT WINAPI Test_IClassFactory_LockServer(
336     LPCLASSFACTORY iface,
337     BOOL fLock)
338 {
339     return S_OK;
340 }
341 
342 static const IClassFactoryVtbl TestClassFactory_Vtbl =
343 {
344     Test_IClassFactory_QueryInterface,
345     Test_IClassFactory_AddRef,
346     Test_IClassFactory_Release,
347     Test_IClassFactory_CreateInstance,
348     Test_IClassFactory_LockServer
349 };
350 
351 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
352 
353 DEFINE_EXPECT(Invoke);
354 DEFINE_EXPECT(CreateStub);
355 DEFINE_EXPECT(CreateProxy);
356 DEFINE_EXPECT(GetWindow);
357 DEFINE_EXPECT(Disconnect);
358 
OleWindow_QueryInterface(IOleWindow * iface,REFIID riid,void ** ppv)359 static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **ppv)
360 {
361     ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
362     *ppv = NULL;
363     return E_NOINTERFACE;
364 }
365 
OleWindow_AddRef(IOleWindow * iface)366 static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
367 {
368     return 2;
369 }
370 
OleWindow_Release(IOleWindow * iface)371 static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
372 {
373     return 1;
374 }
375 
OleWindow_GetWindow(IOleWindow * iface,HWND * hwnd)376 static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
377 {
378     CHECK_EXPECT(GetWindow);
379     *hwnd = (HWND)0xdeadbeef;
380     return S_OK;
381 }
382 
383 static const IOleWindowVtbl OleWindowVtbl = {
384     OleWindow_QueryInterface,
385     OleWindow_AddRef,
386     OleWindow_Release,
387     OleWindow_GetWindow,
388     /* not needed */
389 };
390 
391 static IOleWindow Test_OleWindow = { &OleWindowVtbl };
392 
OleClientSite_QueryInterface(IOleClientSite * iface,REFIID riid,void ** ppv)393 static HRESULT WINAPI OleClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv)
394 {
395     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleClientSite))
396         *ppv = iface;
397     else if (IsEqualGUID(riid, &IID_IOleWindow))
398         *ppv = &Test_OleWindow;
399     else
400     {
401         *ppv = NULL;
402         return E_NOINTERFACE;
403     }
404 
405     IUnknown_AddRef((IUnknown*)*ppv);
406     return S_OK;
407 }
408 
OleClientSite_AddRef(IOleClientSite * iface)409 static ULONG WINAPI OleClientSite_AddRef(IOleClientSite *iface)
410 {
411     return 2;
412 }
413 
OleClientSite_Release(IOleClientSite * iface)414 static ULONG WINAPI OleClientSite_Release(IOleClientSite *iface)
415 {
416     return 1;
417 }
418 
419 static const IOleClientSiteVtbl OleClientSiteVtbl = {
420     OleClientSite_QueryInterface,
421     OleClientSite_AddRef,
422     OleClientSite_Release,
423     /* we don't need the rest, we never call it */
424 };
425 
426 static IOleClientSite Test_OleClientSite = { &OleClientSiteVtbl };
427 
428 typedef struct {
429     IRpcStubBuffer IRpcStubBuffer_iface;
430     LONG ref;
431     IRpcStubBuffer *buffer;
432 } StubBufferWrapper;
433 
impl_from_IRpcStubBuffer(IRpcStubBuffer * iface)434 static StubBufferWrapper *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
435 {
436     return CONTAINING_RECORD(iface, StubBufferWrapper, IRpcStubBuffer_iface);
437 }
438 
RpcStubBuffer_QueryInterface(IRpcStubBuffer * iface,REFIID riid,void ** ppv)439 static HRESULT WINAPI RpcStubBuffer_QueryInterface(IRpcStubBuffer *iface, REFIID riid, void **ppv)
440 {
441     StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
442 
443     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRpcStubBuffer, riid)) {
444         *ppv = &This->IRpcStubBuffer_iface;
445     }else {
446         *ppv = NULL;
447         return E_NOINTERFACE;
448     }
449 
450     IUnknown_AddRef((IUnknown*)*ppv);
451     return S_OK;
452 }
453 
RpcStubBuffer_AddRef(IRpcStubBuffer * iface)454 static ULONG WINAPI RpcStubBuffer_AddRef(IRpcStubBuffer *iface)
455 {
456     StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
457     return InterlockedIncrement(&This->ref);
458 }
459 
RpcStubBuffer_Release(IRpcStubBuffer * iface)460 static ULONG WINAPI RpcStubBuffer_Release(IRpcStubBuffer *iface)
461 {
462     StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
463     LONG ref = InterlockedDecrement(&This->ref);
464     if(!ref) {
465         IRpcStubBuffer_Release(This->buffer);
466         heap_free(This);
467     }
468     return ref;
469 }
470 
RpcStubBuffer_Connect(IRpcStubBuffer * iface,IUnknown * pUnkServer)471 static HRESULT WINAPI RpcStubBuffer_Connect(IRpcStubBuffer *iface, IUnknown *pUnkServer)
472 {
473     ok(0, "unexpected call\n");
474     return E_NOTIMPL;
475 }
476 
RpcStubBuffer_Disconnect(IRpcStubBuffer * iface)477 static void WINAPI RpcStubBuffer_Disconnect(IRpcStubBuffer *iface)
478 {
479     CHECK_EXPECT(Disconnect);
480 }
481 
RpcStubBuffer_Invoke(IRpcStubBuffer * iface,RPCOLEMESSAGE * _prpcmsg,IRpcChannelBuffer * _pRpcChannelBuffer)482 static HRESULT WINAPI RpcStubBuffer_Invoke(IRpcStubBuffer *iface, RPCOLEMESSAGE *_prpcmsg,
483     IRpcChannelBuffer *_pRpcChannelBuffer)
484 {
485     StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
486     void *dest_context_data;
487     DWORD dest_context;
488     HRESULT hr;
489 
490     CHECK_EXPECT(Invoke);
491 
492     hr = IRpcChannelBuffer_GetDestCtx(_pRpcChannelBuffer, &dest_context, &dest_context_data);
493     ok(hr == S_OK, "GetDestCtx failed: %08x\n", hr);
494     ok(dest_context == MSHCTX_INPROC, "desc_context = %x\n", dest_context);
495     ok(!dest_context_data, "desc_context_data = %p\n", dest_context_data);
496 
497     return IRpcStubBuffer_Invoke(This->buffer, _prpcmsg, _pRpcChannelBuffer);
498 }
499 
RpcStubBuffer_IsIIDSupported(IRpcStubBuffer * iface,REFIID riid)500 static IRpcStubBuffer *WINAPI RpcStubBuffer_IsIIDSupported(IRpcStubBuffer *iface, REFIID riid)
501 {
502     ok(0, "unexpected call\n");
503     return NULL;
504 }
505 
RpcStubBuffer_CountRefs(IRpcStubBuffer * iface)506 static ULONG WINAPI RpcStubBuffer_CountRefs(IRpcStubBuffer *iface)
507 {
508     ok(0, "unexpected call\n");
509     return E_NOTIMPL;
510 }
511 
RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer * iface,void ** ppv)512 static HRESULT WINAPI RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer *iface, void **ppv)
513 {
514     ok(0, "unexpected call\n");
515     return E_NOTIMPL;
516 }
517 
RpcStubBuffer_DebugServerRelease(IRpcStubBuffer * iface,void * pv)518 static void WINAPI RpcStubBuffer_DebugServerRelease(IRpcStubBuffer *iface, void *pv)
519 {
520     ok(0, "unexpected call\n");
521 }
522 
523 static const IRpcStubBufferVtbl RpcStubBufferVtbl = {
524     RpcStubBuffer_QueryInterface,
525     RpcStubBuffer_AddRef,
526     RpcStubBuffer_Release,
527     RpcStubBuffer_Connect,
528     RpcStubBuffer_Disconnect,
529     RpcStubBuffer_Invoke,
530     RpcStubBuffer_IsIIDSupported,
531     RpcStubBuffer_CountRefs,
532     RpcStubBuffer_DebugServerQueryInterface,
533     RpcStubBuffer_DebugServerRelease
534 };
535 
536 static IPSFactoryBuffer *ps_factory_buffer;
537 
PSFactoryBuffer_QueryInterface(IPSFactoryBuffer * iface,REFIID riid,void ** ppv)538 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(IPSFactoryBuffer *iface, REFIID riid, void **ppv)
539 {
540     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPSFactoryBuffer))
541         *ppv = iface;
542     else
543     {
544         *ppv = NULL;
545         return E_NOINTERFACE;
546     }
547     IUnknown_AddRef((IUnknown*)*ppv);
548     return S_OK;
549 }
550 
PSFactoryBuffer_AddRef(IPSFactoryBuffer * iface)551 static ULONG WINAPI PSFactoryBuffer_AddRef(IPSFactoryBuffer *iface)
552 {
553     return 2;
554 }
555 
PSFactoryBuffer_Release(IPSFactoryBuffer * iface)556 static ULONG WINAPI PSFactoryBuffer_Release(IPSFactoryBuffer *iface)
557 {
558     return 1;
559 }
560 
PSFactoryBuffer_CreateProxy(IPSFactoryBuffer * iface,IUnknown * outer,REFIID riid,IRpcProxyBuffer ** ppProxy,void ** ppv)561 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(IPSFactoryBuffer *iface, IUnknown *outer,
562     REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv)
563 {
564     CHECK_EXPECT(CreateProxy);
565     return IPSFactoryBuffer_CreateProxy(ps_factory_buffer, outer, riid, ppProxy, ppv);
566 }
567 
PSFactoryBuffer_CreateStub(IPSFactoryBuffer * iface,REFIID riid,IUnknown * server,IRpcStubBuffer ** ppStub)568 static HRESULT WINAPI PSFactoryBuffer_CreateStub(IPSFactoryBuffer *iface, REFIID riid,
569     IUnknown *server, IRpcStubBuffer **ppStub)
570 {
571     StubBufferWrapper *stub;
572     HRESULT hr;
573 
574     CHECK_EXPECT(CreateStub);
575 
576     ok(server == (IUnknown*)&Test_OleClientSite, "unexpected server %p\n", server);
577 
578     stub = heap_alloc(sizeof(*stub));
579     stub->IRpcStubBuffer_iface.lpVtbl = &RpcStubBufferVtbl;
580     stub->ref = 1;
581 
582     hr = IPSFactoryBuffer_CreateStub(ps_factory_buffer, riid, server, &stub->buffer);
583     ok(hr == S_OK, "CreateStub failed: %08x\n", hr);
584 
585     *ppStub = &stub->IRpcStubBuffer_iface;
586     return S_OK;
587 }
588 
589 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
590 {
591     PSFactoryBuffer_QueryInterface,
592     PSFactoryBuffer_AddRef,
593     PSFactoryBuffer_Release,
594     PSFactoryBuffer_CreateProxy,
595     PSFactoryBuffer_CreateStub
596 };
597 
598 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
599 
600 #define RELEASEMARSHALDATA WM_USER
601 
602 struct host_object_data
603 {
604     IStream *stream;
605     const IID *iid;
606     IUnknown *object;
607     MSHLFLAGS marshal_flags;
608     IMessageFilter *filter;
609     IUnknown *register_object;
610     const CLSID *register_clsid;
611     HANDLE marshal_event;
612 };
613 
614 #ifndef __REACTOS__ /* FIXME: Inspect */
615 static IPSFactoryBuffer PSFactoryBuffer;
616 #endif
617 
host_object_proc(LPVOID p)618 static DWORD CALLBACK host_object_proc(LPVOID p)
619 {
620     struct host_object_data *data = p;
621     DWORD registration_key;
622     HRESULT hr;
623     MSG msg;
624 
625     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
626 
627     if(data->register_object) {
628         hr = CoRegisterClassObject(data->register_clsid, data->register_object,
629             CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &registration_key);
630         ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
631     }
632 
633     if (data->filter)
634     {
635         IMessageFilter * prev_filter = NULL;
636         hr = CoRegisterMessageFilter(data->filter, &prev_filter);
637         if (prev_filter) IMessageFilter_Release(prev_filter);
638         ok_ole_success(hr, CoRegisterMessageFilter);
639     }
640 
641     hr = CoMarshalInterface(data->stream, data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
642     ok_ole_success(hr, CoMarshalInterface);
643 
644     /* force the message queue to be created before signaling parent thread */
645     PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
646 
647     SetEvent(data->marshal_event);
648 
649     while (GetMessageA(&msg, NULL, 0, 0))
650     {
651         if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
652         {
653             CoReleaseMarshalData(data->stream);
654             SetEvent((HANDLE)msg.lParam);
655         }
656         else
657             DispatchMessageA(&msg);
658     }
659 
660     HeapFree(GetProcessHeap(), 0, data);
661 
662     CoUninitialize();
663 
664     return hr;
665 }
666 
start_host_object2(struct host_object_data * object_data,HANDLE * thread)667 static DWORD start_host_object2(struct host_object_data *object_data, HANDLE *thread)
668 {
669     DWORD tid = 0;
670     struct host_object_data *data;
671 
672     data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
673     *data = *object_data;
674     data->marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
675     *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
676 
677     /* wait for marshaling to complete before returning */
678     ok( !WaitForSingleObject(data->marshal_event, 10000), "wait timed out\n" );
679     CloseHandle(data->marshal_event);
680 
681     return tid;
682 }
683 
start_host_object(IStream * stream,REFIID riid,IUnknown * object,MSHLFLAGS marshal_flags,HANDLE * thread)684 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
685 {
686     struct host_object_data object_data = { stream, riid, object, marshal_flags };
687     return start_host_object2(&object_data, thread);
688 }
689 
690 /* asks thread to release the marshal data because it has to be done by the
691  * same thread that marshaled the interface in the first place. */
release_host_object(DWORD tid,WPARAM wp)692 static void release_host_object(DWORD tid, WPARAM wp)
693 {
694     HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
695     PostThreadMessageA(tid, RELEASEMARSHALDATA, wp, (LPARAM)event);
696     ok( !WaitForSingleObject(event, 10000), "wait timed out\n" );
697     CloseHandle(event);
698 }
699 
end_host_object(DWORD tid,HANDLE thread)700 static void end_host_object(DWORD tid, HANDLE thread)
701 {
702     BOOL ret = PostThreadMessageA(tid, WM_QUIT, 0, 0);
703     ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
704     /* be careful of races - don't return until hosting thread has terminated */
705     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
706     CloseHandle(thread);
707 }
708 
709 /* tests failure case of interface not having a marshaler specified in the
710  * registry */
test_no_marshaler(void)711 static void test_no_marshaler(void)
712 {
713     IStream *pStream;
714     HRESULT hr;
715 
716     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
717     ok_ole_success(hr, CreateStreamOnHGlobal);
718     hr = CoMarshalInterface(pStream, &IID_IWineTest, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
719     ok(hr == E_NOINTERFACE, "CoMarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
720 
721     IStream_Release(pStream);
722 }
723 
724 /* tests normal marshal and then release without unmarshaling */
test_normal_marshal_and_release(void)725 static void test_normal_marshal_and_release(void)
726 {
727     HRESULT hr;
728     IStream *pStream = NULL;
729 
730     cLocks = 0;
731     external_connections = 0;
732 
733     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
734     ok_ole_success(hr, CreateStreamOnHGlobal);
735     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
736     ok_ole_success(hr, CoMarshalInterface);
737 
738     ok_more_than_one_lock();
739     ok_non_zero_external_conn();
740 
741     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
742     hr = CoReleaseMarshalData(pStream);
743     ok_ole_success(hr, CoReleaseMarshalData);
744     IStream_Release(pStream);
745 
746     ok_no_locks();
747     ok_zero_external_conn();
748     ok_last_release_closes(TRUE);
749 }
750 
751 /* tests success case of a same-thread marshal and unmarshal */
test_normal_marshal_and_unmarshal(void)752 static void test_normal_marshal_and_unmarshal(void)
753 {
754     HRESULT hr;
755     IStream *pStream = NULL;
756     IUnknown *pProxy = NULL;
757 
758     cLocks = 0;
759     external_connections = 0;
760 
761     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
762     ok_ole_success(hr, CreateStreamOnHGlobal);
763     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
764     ok_ole_success(hr, CoMarshalInterface);
765 
766     ok_more_than_one_lock();
767     ok_non_zero_external_conn();
768 
769     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
770     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
771     ok_ole_success(hr, CoUnmarshalInterface);
772     IStream_Release(pStream);
773 
774     ok_more_than_one_lock();
775     ok_zero_external_conn();
776     ok_last_release_closes(FALSE);
777 
778     IUnknown_Release(pProxy);
779 
780     ok_no_locks();
781 }
782 
783 /* tests failure case of unmarshaling a freed object */
test_marshal_and_unmarshal_invalid(void)784 static void test_marshal_and_unmarshal_invalid(void)
785 {
786     HRESULT hr;
787     IStream *pStream = NULL;
788     IClassFactory *pProxy = NULL;
789     DWORD tid;
790     void * dummy;
791     HANDLE thread;
792 
793     cLocks = 0;
794     external_connections = 0;
795 
796     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
797     ok_ole_success(hr, CreateStreamOnHGlobal);
798     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
799 
800     ok_more_than_one_lock();
801     ok_non_zero_external_conn();
802 
803     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
804     hr = CoReleaseMarshalData(pStream);
805     ok_ole_success(hr, CoReleaseMarshalData);
806 
807     ok_no_locks();
808     ok_zero_external_conn();
809     ok_last_release_closes(TRUE);
810 
811     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
812     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
813     todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
814 
815     ok_no_locks();
816 
817     if (pProxy)
818     {
819         hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, &dummy);
820         ok(hr == RPC_E_DISCONNECTED, "Remote call should have returned RPC_E_DISCONNECTED, instead of 0x%08x\n", hr);
821 
822         IClassFactory_Release(pProxy);
823     }
824 
825     IStream_Release(pStream);
826 
827     end_host_object(tid, thread);
828 }
829 
test_same_apartment_unmarshal_failure(void)830 static void test_same_apartment_unmarshal_failure(void)
831 {
832     HRESULT hr;
833     IStream *pStream;
834     IUnknown *pProxy;
835     static const LARGE_INTEGER llZero;
836 
837     cLocks = 0;
838     external_connections = 0;
839 
840     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
841     ok_ole_success(hr, CreateStreamOnHGlobal);
842 
843     hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
844     ok_ole_success(hr, CoMarshalInterface);
845 
846     ok_more_than_one_lock();
847     ok_non_zero_external_conn();
848 
849     hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
850     ok_ole_success(hr, IStream_Seek);
851 
852     hr = CoUnmarshalInterface(pStream, &IID_IParseDisplayName, (void **)&pProxy);
853     ok(hr == E_NOINTERFACE, "CoUnmarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
854 
855     ok_no_locks();
856     ok_zero_external_conn();
857     ok_last_release_closes(FALSE);
858 
859     IStream_Release(pStream);
860 }
861 
862 /* tests success case of an interthread marshal */
test_interthread_marshal_and_unmarshal(void)863 static void test_interthread_marshal_and_unmarshal(void)
864 {
865     HRESULT hr;
866     IStream *pStream = NULL;
867     IUnknown *pProxy = NULL;
868     DWORD tid;
869     HANDLE thread;
870 
871     cLocks = 0;
872     external_connections = 0;
873 
874     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
875     ok_ole_success(hr, CreateStreamOnHGlobal);
876     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
877 
878     ok_more_than_one_lock();
879     ok_non_zero_external_conn();
880 
881     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
882     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
883     ok_ole_success(hr, CoUnmarshalInterface);
884     IStream_Release(pStream);
885 
886     ok_more_than_one_lock();
887     ok_non_zero_external_conn();
888 
889     IUnknown_Release(pProxy);
890 
891     ok_no_locks();
892     ok_zero_external_conn();
893     ok_last_release_closes(TRUE);
894 
895     end_host_object(tid, thread);
896 }
897 
898 /* the number of external references that Wine's proxy manager normally gives
899  * out, so we can test the border case of running out of references */
900 #define NORMALEXTREFS 5
901 
902 /* tests success case of an interthread marshal and then marshaling the proxy */
test_proxy_marshal_and_unmarshal(void)903 static void test_proxy_marshal_and_unmarshal(void)
904 {
905     HRESULT hr;
906     IStream *pStream = NULL;
907     IUnknown *pProxy = NULL;
908     IUnknown *pProxy2 = NULL;
909     DWORD tid;
910     HANDLE thread;
911     int i;
912 
913     cLocks = 0;
914     external_connections = 0;
915 
916     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
917     ok_ole_success(hr, CreateStreamOnHGlobal);
918     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
919 
920     ok_more_than_one_lock();
921     ok_non_zero_external_conn();
922 
923     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
924     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
925     ok_ole_success(hr, CoUnmarshalInterface);
926 
927     ok_more_than_one_lock();
928 
929     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
930     /* marshal the proxy */
931     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
932     ok_ole_success(hr, CoMarshalInterface);
933 
934     ok_more_than_one_lock();
935 
936     /* marshal 5 more times to exhaust the normal external references of 5 */
937     for (i = 0; i < NORMALEXTREFS; i++)
938     {
939         hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
940         ok_ole_success(hr, CoMarshalInterface);
941     }
942 
943     ok_more_than_one_lock();
944 
945     /* release the original proxy to test that we successfully keep the
946      * original object alive */
947     IUnknown_Release(pProxy);
948 
949     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
950     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
951     ok_ole_success(hr, CoUnmarshalInterface);
952 
953     ok_more_than_one_lock();
954     ok_non_zero_external_conn();
955 
956     IUnknown_Release(pProxy2);
957 
958     /* unmarshal all of the proxies to check that the object stub still exists */
959     for (i = 0; i < NORMALEXTREFS; i++)
960     {
961         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
962         ok_ole_success(hr, CoUnmarshalInterface);
963 
964         IUnknown_Release(pProxy2);
965     }
966 
967     ok_no_locks();
968     ok_zero_external_conn();
969     ok_last_release_closes(TRUE);
970 
971     IStream_Release(pStream);
972 
973     end_host_object(tid, thread);
974 }
975 
976 /* tests success case of an interthread marshal and then marshaling the proxy
977  * using an iid that hasn't previously been unmarshaled */
test_proxy_marshal_and_unmarshal2(void)978 static void test_proxy_marshal_and_unmarshal2(void)
979 {
980     HRESULT hr;
981     IStream *pStream = NULL;
982     IUnknown *pProxy = NULL;
983     IUnknown *pProxy2 = NULL;
984     DWORD tid;
985     HANDLE thread;
986 
987     cLocks = 0;
988     external_connections = 0;
989 
990     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
991     ok_ole_success(hr, CreateStreamOnHGlobal);
992     tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
993 
994     ok_more_than_one_lock();
995     ok_non_zero_external_conn();
996 
997     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
998     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
999     ok_ole_success(hr, CoUnmarshalInterface);
1000 
1001     ok_more_than_one_lock();
1002 
1003     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1004     /* marshal the proxy */
1005     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1006     ok_ole_success(hr, CoMarshalInterface);
1007 
1008     ok_more_than_one_lock();
1009 
1010     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1011     /* unmarshal the second proxy to the object */
1012     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1013     ok_ole_success(hr, CoUnmarshalInterface);
1014     IStream_Release(pStream);
1015 
1016     /* now the proxies should be as follows:
1017      *  pProxy -> &Test_ClassFactory
1018      *  pProxy2 -> &Test_ClassFactory
1019      * they should NOT be as follows:
1020      *  pProxy -> &Test_ClassFactory
1021      *  pProxy2 -> pProxy
1022      * the above can only really be tested by looking in +ole traces
1023      */
1024 
1025     ok_more_than_one_lock();
1026 
1027     IUnknown_Release(pProxy);
1028 
1029     ok_more_than_one_lock();
1030     ok_non_zero_external_conn();
1031 
1032     IUnknown_Release(pProxy2);
1033 
1034     ok_no_locks();
1035     ok_zero_external_conn();
1036     ok_last_release_closes(TRUE);
1037 
1038     end_host_object(tid, thread);
1039 }
1040 
1041 /* tests success case of an interthread marshal and then table-weak-marshaling the proxy */
test_proxy_marshal_and_unmarshal_weak(void)1042 static void test_proxy_marshal_and_unmarshal_weak(void)
1043 {
1044     HRESULT hr;
1045     IStream *pStream = NULL;
1046     IUnknown *pProxy = NULL;
1047     IUnknown *pProxy2 = NULL;
1048     DWORD tid;
1049     HANDLE thread;
1050 
1051     cLocks = 0;
1052     external_connections = 0;
1053 
1054     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1055     ok_ole_success(hr, CreateStreamOnHGlobal);
1056     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1057 
1058     ok_more_than_one_lock();
1059     ok_non_zero_external_conn();
1060 
1061     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1062     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1063     ok_ole_success(hr, CoUnmarshalInterface);
1064 
1065     ok_more_than_one_lock();
1066     ok_non_zero_external_conn();
1067 
1068     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1069     /* marshal the proxy */
1070     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
1071     ok_ole_success(hr, CoMarshalInterface);
1072 
1073     ok_more_than_one_lock();
1074     ok_non_zero_external_conn();
1075 
1076     /* release the original proxy to test that we successfully keep the
1077      * original object alive */
1078     IUnknown_Release(pProxy);
1079 
1080     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1081     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1082     todo_wine
1083     ok(hr == CO_E_OBJNOTREG, "CoUnmarshalInterface should return CO_E_OBJNOTREG instead of 0x%08x\n", hr);
1084 
1085     ok_no_locks();
1086     ok_zero_external_conn();
1087     ok_last_release_closes(TRUE);
1088 
1089     IStream_Release(pStream);
1090 
1091     end_host_object(tid, thread);
1092 }
1093 
1094 /* tests success case of an interthread marshal and then table-strong-marshaling the proxy */
test_proxy_marshal_and_unmarshal_strong(void)1095 static void test_proxy_marshal_and_unmarshal_strong(void)
1096 {
1097     HRESULT hr;
1098     IStream *pStream = NULL;
1099     IUnknown *pProxy = NULL;
1100     IUnknown *pProxy2 = NULL;
1101     DWORD tid;
1102     HANDLE thread;
1103 
1104     cLocks = 0;
1105     external_connections = 0;
1106 
1107     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1108     ok_ole_success(hr, CreateStreamOnHGlobal);
1109     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1110 
1111     ok_more_than_one_lock();
1112     ok_non_zero_external_conn();
1113 
1114     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1115     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1116     ok_ole_success(hr, CoUnmarshalInterface);
1117 
1118     ok_more_than_one_lock();
1119     ok_non_zero_external_conn();
1120 
1121     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1122     /* marshal the proxy */
1123     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG);
1124     ok(hr == S_OK /* WinNT */ || hr == E_INVALIDARG /* Win9x */,
1125         "CoMarshalInterface should have return S_OK or E_INVALIDARG instead of 0x%08x\n", hr);
1126     if (FAILED(hr))
1127     {
1128         IUnknown_Release(pProxy);
1129         goto end;
1130     }
1131 
1132     ok_more_than_one_lock();
1133     ok_non_zero_external_conn();
1134 
1135     /* release the original proxy to test that we successfully keep the
1136      * original object alive */
1137     IUnknown_Release(pProxy);
1138 
1139     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1140     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1141     ok_ole_success(hr, CoUnmarshalInterface);
1142 
1143     ok_more_than_one_lock();
1144     ok_non_zero_external_conn();
1145 
1146     IUnknown_Release(pProxy2);
1147 
1148     ok_more_than_one_lock();
1149     ok_non_zero_external_conn();
1150 
1151 end:
1152     IStream_Release(pStream);
1153 
1154     end_host_object(tid, thread);
1155 
1156     ok_no_locks();
1157 todo_wine {
1158     ok_zero_external_conn();
1159     ok_last_release_closes(FALSE);
1160 }
1161 }
1162 
1163 /* tests that stubs are released when the containing apartment is destroyed */
test_marshal_stub_apartment_shutdown(void)1164 static void test_marshal_stub_apartment_shutdown(void)
1165 {
1166     HRESULT hr;
1167     IStream *pStream = NULL;
1168     IUnknown *pProxy = NULL;
1169     DWORD tid;
1170     HANDLE thread;
1171 
1172     cLocks = 0;
1173     external_connections = 0;
1174 
1175     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1176     ok_ole_success(hr, CreateStreamOnHGlobal);
1177     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1178 
1179     ok_more_than_one_lock();
1180     ok_non_zero_external_conn();
1181 
1182     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1183     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1184     ok_ole_success(hr, CoUnmarshalInterface);
1185     IStream_Release(pStream);
1186 
1187     ok_more_than_one_lock();
1188     ok_non_zero_external_conn();
1189 
1190     end_host_object(tid, thread);
1191 
1192     ok_no_locks();
1193 todo_wine {
1194     ok_zero_external_conn();
1195     ok_last_release_closes(FALSE);
1196 }
1197 
1198     IUnknown_Release(pProxy);
1199 
1200     ok_no_locks();
1201 }
1202 
1203 /* tests that proxies are released when the containing apartment is destroyed */
test_marshal_proxy_apartment_shutdown(void)1204 static void test_marshal_proxy_apartment_shutdown(void)
1205 {
1206     HRESULT hr;
1207     IStream *pStream = NULL;
1208     IClassFactory *proxy;
1209     IUnknown *unk;
1210     ULONG ref;
1211     DWORD tid;
1212     HANDLE thread;
1213 
1214     cLocks = 0;
1215     external_connections = 0;
1216 
1217     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1218     ok_ole_success(hr, CreateStreamOnHGlobal);
1219     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1220 
1221     ok_more_than_one_lock();
1222     ok_non_zero_external_conn();
1223 
1224     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1225     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1226     ok_ole_success(hr, CoUnmarshalInterface);
1227     IStream_Release(pStream);
1228 
1229     ok_more_than_one_lock();
1230     ok_non_zero_external_conn();
1231 
1232     CoUninitialize();
1233 
1234     ok_no_locks();
1235     ok_zero_external_conn();
1236     ok_last_release_closes(TRUE);
1237 
1238     hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&unk);
1239     ok(hr == CO_E_OBJNOTCONNECTED, "got %#x\n", hr);
1240 
1241     ref = IClassFactory_Release(proxy);
1242     ok(!ref, "got %d refs\n", ref);
1243 
1244     ok_no_locks();
1245 
1246     end_host_object(tid, thread);
1247 
1248     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1249 }
1250 
1251 /* tests that proxies are released when the containing mta apartment is destroyed */
test_marshal_proxy_mta_apartment_shutdown(void)1252 static void test_marshal_proxy_mta_apartment_shutdown(void)
1253 {
1254     HRESULT hr;
1255     IStream *pStream = NULL;
1256     IUnknown *pProxy = NULL;
1257     DWORD tid;
1258     HANDLE thread;
1259 
1260     CoUninitialize();
1261     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1262 
1263     cLocks = 0;
1264     external_connections = 0;
1265 
1266     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1267     ok_ole_success(hr, CreateStreamOnHGlobal);
1268     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1269 
1270     ok_more_than_one_lock();
1271     ok_non_zero_external_conn();
1272 
1273     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1274     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1275     ok_ole_success(hr, CoUnmarshalInterface);
1276     IStream_Release(pStream);
1277 
1278     ok_more_than_one_lock();
1279     ok_non_zero_external_conn();
1280 
1281     CoUninitialize();
1282 
1283     ok_no_locks();
1284     ok_zero_external_conn();
1285     ok_last_release_closes(TRUE);
1286 
1287     IUnknown_Release(pProxy);
1288 
1289     ok_no_locks();
1290 
1291     end_host_object(tid, thread);
1292 
1293     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1294 }
1295 
test_marshal_channel_buffer(void)1296 static void test_marshal_channel_buffer(void)
1297 {
1298     DWORD registration_key;
1299     IUnknown *proxy = NULL;
1300     IOleWindow *ole_window;
1301     HWND hwnd;
1302     CLSID clsid;
1303     DWORD tid;
1304     HANDLE thread;
1305     HRESULT hr;
1306 
1307     struct host_object_data object_data = { NULL, &IID_IOleClientSite, (IUnknown*)&Test_OleClientSite,
1308                                             MSHLFLAGS_NORMAL, NULL, (IUnknown*)&PSFactoryBuffer,
1309                                             &CLSID_WineTestPSFactoryBuffer };
1310 
1311     cLocks = 0;
1312     external_connections = 0;
1313 
1314     hr = CoGetPSClsid(&IID_IOleWindow, &clsid);
1315     ok_ole_success(hr, "CoGetPSClsid");
1316 
1317     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer,
1318         (void **)&ps_factory_buffer);
1319     ok_ole_success(hr, "CoGetClassObject");
1320 
1321     hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
1322     ok_ole_success(hr, CreateStreamOnHGlobal);
1323     tid = start_host_object2(&object_data, &thread);
1324 
1325     IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
1326     hr = CoUnmarshalInterface(object_data.stream, &IID_IUnknown, (void **)&proxy);
1327     ok_ole_success(hr, CoUnmarshalInterface);
1328     IStream_Release(object_data.stream);
1329 
1330     hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
1331         CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &registration_key);
1332     ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
1333 
1334     hr = CoRegisterPSClsid(&IID_IOleWindow, &CLSID_WineTestPSFactoryBuffer);
1335     ok(hr == S_OK, "CoRegisterPSClsid failed: %08x\n", hr);
1336 
1337     SET_EXPECT(CreateStub);
1338     SET_EXPECT(CreateProxy);
1339     hr = IUnknown_QueryInterface(proxy, &IID_IOleWindow, (void**)&ole_window);
1340     ok(hr == S_OK, "Could not get IOleWindow iface: %08x\n", hr);
1341     CHECK_CALLED(CreateStub);
1342     CHECK_CALLED(CreateProxy);
1343 
1344     SET_EXPECT(Invoke);
1345     SET_EXPECT(GetWindow);
1346     hr = IOleWindow_GetWindow(ole_window, &hwnd);
1347     ok(hr == S_OK, "GetWindow failed: %08x\n", hr);
1348     ok((DWORD)(DWORD_PTR)hwnd == 0xdeadbeef, "hwnd = %p\n", hwnd);
1349     CHECK_CALLED(Invoke);
1350     CHECK_CALLED(GetWindow);
1351 
1352     IOleWindow_Release(ole_window);
1353 
1354     SET_EXPECT(Disconnect);
1355     IUnknown_Release(proxy);
1356 todo_wine
1357     CHECK_CALLED(Disconnect);
1358 
1359     hr = CoRevokeClassObject(registration_key);
1360     ok(hr == S_OK, "CoRevokeClassObject failed: %08x\n", hr);
1361 
1362     end_host_object(tid, thread);
1363 }
1364 
1365 static const CLSID *unmarshal_class;
1366 DEFINE_EXPECT(CustomMarshal_GetUnmarshalClass);
1367 DEFINE_EXPECT(CustomMarshal_GetMarshalSizeMax);
1368 DEFINE_EXPECT(CustomMarshal_MarshalInterface);
1369 
CustomMarshal_QueryInterface(IMarshal * iface,REFIID riid,void ** ppv)1370 static HRESULT WINAPI CustomMarshal_QueryInterface(IMarshal *iface, REFIID riid, void **ppv)
1371 {
1372     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal)) {
1373         *ppv = iface;
1374     }
1375     else
1376     {
1377         *ppv = NULL;
1378         return E_NOINTERFACE;
1379     }
1380     IUnknown_AddRef((IUnknown*)*ppv);
1381     return S_OK;
1382 }
1383 
CustomMarshal_AddRef(IMarshal * iface)1384 static ULONG WINAPI CustomMarshal_AddRef(IMarshal *iface)
1385 {
1386     return 2;
1387 }
1388 
CustomMarshal_Release(IMarshal * iface)1389 static ULONG WINAPI CustomMarshal_Release(IMarshal *iface)
1390 {
1391     return 1;
1392 }
1393 
CustomMarshal_GetUnmarshalClass(IMarshal * iface,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags,CLSID * clsid)1394 static HRESULT WINAPI CustomMarshal_GetUnmarshalClass(IMarshal *iface, REFIID riid,
1395         void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *clsid)
1396 {
1397     CHECK_EXPECT(CustomMarshal_GetUnmarshalClass);
1398     *clsid = *unmarshal_class;
1399     return S_OK;
1400 }
1401 
CustomMarshal_GetMarshalSizeMax(IMarshal * iface,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags,DWORD * size)1402 static HRESULT WINAPI CustomMarshal_GetMarshalSizeMax(IMarshal *iface, REFIID riid,
1403         void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *size)
1404 {
1405     CHECK_EXPECT(CustomMarshal_GetMarshalSizeMax);
1406     ok(size != NULL, "size = NULL\n");
1407 
1408     *size = 0;
1409     return S_OK;
1410 }
1411 
CustomMarshal_MarshalInterface(IMarshal * iface,IStream * stream,REFIID riid,void * pv,DWORD dwDestContext,void * pvDestContext,DWORD mshlflags)1412 static HRESULT WINAPI CustomMarshal_MarshalInterface(IMarshal *iface, IStream *stream,
1413         REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
1414 {
1415     IMarshal *std_marshal;
1416     STATSTG stat;
1417     HRESULT hr;
1418 
1419     CHECK_EXPECT(CustomMarshal_MarshalInterface);
1420 
1421     if(unmarshal_class != &CLSID_StdMarshal)
1422         return S_OK;
1423 
1424     hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT);
1425     ok_ole_success(hr, IStream_Stat);
1426     ok(U(stat.cbSize).LowPart == 0, "stream is not empty (%d)\n", U(stat.cbSize).LowPart);
1427     ok(U(stat.cbSize).HighPart == 0, "stream is not empty (%d)\n", U(stat.cbSize).HighPart);
1428 
1429     hr = CoGetStandardMarshal(riid, (IUnknown*)iface,
1430             dwDestContext, NULL, mshlflags, &std_marshal);
1431     ok_ole_success(hr, CoGetStandardMarshal);
1432     hr = IMarshal_MarshalInterface(std_marshal, stream, riid, pv,
1433             dwDestContext, pvDestContext, mshlflags);
1434     ok_ole_success(hr, IMarshal_MarshalInterface);
1435     IMarshal_Release(std_marshal);
1436 
1437     return S_OK;
1438 }
1439 
CustomMarshal_UnmarshalInterface(IMarshal * iface,IStream * stream,REFIID riid,void ** ppv)1440 static HRESULT WINAPI CustomMarshal_UnmarshalInterface(IMarshal *iface,
1441         IStream *stream, REFIID riid, void **ppv)
1442 {
1443     ok(0, "unexpected call\n");
1444     return E_NOTIMPL;
1445 }
1446 
CustomMarshal_ReleaseMarshalData(IMarshal * iface,IStream * stream)1447 static HRESULT WINAPI CustomMarshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
1448 {
1449     ok(0, "unexpected call\n");
1450     return E_NOTIMPL;
1451 }
1452 
CustomMarshal_DisconnectObject(IMarshal * iface,DWORD res)1453 static HRESULT WINAPI CustomMarshal_DisconnectObject(IMarshal *iface, DWORD res)
1454 {
1455     ok(0, "unexpected call\n");
1456     return E_NOTIMPL;
1457 }
1458 
1459 static IMarshalVtbl CustomMarshalVtbl =
1460 {
1461     CustomMarshal_QueryInterface,
1462     CustomMarshal_AddRef,
1463     CustomMarshal_Release,
1464     CustomMarshal_GetUnmarshalClass,
1465     CustomMarshal_GetMarshalSizeMax,
1466     CustomMarshal_MarshalInterface,
1467     CustomMarshal_UnmarshalInterface,
1468     CustomMarshal_ReleaseMarshalData,
1469     CustomMarshal_DisconnectObject
1470 };
1471 
1472 static IMarshal CustomMarshal = { &CustomMarshalVtbl };
1473 
test_StdMarshal_custom_marshaling(void)1474 static void test_StdMarshal_custom_marshaling(void)
1475 {
1476     IStream *stream;
1477     IUnknown *unk;
1478     DWORD size;
1479     HRESULT hr;
1480 
1481     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1482     ok_ole_success(hr, CreateStreamOnHGlobal);
1483 
1484     unmarshal_class = &CLSID_StdMarshal;
1485     SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1486     SET_EXPECT(CustomMarshal_MarshalInterface);
1487     hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1488             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1489     ok_ole_success(hr, CoMarshalInterface);
1490     CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1491     CHECK_CALLED(CustomMarshal_MarshalInterface);
1492 
1493     hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1494     ok_ole_success(hr, IStream_Seek);
1495     hr = CoUnmarshalInterface(stream, &IID_IUnknown, (void**)&unk);
1496     ok_ole_success(hr, CoUnmarshalInterface);
1497     ok(unk == (IUnknown*)&CustomMarshal, "unk != &CustomMarshal\n");
1498     IUnknown_Release(unk);
1499     IStream_Release(stream);
1500 
1501     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1502     ok_ole_success(hr, CreateStreamOnHGlobal);
1503 
1504     SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1505     SET_EXPECT(CustomMarshal_MarshalInterface);
1506     hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1507             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1508     ok_ole_success(hr, CoMarshalInterface);
1509     CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1510     CHECK_CALLED(CustomMarshal_MarshalInterface);
1511 
1512     hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1513     ok_ole_success(hr, IStream_Seek);
1514     hr = CoReleaseMarshalData(stream);
1515     ok_ole_success(hr, CoReleaseMarshalData);
1516     IStream_Release(stream);
1517 
1518     SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1519     hr = CoGetMarshalSizeMax(&size, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1520             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1521     ok_ole_success(hr, CoGetMarshalSizeMax);
1522     CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1523     ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF));
1524 }
1525 
test_DfMarshal_custom_marshaling(void)1526 static void test_DfMarshal_custom_marshaling(void)
1527 {
1528     DWORD size, read;
1529     IStream *stream;
1530     OBJREF objref;
1531     HRESULT hr;
1532 
1533     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1534     ok_ole_success(hr, CreateStreamOnHGlobal);
1535 
1536     unmarshal_class = &CLSID_DfMarshal;
1537     SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1538     SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1539     SET_EXPECT(CustomMarshal_MarshalInterface);
1540     hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1541             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1542     ok_ole_success(hr, CoMarshalInterface);
1543     CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1544     CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1545     CHECK_CALLED(CustomMarshal_MarshalInterface);
1546 
1547     hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1548     ok_ole_success(hr, IStream_Seek);
1549     size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData);
1550     hr = IStream_Read(stream, &objref, size, &read);
1551     ok_ole_success(hr, IStream_Read);
1552     ok(read == size, "read = %d, expected %d\n", read, size);
1553     ok(objref.signature == OBJREF_SIGNATURE, "objref.signature = %x\n",
1554             objref.signature);
1555     ok(objref.flags == OBJREF_CUSTOM, "objref.flags = %x\n", objref.flags);
1556     ok(IsEqualIID(&objref.iid, &IID_IUnknown), "objref.iid = %s\n",
1557             wine_dbgstr_guid(&objref.iid));
1558     ok(IsEqualIID(&objref.u_objref.u_custom.clsid, &CLSID_DfMarshal),
1559             "custom.clsid = %s\n", wine_dbgstr_guid(&objref.u_objref.u_custom.clsid));
1560     ok(!objref.u_objref.u_custom.cbExtension, "custom.cbExtension = %d\n",
1561             objref.u_objref.u_custom.cbExtension);
1562     ok(!objref.u_objref.u_custom.size, "custom.size = %d\n",
1563             objref.u_objref.u_custom.size);
1564 
1565     IStream_Release(stream);
1566 
1567     SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1568     hr = CoGetMarshalSizeMax(&size, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1569             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1570     ok_ole_success(hr, CoGetMarshalSizeMax);
1571     CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1572     ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF));
1573 }
1574 
test_CoGetStandardMarshal(void)1575 static void test_CoGetStandardMarshal(void)
1576 {
1577     DUALSTRINGARRAY *dualstringarr;
1578     STDOBJREF *stdobjref;
1579     OBJREF objref;
1580     IMarshal *marshal;
1581     DWORD size, read;
1582     IStream *stream;
1583     IUnknown *unk;
1584     CLSID clsid;
1585     HRESULT hr;
1586 
1587     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1588     ok_ole_success(hr, CreateStreamOnHGlobal);
1589 
1590     hr = CoGetStandardMarshal(&IID_IUnknown, &Test_Unknown,
1591             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &marshal);
1592     ok_ole_success(hr, CoGetStandardMarshal);
1593 
1594     hr = IMarshal_GetUnmarshalClass(marshal, &IID_IUnknown, &Test_Unknown,
1595             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &clsid);
1596     ok_ole_success(hr, IMarshal_GetUnmarshalClass);
1597     ok(IsEqualGUID(&clsid, &CLSID_StdMarshal), "clsid = %s\n", wine_dbgstr_guid(&clsid));
1598 
1599     hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IUnknown, &Test_Unknown,
1600             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &size);
1601     ok_ole_success(hr, IMarshal_GetMarshalSizeMax);
1602     hr = CoGetMarshalSizeMax(&read, &IID_IUnknown, &Test_Unknown,
1603             MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1604     ok_ole_success(hr, CoGetMarshalSizeMax);
1605     ok(size == read, "IMarshal_GetMarshalSizeMax size = %d, expected %d\n", size, read);
1606 
1607     hr = IMarshal_MarshalInterface(marshal, stream, &IID_IUnknown,
1608             &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1609     ok_ole_success(hr, IMarshal_MarshalInterface);
1610 
1611     hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1612     ok_ole_success(hr, IStream_Seek);
1613     size = FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray);
1614     hr = IStream_Read(stream, &objref, size, &read);
1615     ok_ole_success(hr, IStream_Read);
1616     ok(read == size, "read = %d, expected %d\n", read, size);
1617     ok(objref.signature == OBJREF_SIGNATURE, "objref.signature = %x\n",
1618             objref.signature);
1619     ok(objref.flags == OBJREF_STANDARD, "objref.flags = %x\n", objref.flags);
1620     ok(IsEqualIID(&objref.iid, &IID_IUnknown), "objref.iid = %s\n",
1621             wine_dbgstr_guid(&objref.iid));
1622     stdobjref = &objref.u_objref.u_standard.std;
1623     ok(stdobjref->flags == 0, "stdobjref.flags = %d\n", stdobjref->flags);
1624     ok(stdobjref->cPublicRefs == 5, "stdobjref.cPublicRefs = %d\n",
1625             stdobjref->cPublicRefs);
1626     dualstringarr = &objref.u_objref.u_standard.saResAddr;
1627     ok(dualstringarr->wNumEntries == 0, "dualstringarr.wNumEntries = %d\n",
1628             dualstringarr->wNumEntries);
1629     ok(dualstringarr->wSecurityOffset == 0, "dualstringarr.wSecurityOffset = %d\n",
1630             dualstringarr->wSecurityOffset);
1631 
1632     hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1633     ok_ole_success(hr, IStream_Seek);
1634     hr = IMarshal_UnmarshalInterface(marshal, stream, &IID_IUnknown, (void**)&unk);
1635     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1636     IUnknown_Release(unk);
1637 
1638     hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1639     ok_ole_success(hr, IStream_Seek);
1640     hr = IMarshal_MarshalInterface(marshal, stream, &IID_IUnknown,
1641             &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1642     ok_ole_success(hr, IMarshal_MarshalInterface);
1643 
1644     hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1645     ok_ole_success(hr, IStream_Seek);
1646     hr = IMarshal_ReleaseMarshalData(marshal, stream);
1647     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1648     IStream_Release(stream);
1649 
1650     IMarshal_Release(marshal);
1651 }
1652 struct ncu_params
1653 {
1654     LPSTREAM stream;
1655     HANDLE marshal_event;
1656     HANDLE unmarshal_event;
1657 };
1658 
1659 /* helper for test_no_couninitialize_server */
no_couninitialize_server_proc(LPVOID p)1660 static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p)
1661 {
1662     struct ncu_params *ncu_params = p;
1663     HRESULT hr;
1664 
1665     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1666 
1667     hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1668     ok_ole_success(hr, CoMarshalInterface);
1669 
1670     SetEvent(ncu_params->marshal_event);
1671 
1672     ok( !WaitForSingleObject(ncu_params->unmarshal_event, 10000), "wait timed out\n" );
1673 
1674     /* die without calling CoUninitialize */
1675 
1676     return 0;
1677 }
1678 
1679 /* tests apartment that an apartment with a stub is released without deadlock
1680  * if the owning thread exits */
test_no_couninitialize_server(void)1681 static void test_no_couninitialize_server(void)
1682 {
1683     HRESULT hr;
1684     IStream *pStream = NULL;
1685     IUnknown *pProxy = NULL;
1686     DWORD tid;
1687     HANDLE thread;
1688     struct ncu_params ncu_params;
1689 
1690     cLocks = 0;
1691     external_connections = 0;
1692 
1693     ncu_params.marshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
1694     ncu_params.unmarshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
1695 
1696     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1697     ok_ole_success(hr, CreateStreamOnHGlobal);
1698     ncu_params.stream = pStream;
1699 
1700     thread = CreateThread(NULL, 0, no_couninitialize_server_proc, &ncu_params, 0, &tid);
1701 
1702     ok( !WaitForSingleObject(ncu_params.marshal_event, 10000), "wait timed out\n" );
1703     ok_more_than_one_lock();
1704     ok_non_zero_external_conn();
1705 
1706     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1707     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1708     ok_ole_success(hr, CoUnmarshalInterface);
1709     IStream_Release(pStream);
1710 
1711     ok_more_than_one_lock();
1712     ok_non_zero_external_conn();
1713 
1714     SetEvent(ncu_params.unmarshal_event);
1715     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1716 
1717     ok_no_locks();
1718 todo_wine {
1719     ok_zero_external_conn();
1720     ok_last_release_closes(FALSE);
1721 }
1722 
1723     CloseHandle(thread);
1724     CloseHandle(ncu_params.marshal_event);
1725     CloseHandle(ncu_params.unmarshal_event);
1726 
1727     IUnknown_Release(pProxy);
1728 
1729     ok_no_locks();
1730 }
1731 
1732 /* STA -> STA call during DLL_THREAD_DETACH */
no_couninitialize_client_proc(LPVOID p)1733 static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p)
1734 {
1735     struct ncu_params *ncu_params = p;
1736     HRESULT hr;
1737     IUnknown *pProxy = NULL;
1738 
1739     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1740 
1741     hr = CoUnmarshalInterface(ncu_params->stream, &IID_IClassFactory, (void **)&pProxy);
1742     ok_ole_success(hr, CoUnmarshalInterface);
1743     IStream_Release(ncu_params->stream);
1744 
1745     ok_more_than_one_lock();
1746 
1747     /* die without calling CoUninitialize */
1748 
1749     return 0;
1750 }
1751 
1752 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
test_no_couninitialize_client(void)1753 static void test_no_couninitialize_client(void)
1754 {
1755     HRESULT hr;
1756     IStream *pStream = NULL;
1757     DWORD tid;
1758     DWORD host_tid;
1759     HANDLE thread;
1760     HANDLE host_thread;
1761     struct ncu_params ncu_params;
1762 
1763     cLocks = 0;
1764     external_connections = 0;
1765 
1766     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1767     ok_ole_success(hr, CreateStreamOnHGlobal);
1768     ncu_params.stream = pStream;
1769 
1770     /* NOTE: assumes start_host_object uses an STA to host the object, as MTAs
1771      * always deadlock when called from within DllMain */
1772     host_tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
1773     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1774 
1775     ok_more_than_one_lock();
1776     ok_non_zero_external_conn();
1777 
1778     thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
1779 
1780     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1781     CloseHandle(thread);
1782 
1783     ok_no_locks();
1784     ok_zero_external_conn();
1785     ok_last_release_closes(TRUE);
1786 
1787     end_host_object(host_tid, host_thread);
1788 }
1789 
1790 static BOOL crash_thread_success;
1791 
crash_couninitialize_proc(void * p)1792 static DWORD CALLBACK crash_couninitialize_proc(void *p)
1793 {
1794     IStream *stream;
1795     HRESULT hr;
1796 
1797     cLocks = 0;
1798 
1799     CoInitialize(NULL);
1800 
1801     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1802     ok_ole_success(hr, CreateStreamOnHGlobal);
1803 
1804     hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1805     ok_ole_success(hr, CoMarshalInterface);
1806 
1807     IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1808 
1809     hr = CoReleaseMarshalData(stream);
1810     ok_ole_success(hr, CoReleaseMarshalData);
1811 
1812     ok_no_locks();
1813 
1814     hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1815     ok_ole_success(hr, CoMarshalInterface);
1816 
1817     ok_more_than_one_lock();
1818 
1819     trace("CoUninitialize >>>\n");
1820     CoUninitialize();
1821     trace("CoUninitialize <<<\n");
1822 
1823     ok_no_locks();
1824 
1825     IStream_Release(stream);
1826     crash_thread_success = TRUE;
1827     return 0;
1828 }
1829 
test_crash_couninitialize(void)1830 static void test_crash_couninitialize(void)
1831 {
1832     HANDLE thread;
1833     DWORD tid;
1834 
1835     if(!GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateActCtxW")) {
1836         win_skip("Skipping crash tests on win2k.\n");
1837         return;
1838     }
1839 
1840     crash_thread_success = FALSE;
1841     thread = CreateThread(NULL, 0, crash_couninitialize_proc, NULL, 0, &tid);
1842     ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1843     CloseHandle(thread);
1844     ok(crash_thread_success, "Crash thread failed\n");
1845 }
1846 
1847 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
test_tableweak_marshal_and_unmarshal_twice(void)1848 static void test_tableweak_marshal_and_unmarshal_twice(void)
1849 {
1850     HRESULT hr;
1851     IStream *pStream = NULL;
1852     IUnknown *pProxy1 = NULL;
1853     IUnknown *pProxy2 = NULL;
1854     DWORD tid;
1855     HANDLE thread;
1856 
1857     cLocks = 0;
1858     external_connections = 0;
1859 
1860     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1861     ok_ole_success(hr, CreateStreamOnHGlobal);
1862     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1863 
1864     ok_more_than_one_lock();
1865     ok_zero_external_conn();
1866 
1867     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1868     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1869     ok_ole_success(hr, CoUnmarshalInterface);
1870 
1871     ok_more_than_one_lock();
1872     ok_non_zero_external_conn();
1873 
1874     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1875     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1876     ok_ole_success(hr, CoUnmarshalInterface);
1877 
1878     ok_more_than_one_lock();
1879 
1880     IUnknown_Release(pProxy1);
1881     ok_non_zero_external_conn();
1882     IUnknown_Release(pProxy2);
1883     ok_zero_external_conn();
1884     ok_last_release_closes(TRUE);
1885 
1886     /* When IExternalConnection is present COM's lifetime management
1887      * behaviour is altered; the remaining weak ref prevents stub shutdown. */
1888     if (with_external_conn)
1889     {
1890         ok_more_than_one_lock();
1891         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1892         release_host_object(tid, 0);
1893     }
1894 
1895     /* Without IExternalConnection this line is shows the difference between weak and strong table marshaling
1896      * weak has cLocks == 0, strong has cLocks > 0. */
1897     ok_no_locks();
1898 
1899     IStream_Release(pStream);
1900     end_host_object(tid, thread);
1901 }
1902 
1903 /* tests releasing after unmarshaling one object */
test_tableweak_marshal_releasedata1(void)1904 static void test_tableweak_marshal_releasedata1(void)
1905 {
1906     HRESULT hr;
1907     IStream *pStream = NULL;
1908     IUnknown *pProxy1 = NULL;
1909     IUnknown *pProxy2 = NULL;
1910     DWORD tid;
1911     HANDLE thread;
1912 
1913     cLocks = 0;
1914     external_connections = 0;
1915 
1916     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1917     ok_ole_success(hr, CreateStreamOnHGlobal);
1918     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1919 
1920     ok_more_than_one_lock();
1921     ok_zero_external_conn();
1922 
1923     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1924     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1925     ok_ole_success(hr, CoUnmarshalInterface);
1926 
1927     ok_more_than_one_lock();
1928     ok_non_zero_external_conn();
1929 
1930     /* release the remaining reference on the object by calling
1931      * CoReleaseMarshalData in the hosting thread */
1932     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1933     release_host_object(tid, 0);
1934 
1935     ok_more_than_one_lock();
1936     ok_non_zero_external_conn();
1937 
1938     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1939     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1940     ok_ole_success(hr, CoUnmarshalInterface);
1941     IStream_Release(pStream);
1942 
1943     ok_more_than_one_lock();
1944     ok_non_zero_external_conn();
1945 
1946     IUnknown_Release(pProxy1);
1947 
1948     if (pProxy2)
1949     {
1950         ok_non_zero_external_conn();
1951         IUnknown_Release(pProxy2);
1952     }
1953 
1954     /* this line is shows the difference between weak and strong table marshaling:
1955      *  weak has cLocks == 0
1956      *  strong has cLocks > 0 */
1957     ok_no_locks();
1958     ok_zero_external_conn();
1959     ok_last_release_closes(TRUE);
1960 
1961     end_host_object(tid, thread);
1962 }
1963 
1964 /* tests releasing after unmarshaling one object */
test_tableweak_marshal_releasedata2(void)1965 static void test_tableweak_marshal_releasedata2(void)
1966 {
1967     HRESULT hr;
1968     IStream *pStream = NULL;
1969     IUnknown *pProxy = NULL;
1970     DWORD tid;
1971     HANDLE thread;
1972 
1973     cLocks = 0;
1974     external_connections = 0;
1975 
1976     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1977     ok_ole_success(hr, CreateStreamOnHGlobal);
1978     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1979 
1980     ok_more_than_one_lock();
1981     ok_zero_external_conn();
1982 
1983     /* release the remaining reference on the object by calling
1984      * CoReleaseMarshalData in the hosting thread */
1985     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1986     release_host_object(tid, 0);
1987 
1988     ok_no_locks();
1989 
1990     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1991     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1992     todo_wine
1993     {
1994     ok(hr == CO_E_OBJNOTREG,
1995        "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08x instead\n",
1996        hr);
1997     }
1998     IStream_Release(pStream);
1999 
2000     ok_no_locks();
2001     ok_zero_external_conn();
2002 
2003     end_host_object(tid, thread);
2004 }
2005 
2006 struct duo_marshal_data
2007 {
2008     MSHLFLAGS marshal_flags1, marshal_flags2;
2009     IStream *pStream1, *pStream2;
2010     HANDLE hReadyEvent;
2011     HANDLE hQuitEvent;
2012 };
2013 
duo_marshal_thread_proc(void * p)2014 static DWORD CALLBACK duo_marshal_thread_proc(void *p)
2015 {
2016     HRESULT hr;
2017     struct duo_marshal_data *data = p;
2018     HANDLE hQuitEvent = data->hQuitEvent;
2019     MSG msg;
2020 
2021     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2022 
2023     hr = CoMarshalInterface(data->pStream1, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags1);
2024     ok_ole_success(hr, "CoMarshalInterface");
2025 
2026     hr = CoMarshalInterface(data->pStream2, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags2);
2027     ok_ole_success(hr, "CoMarshalInterface");
2028 
2029     /* force the message queue to be created before signaling parent thread */
2030     PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
2031 
2032     SetEvent(data->hReadyEvent);
2033 
2034     while (WAIT_OBJECT_0 + 1 == MsgWaitForMultipleObjects(1, &hQuitEvent, FALSE, 10000, QS_ALLINPUT))
2035     {
2036         while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
2037         {
2038             if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
2039             {
2040                 CoReleaseMarshalData(msg.wParam == 1 ? data->pStream1 : data->pStream2);
2041                 SetEvent((HANDLE)msg.lParam);
2042             }
2043             else
2044                 DispatchMessageA(&msg);
2045         }
2046     }
2047     CloseHandle(hQuitEvent);
2048 
2049     CoUninitialize();
2050 
2051     return 0;
2052 }
2053 
2054 /* tests interaction between table-weak and normal marshalling of an object */
test_tableweak_and_normal_marshal_and_unmarshal(void)2055 static void test_tableweak_and_normal_marshal_and_unmarshal(void)
2056 {
2057     HRESULT hr;
2058     IUnknown *pProxyWeak = NULL;
2059     IUnknown *pProxyNormal = NULL;
2060     DWORD tid;
2061     HANDLE thread;
2062     struct duo_marshal_data data;
2063 
2064     cLocks = 0;
2065     external_connections = 0;
2066 
2067     data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2068     data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2069     data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2070     data.marshal_flags2 = MSHLFLAGS_NORMAL;
2071     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2072     ok_ole_success(hr, CreateStreamOnHGlobal);
2073     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2074     ok_ole_success(hr, CreateStreamOnHGlobal);
2075 
2076     thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2077     ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2078     CloseHandle(data.hReadyEvent);
2079 
2080     ok_more_than_one_lock();
2081     ok_non_zero_external_conn();
2082 
2083     /* weak */
2084     IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2085     hr = CoUnmarshalInterface(data.pStream1, &IID_IClassFactory, (void **)&pProxyWeak);
2086     ok_ole_success(hr, CoUnmarshalInterface);
2087 
2088     ok_more_than_one_lock();
2089 
2090     /* normal */
2091     IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2092     hr = CoUnmarshalInterface(data.pStream2, &IID_IClassFactory, (void **)&pProxyNormal);
2093     ok_ole_success(hr, CoUnmarshalInterface);
2094 
2095     ok_more_than_one_lock();
2096 
2097     IUnknown_Release(pProxyNormal);
2098 
2099     ok_more_than_one_lock();
2100     ok_non_zero_external_conn();
2101 
2102     IUnknown_Release(pProxyWeak);
2103 
2104     ok_zero_external_conn();
2105     ok_last_release_closes(TRUE);
2106 
2107     /* When IExternalConnection is present COM's lifetime management
2108      * behaviour is altered; the remaining weak ref prevents stub shutdown. */
2109     if (with_external_conn)
2110     {
2111         ok_more_than_one_lock();
2112         IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2113         release_host_object(tid, 1);
2114     }
2115     ok_no_locks();
2116 
2117     IStream_Release(data.pStream1);
2118     IStream_Release(data.pStream2);
2119 
2120     SetEvent(data.hQuitEvent);
2121     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2122     CloseHandle(thread);
2123 }
2124 
test_tableweak_and_normal_marshal_and_releasedata(void)2125 static void test_tableweak_and_normal_marshal_and_releasedata(void)
2126 {
2127     HRESULT hr;
2128     DWORD tid;
2129     HANDLE thread;
2130     struct duo_marshal_data data;
2131 
2132     cLocks = 0;
2133     external_connections = 0;
2134 
2135     data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2136     data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2137     data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2138     data.marshal_flags2 = MSHLFLAGS_NORMAL;
2139     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2140     ok_ole_success(hr, CreateStreamOnHGlobal);
2141     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2142     ok_ole_success(hr, CreateStreamOnHGlobal);
2143 
2144     thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2145     ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2146     CloseHandle(data.hReadyEvent);
2147 
2148     ok_more_than_one_lock();
2149     ok_non_zero_external_conn();
2150 
2151     /* release normal - which in the non-external conn case will free the object despite the weak ref. */
2152     IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2153     release_host_object(tid, 2);
2154 
2155     ok_zero_external_conn();
2156     ok_last_release_closes(TRUE);
2157 
2158     if (with_external_conn)
2159     {
2160         ok_more_than_one_lock();
2161         IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2162         release_host_object(tid, 1);
2163     }
2164 
2165     ok_no_locks();
2166 
2167     IStream_Release(data.pStream1);
2168     IStream_Release(data.pStream2);
2169 
2170     SetEvent(data.hQuitEvent);
2171     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2172     CloseHandle(thread);
2173 }
2174 
test_two_tableweak_marshal_and_releasedata(void)2175 static void test_two_tableweak_marshal_and_releasedata(void)
2176 {
2177     HRESULT hr;
2178     DWORD tid;
2179     HANDLE thread;
2180     struct duo_marshal_data data;
2181 
2182     cLocks = 0;
2183     external_connections = 0;
2184 
2185     data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2186     data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2187     data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2188     data.marshal_flags2 = MSHLFLAGS_TABLEWEAK;
2189     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2190     ok_ole_success(hr, CreateStreamOnHGlobal);
2191     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2192     ok_ole_success(hr, CreateStreamOnHGlobal);
2193 
2194     thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2195     ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2196     CloseHandle(data.hReadyEvent);
2197 
2198     ok_more_than_one_lock();
2199     ok_zero_external_conn();
2200 
2201     /* release one weak ref - the remaining weak ref will keep the obj alive */
2202     IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2203     release_host_object(tid, 1);
2204 
2205     ok_more_than_one_lock();
2206 
2207     IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2208     release_host_object(tid, 2);
2209 
2210     ok_no_locks();
2211 
2212     IStream_Release(data.pStream1);
2213     IStream_Release(data.pStream2);
2214 
2215     SetEvent(data.hQuitEvent);
2216     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2217     CloseHandle(thread);
2218 }
2219 
2220 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
test_tablestrong_marshal_and_unmarshal_twice(void)2221 static void test_tablestrong_marshal_and_unmarshal_twice(void)
2222 {
2223     HRESULT hr;
2224     IStream *pStream = NULL;
2225     IUnknown *pProxy1 = NULL;
2226     IUnknown *pProxy2 = NULL;
2227     DWORD tid;
2228     HANDLE thread;
2229 
2230     cLocks = 0;
2231     external_connections = 0;
2232 
2233     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2234     ok_ole_success(hr, CreateStreamOnHGlobal);
2235     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
2236 
2237     ok_more_than_one_lock();
2238     ok_non_zero_external_conn();
2239 
2240     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2241     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2242     ok_ole_success(hr, CoUnmarshalInterface);
2243 
2244     ok_more_than_one_lock();
2245 
2246     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2247     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
2248     ok_ole_success(hr, CoUnmarshalInterface);
2249 
2250     ok_more_than_one_lock();
2251 
2252     if (pProxy1) IUnknown_Release(pProxy1);
2253     if (pProxy2) IUnknown_Release(pProxy2);
2254 
2255     /* this line is shows the difference between weak and strong table marshaling:
2256      *  weak has cLocks == 0
2257      *  strong has cLocks > 0 */
2258     ok_more_than_one_lock();
2259 
2260     /* release the remaining reference on the object by calling
2261      * CoReleaseMarshalData in the hosting thread */
2262     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2263     release_host_object(tid, 0);
2264     IStream_Release(pStream);
2265 
2266     ok_no_locks();
2267     ok_zero_external_conn();
2268     ok_last_release_closes(TRUE);
2269 
2270     end_host_object(tid, thread);
2271 }
2272 
2273 /* tests CoLockObjectExternal */
test_lock_object_external(void)2274 static void test_lock_object_external(void)
2275 {
2276     HRESULT hr;
2277     IStream *pStream = NULL;
2278 
2279     cLocks = 0;
2280     external_connections = 0;
2281 
2282     /* test the stub manager creation aspect of CoLockObjectExternal when the
2283      * object hasn't been marshaled yet */
2284     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2285 
2286     ok_more_than_one_lock();
2287     ok_non_zero_external_conn();
2288 
2289     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2290 
2291     ok_no_locks();
2292     ok_non_zero_external_conn();
2293     external_connections = 0;
2294 
2295     /* test our empty stub manager being handled correctly in
2296      * CoMarshalInterface */
2297     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2298 
2299     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2300     ok_ole_success(hr, CreateStreamOnHGlobal);
2301     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2302     ok_ole_success(hr, CoMarshalInterface);
2303 
2304     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2305 
2306     ok_more_than_one_lock();
2307     ok_non_zero_external_conn();
2308 
2309     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2310     hr = CoReleaseMarshalData(pStream);
2311     ok_ole_success(hr, CoReleaseMarshalData);
2312     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2313 
2314     ok_more_than_one_lock();
2315     ok_non_zero_external_conn();
2316     ok_last_release_closes(TRUE);
2317 
2318     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
2319 
2320     ok_more_than_one_lock();
2321     ok_non_zero_external_conn();
2322     ok_last_release_closes(TRUE);
2323 
2324     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
2325 
2326     ok_no_locks();
2327     ok_zero_external_conn();
2328     ok_last_release_closes(TRUE);
2329 
2330     /* test CoLockObjectExternal releases reference to object with
2331      * fLastUnlockReleases as TRUE and there are only strong references on
2332      * the object */
2333     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
2334 
2335     ok_more_than_one_lock();
2336     ok_non_zero_external_conn();
2337 
2338     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
2339 
2340     ok_no_locks();
2341     ok_zero_external_conn();
2342     ok_last_release_closes(FALSE);
2343 
2344     /* test CoLockObjectExternal doesn't release the last reference to an
2345      * object with fLastUnlockReleases as TRUE and there is a weak reference
2346      * on the object */
2347     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
2348     ok_ole_success(hr, CoMarshalInterface);
2349 
2350     ok_more_than_one_lock();
2351     ok_zero_external_conn();
2352 
2353     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
2354 
2355     ok_more_than_one_lock();
2356     ok_non_zero_external_conn();
2357 
2358     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
2359 
2360     ok_more_than_one_lock();
2361     ok_zero_external_conn();
2362     ok_last_release_closes(FALSE);
2363 
2364     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2365 
2366     ok_no_locks();
2367 
2368     IStream_Release(pStream);
2369 }
2370 
2371 /* tests disconnecting stubs */
test_disconnect_stub(void)2372 static void test_disconnect_stub(void)
2373 {
2374     HRESULT hr;
2375     IStream *pStream = NULL;
2376 
2377     cLocks = 0;
2378     external_connections = 0;
2379 
2380     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2381     ok_ole_success(hr, CreateStreamOnHGlobal);
2382     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2383     ok_ole_success(hr, CoMarshalInterface);
2384 
2385     ok_non_zero_external_conn();
2386 
2387     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2388 
2389     ok_more_than_one_lock();
2390     ok_non_zero_external_conn();
2391 
2392     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2393     hr = CoReleaseMarshalData(pStream);
2394     ok_ole_success(hr, CoReleaseMarshalData);
2395     IStream_Release(pStream);
2396 
2397     ok_more_than_one_lock();
2398     ok_non_zero_external_conn();
2399 
2400     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2401 
2402     ok_no_locks();
2403     ok_non_zero_external_conn();
2404 
2405     hr = CoDisconnectObject(NULL, 0);
2406     ok( hr == E_INVALIDARG, "wrong status %x\n", hr );
2407 }
2408 
2409 /* tests failure case of a same-thread marshal and unmarshal twice */
test_normal_marshal_and_unmarshal_twice(void)2410 static void test_normal_marshal_and_unmarshal_twice(void)
2411 {
2412     HRESULT hr;
2413     IStream *pStream = NULL;
2414     IUnknown *pProxy1 = NULL;
2415     IUnknown *pProxy2 = NULL;
2416 
2417     cLocks = 0;
2418     external_connections = 0;
2419 
2420     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2421     ok_ole_success(hr, CreateStreamOnHGlobal);
2422     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2423     ok_ole_success(hr, CoMarshalInterface);
2424 
2425     ok_more_than_one_lock();
2426     ok_non_zero_external_conn();
2427 
2428     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2429     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2430     ok_ole_success(hr, CoUnmarshalInterface);
2431 
2432     ok_more_than_one_lock();
2433     ok_zero_external_conn();
2434     ok_last_release_closes(FALSE);
2435 
2436     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2437     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
2438     ok(hr == CO_E_OBJNOTCONNECTED,
2439         "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08x\n", hr);
2440 
2441     IStream_Release(pStream);
2442 
2443     ok_more_than_one_lock();
2444 
2445     IUnknown_Release(pProxy1);
2446 
2447     ok_no_locks();
2448 }
2449 
2450 /* tests success case of marshaling and unmarshaling an HRESULT */
test_hresult_marshaling(void)2451 static void test_hresult_marshaling(void)
2452 {
2453     HRESULT hr;
2454     HRESULT hr_marshaled = 0;
2455     IStream *pStream = NULL;
2456     static const HRESULT E_DEADBEEF = 0xdeadbeef;
2457 
2458     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2459     ok_ole_success(hr, CreateStreamOnHGlobal);
2460 
2461     hr = CoMarshalHresult(pStream, E_DEADBEEF);
2462     ok_ole_success(hr, CoMarshalHresult);
2463 
2464     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2465     hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
2466     ok_ole_success(hr, IStream_Read);
2467 
2468     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
2469 
2470     hr_marshaled = 0;
2471     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2472     hr = CoUnmarshalHresult(pStream, &hr_marshaled);
2473     ok_ole_success(hr, CoUnmarshalHresult);
2474 
2475     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
2476 
2477     IStream_Release(pStream);
2478 }
2479 
2480 
2481 /* helper for test_proxy_used_in_wrong_thread */
bad_thread_proc(LPVOID p)2482 static DWORD CALLBACK bad_thread_proc(LPVOID p)
2483 {
2484     IClassFactory * cf = p;
2485     HRESULT hr;
2486     IUnknown * proxy = NULL;
2487 
2488     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2489     todo_wine
2490     ok(hr == CO_E_NOTINITIALIZED,
2491        "COM should have failed with CO_E_NOTINITIALIZED on using proxy without apartment, but instead returned 0x%08x\n",
2492        hr);
2493 
2494     hr = IClassFactory_QueryInterface(cf, &IID_IMultiQI, (LPVOID *)&proxy);
2495     /* Win9x returns S_OK, whilst NT returns RPC_E_WRONG_THREAD */
2496     trace("call to proxy's QueryInterface for local interface without apartment returned 0x%08x\n", hr);
2497     if (SUCCEEDED(hr))
2498         IUnknown_Release(proxy);
2499 
2500     hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
2501     /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
2502     trace("call to proxy's QueryInterface without apartment returned 0x%08x\n", hr);
2503     if (SUCCEEDED(hr))
2504         IUnknown_Release(proxy);
2505 
2506     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
2507 
2508     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2509     if (proxy) IUnknown_Release(proxy);
2510     ok(hr == RPC_E_WRONG_THREAD,
2511         "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08x\n",
2512         hr);
2513 
2514     hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
2515     /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
2516     trace("call to proxy's QueryInterface from wrong apartment returned 0x%08x\n", hr);
2517 
2518     /* now be really bad and release the proxy from the wrong apartment */
2519     IClassFactory_Release(cf);
2520 
2521     CoUninitialize();
2522 
2523     return 0;
2524 }
2525 
2526 /* tests failure case of a using a proxy in the wrong apartment */
test_proxy_used_in_wrong_thread(void)2527 static void test_proxy_used_in_wrong_thread(void)
2528 {
2529     HRESULT hr;
2530     IStream *pStream = NULL;
2531     IUnknown *pProxy = NULL;
2532     DWORD tid, tid2;
2533     HANDLE thread;
2534     HANDLE host_thread;
2535 
2536     cLocks = 0;
2537 
2538     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2539     ok_ole_success(hr, CreateStreamOnHGlobal);
2540     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
2541 
2542     ok_more_than_one_lock();
2543 
2544     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2545     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
2546     ok_ole_success(hr, CoUnmarshalInterface);
2547     IStream_Release(pStream);
2548 
2549     ok_more_than_one_lock();
2550 
2551     /* do a call that will fail, but result in IRemUnknown being used by the proxy */
2552     IUnknown_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream);
2553 
2554     /* create a thread that we can misbehave in */
2555     thread = CreateThread(NULL, 0, bad_thread_proc, pProxy, 0, &tid2);
2556 
2557     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2558     CloseHandle(thread);
2559 
2560     /* do release statement on Win9x that we should have done above */
2561     if (!GetProcAddress(GetModuleHandleA("ole32"), "CoRegisterSurrogateEx"))
2562         IUnknown_Release(pProxy);
2563 
2564     ok_no_locks();
2565 
2566     end_host_object(tid, host_thread);
2567 }
2568 
MessageFilter_QueryInterface(IMessageFilter * iface,REFIID riid,void ** ppvObj)2569 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
2570 {
2571     if (ppvObj == NULL) return E_POINTER;
2572 
2573     if (IsEqualGUID(riid, &IID_IUnknown) ||
2574         IsEqualGUID(riid, &IID_IClassFactory))
2575     {
2576         *ppvObj = iface;
2577         IMessageFilter_AddRef(iface);
2578         return S_OK;
2579     }
2580 
2581     return E_NOINTERFACE;
2582 }
2583 
MessageFilter_AddRef(IMessageFilter * iface)2584 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
2585 {
2586     return 2; /* non-heap object */
2587 }
2588 
MessageFilter_Release(IMessageFilter * iface)2589 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
2590 {
2591     return 1; /* non-heap object */
2592 }
2593 
MessageFilter_HandleInComingCall(IMessageFilter * iface,DWORD dwCallType,HTASK threadIDCaller,DWORD dwTickCount,LPINTERFACEINFO lpInterfaceInfo)2594 static DWORD WINAPI MessageFilter_HandleInComingCall(
2595   IMessageFilter *iface,
2596   DWORD dwCallType,
2597   HTASK threadIDCaller,
2598   DWORD dwTickCount,
2599   LPINTERFACEINFO lpInterfaceInfo)
2600 {
2601     static int callcount = 0;
2602     DWORD ret;
2603     trace("HandleInComingCall\n");
2604     switch (callcount)
2605     {
2606     case 0:
2607         ret = SERVERCALL_REJECTED;
2608         break;
2609     case 1:
2610         ret = SERVERCALL_RETRYLATER;
2611         break;
2612     default:
2613         ret = SERVERCALL_ISHANDLED;
2614         break;
2615     }
2616     callcount++;
2617     return ret;
2618 }
2619 
MessageFilter_RetryRejectedCall(IMessageFilter * iface,HTASK threadIDCallee,DWORD dwTickCount,DWORD dwRejectType)2620 static DWORD WINAPI MessageFilter_RetryRejectedCall(
2621   IMessageFilter *iface,
2622   HTASK threadIDCallee,
2623   DWORD dwTickCount,
2624   DWORD dwRejectType)
2625 {
2626     trace("RetryRejectedCall\n");
2627     return 0;
2628 }
2629 
MessageFilter_MessagePending(IMessageFilter * iface,HTASK threadIDCallee,DWORD dwTickCount,DWORD dwPendingType)2630 static DWORD WINAPI MessageFilter_MessagePending(
2631   IMessageFilter *iface,
2632   HTASK threadIDCallee,
2633   DWORD dwTickCount,
2634   DWORD dwPendingType)
2635 {
2636     trace("MessagePending\n");
2637     return PENDINGMSG_WAITNOPROCESS;
2638 }
2639 
2640 static const IMessageFilterVtbl MessageFilter_Vtbl =
2641 {
2642     MessageFilter_QueryInterface,
2643     MessageFilter_AddRef,
2644     MessageFilter_Release,
2645     MessageFilter_HandleInComingCall,
2646     MessageFilter_RetryRejectedCall,
2647     MessageFilter_MessagePending
2648 };
2649 
2650 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
2651 
test_message_filter(void)2652 static void test_message_filter(void)
2653 {
2654     HRESULT hr;
2655     IClassFactory *cf = NULL;
2656     DWORD tid;
2657     IUnknown *proxy = NULL;
2658     IMessageFilter *prev_filter = NULL;
2659     HANDLE thread;
2660 
2661     struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
2662                                             MSHLFLAGS_NORMAL, &MessageFilter };
2663 
2664     cLocks = 0;
2665 
2666     hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
2667     ok_ole_success(hr, CreateStreamOnHGlobal);
2668     tid = start_host_object2(&object_data, &thread);
2669 
2670     ok_more_than_one_lock();
2671 
2672     IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
2673     hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
2674     ok_ole_success(hr, CoUnmarshalInterface);
2675     IStream_Release(object_data.stream);
2676 
2677     ok_more_than_one_lock();
2678 
2679     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2680     ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08x instead\n", hr);
2681     if (proxy) IUnknown_Release(proxy);
2682     proxy = NULL;
2683 
2684     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
2685     ok_ole_success(hr, CoRegisterMessageFilter);
2686 
2687     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2688     ok_ole_success(hr, IClassFactory_CreateInstance);
2689 
2690     IUnknown_Release(proxy);
2691 
2692     IClassFactory_Release(cf);
2693 
2694     ok_no_locks();
2695 
2696     end_host_object(tid, thread);
2697 
2698     hr = CoRegisterMessageFilter(prev_filter, NULL);
2699     ok_ole_success(hr, CoRegisterMessageFilter);
2700 }
2701 
2702 /* test failure case of trying to unmarshal from bad stream */
test_bad_marshal_stream(void)2703 static void test_bad_marshal_stream(void)
2704 {
2705     HRESULT hr;
2706     IStream *pStream = NULL;
2707 
2708     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2709     ok_ole_success(hr, CreateStreamOnHGlobal);
2710     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2711     ok_ole_success(hr, CoMarshalInterface);
2712 
2713     ok_more_than_one_lock();
2714 
2715     /* try to read beyond end of stream */
2716     hr = CoReleaseMarshalData(pStream);
2717     ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08x instead\n", hr);
2718 
2719     /* now release for real */
2720     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2721     hr = CoReleaseMarshalData(pStream);
2722     ok_ole_success(hr, CoReleaseMarshalData);
2723 
2724     IStream_Release(pStream);
2725 }
2726 
2727 /* tests that proxies implement certain interfaces */
test_proxy_interfaces(void)2728 static void test_proxy_interfaces(void)
2729 {
2730     HRESULT hr;
2731     IStream *pStream = NULL;
2732     IUnknown *pProxy = NULL;
2733     IUnknown *pOtherUnknown = NULL;
2734     DWORD tid;
2735     HANDLE thread;
2736 
2737     cLocks = 0;
2738 
2739     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2740     ok_ole_success(hr, CreateStreamOnHGlobal);
2741     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2742 
2743     ok_more_than_one_lock();
2744 
2745     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2746     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
2747     ok_ole_success(hr, CoUnmarshalInterface);
2748     IStream_Release(pStream);
2749 
2750     ok_more_than_one_lock();
2751 
2752     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
2753     ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
2754     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2755 
2756     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
2757     ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity);
2758     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2759 
2760     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
2761     ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
2762     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2763 
2764     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
2765     ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal);
2766     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2767 
2768     /* IMarshal2 is also supported on NT-based systems, but is pretty much
2769      * useless as it has no more methods over IMarshal that it inherits from. */
2770 
2771     IUnknown_Release(pProxy);
2772 
2773     ok_no_locks();
2774 
2775     end_host_object(tid, thread);
2776 }
2777 
2778 typedef struct
2779 {
2780     IUnknown IUnknown_iface;
2781     ULONG refs;
2782 } HeapUnknown;
2783 
impl_from_IUnknown(IUnknown * iface)2784 static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
2785 {
2786     return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
2787 }
2788 
HeapUnknown_QueryInterface(IUnknown * iface,REFIID riid,void ** ppv)2789 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2790 {
2791     if (IsEqualIID(riid, &IID_IUnknown))
2792     {
2793         IUnknown_AddRef(iface);
2794         *ppv = iface;
2795         return S_OK;
2796     }
2797     *ppv = NULL;
2798     return E_NOINTERFACE;
2799 }
2800 
HeapUnknown_AddRef(IUnknown * iface)2801 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
2802 {
2803     HeapUnknown *This = impl_from_IUnknown(iface);
2804     return InterlockedIncrement((LONG*)&This->refs);
2805 }
2806 
HeapUnknown_Release(IUnknown * iface)2807 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
2808 {
2809     HeapUnknown *This = impl_from_IUnknown(iface);
2810     ULONG refs = InterlockedDecrement((LONG*)&This->refs);
2811     if (!refs) HeapFree(GetProcessHeap(), 0, This);
2812     return refs;
2813 }
2814 
2815 static const IUnknownVtbl HeapUnknown_Vtbl =
2816 {
2817     HeapUnknown_QueryInterface,
2818     HeapUnknown_AddRef,
2819     HeapUnknown_Release
2820 };
2821 
test_proxybuffer(REFIID riid)2822 static void test_proxybuffer(REFIID riid)
2823 {
2824     HRESULT hr;
2825     IPSFactoryBuffer *psfb;
2826     IRpcProxyBuffer *proxy;
2827     LPVOID lpvtbl;
2828     ULONG refs;
2829     CLSID clsid;
2830     HeapUnknown *pUnkOuter = HeapAlloc(GetProcessHeap(), 0, sizeof(*pUnkOuter));
2831 
2832     pUnkOuter->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
2833     pUnkOuter->refs = 1;
2834 
2835     hr = CoGetPSClsid(riid, &clsid);
2836     ok_ole_success(hr, CoGetPSClsid);
2837 
2838     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
2839     ok_ole_success(hr, CoGetClassObject);
2840 
2841     hr = IPSFactoryBuffer_CreateProxy(psfb, &pUnkOuter->IUnknown_iface, riid, &proxy, &lpvtbl);
2842     ok_ole_success(hr, IPSFactoryBuffer_CreateProxy);
2843     ok(lpvtbl != NULL, "IPSFactoryBuffer_CreateProxy succeeded, but returned a NULL vtable!\n");
2844 
2845     /* release our reference to the outer unknown object - the PS factory
2846      * buffer will have AddRef's it in the CreateProxy call */
2847     refs = IUnknown_Release(&pUnkOuter->IUnknown_iface);
2848     ok(refs == 1, "Ref count of outer unknown should have been 1 instead of %d\n", refs);
2849 
2850     /* Not checking return, unreliable on native. Maybe it leaks references? */
2851     IPSFactoryBuffer_Release(psfb);
2852 
2853     refs = IUnknown_Release((IUnknown *)lpvtbl);
2854     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2855 
2856     refs = IRpcProxyBuffer_Release(proxy);
2857     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2858 }
2859 
test_stubbuffer(REFIID riid)2860 static void test_stubbuffer(REFIID riid)
2861 {
2862     HRESULT hr;
2863     IPSFactoryBuffer *psfb;
2864     IRpcStubBuffer *stub;
2865     ULONG refs;
2866     CLSID clsid;
2867 
2868     cLocks = 0;
2869 
2870     hr = CoGetPSClsid(riid, &clsid);
2871     ok_ole_success(hr, CoGetPSClsid);
2872 
2873     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
2874     ok_ole_success(hr, CoGetClassObject);
2875 
2876     hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
2877     ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
2878 
2879     /* Not checking return, unreliable on native. Maybe it leaks references? */
2880     IPSFactoryBuffer_Release(psfb);
2881 
2882     ok_more_than_one_lock();
2883 
2884     IRpcStubBuffer_Disconnect(stub);
2885 
2886     ok_no_locks();
2887 
2888     refs = IRpcStubBuffer_Release(stub);
2889     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2890 }
2891 
2892 static HWND hwnd_app;
2893 
TestRE_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)2894 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
2895     LPCLASSFACTORY iface,
2896     LPUNKNOWN pUnkOuter,
2897     REFIID riid,
2898     LPVOID *ppvObj)
2899 {
2900     DWORD_PTR res;
2901     if (IsEqualIID(riid, &IID_IWineTest))
2902     {
2903         BOOL ret = SendMessageTimeoutA(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
2904         ok(ret, "Timed out sending a message to originating window during RPC call\n");
2905     }
2906     *ppvObj = NULL;
2907     return S_FALSE;
2908 }
2909 
2910 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
2911 {
2912     Test_IClassFactory_QueryInterface,
2913     Test_IClassFactory_AddRef,
2914     Test_IClassFactory_Release,
2915     TestRE_IClassFactory_CreateInstance,
2916     Test_IClassFactory_LockServer
2917 };
2918 
2919 static IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
2920 
window_proc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)2921 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
2922 {
2923     switch (msg)
2924     {
2925     case WM_USER:
2926     {
2927         HRESULT hr;
2928         IStream *pStream = NULL;
2929         IClassFactory *proxy = NULL;
2930         IUnknown *object;
2931         DWORD tid;
2932         HANDLE thread;
2933 
2934         cLocks = 0;
2935 
2936         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2937         ok_ole_success(hr, CreateStreamOnHGlobal);
2938         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2939 
2940         ok_more_than_one_lock();
2941 
2942         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2943         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2944         ok_ole_success(hr, CoReleaseMarshalData);
2945         IStream_Release(pStream);
2946 
2947         ok_more_than_one_lock();
2948 
2949         /* note the use of the magic IID_IWineTest value to tell remote thread
2950          * to try to send a message back to us */
2951         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IWineTest, (void **)&object);
2952         ok(hr == S_FALSE, "expected S_FALSE, got %d\n", hr);
2953 
2954         IClassFactory_Release(proxy);
2955 
2956         ok_no_locks();
2957 
2958         end_host_object(tid, thread);
2959 
2960         PostMessageA(hwnd, WM_QUIT, 0, 0);
2961 
2962         return 0;
2963     }
2964     case WM_USER+1:
2965     {
2966         HRESULT hr;
2967         IStream *pStream = NULL;
2968         IClassFactory *proxy = NULL;
2969         IUnknown *object;
2970         DWORD tid;
2971         HANDLE thread;
2972 
2973         cLocks = 0;
2974 
2975         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2976         ok_ole_success(hr, CreateStreamOnHGlobal);
2977         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2978 
2979         ok_more_than_one_lock();
2980 
2981         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2982         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2983         ok_ole_success(hr, CoReleaseMarshalData);
2984         IStream_Release(pStream);
2985 
2986         ok_more_than_one_lock();
2987 
2988         /* post quit message before a doing a COM call to show that a pending
2989         * WM_QUIT message doesn't stop the call from succeeding */
2990         PostMessageA(hwnd, WM_QUIT, 0, 0);
2991         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
2992 	ok(hr == S_FALSE, "IClassFactory_CreateInstance returned 0x%08x, expected S_FALSE\n", hr);
2993 
2994         IClassFactory_Release(proxy);
2995 
2996         ok_no_locks();
2997 
2998         end_host_object(tid, thread);
2999 
3000         return 0;
3001     }
3002     case WM_USER+2:
3003     {
3004         HRESULT hr;
3005         IStream *pStream = NULL;
3006         IClassFactory *proxy = NULL;
3007         IUnknown *object;
3008         DWORD tid;
3009         HANDLE thread;
3010 
3011         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3012         ok_ole_success(hr, CreateStreamOnHGlobal);
3013         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3014 
3015         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3016         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
3017         ok_ole_success(hr, CoReleaseMarshalData);
3018         IStream_Release(pStream);
3019 
3020         /* shows that COM calls executed during the processing of sent
3021          * messages should fail */
3022         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
3023         ok(hr == RPC_E_CANTCALLOUT_ININPUTSYNCCALL,
3024            "COM call during processing of sent message should return RPC_E_CANTCALLOUT_ININPUTSYNCCALL instead of 0x%08x\n", hr);
3025 
3026         IClassFactory_Release(proxy);
3027 
3028         end_host_object(tid, thread);
3029 
3030         PostQuitMessage(0);
3031 
3032         return 0;
3033     }
3034     default:
3035         return DefWindowProcA(hwnd, msg, wparam, lparam);
3036     }
3037 }
3038 
register_test_window(void)3039 static void register_test_window(void)
3040 {
3041     WNDCLASSA wndclass;
3042 
3043     memset(&wndclass, 0, sizeof(wndclass));
3044     wndclass.lpfnWndProc = window_proc;
3045     wndclass.lpszClassName = "WineCOMTest";
3046     RegisterClassA(&wndclass);
3047 }
3048 
test_message_reentrancy(void)3049 static void test_message_reentrancy(void)
3050 {
3051     MSG msg;
3052 
3053     hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3054     ok(hwnd_app != NULL, "Window creation failed\n");
3055 
3056     /* start message re-entrancy test */
3057     PostMessageA(hwnd_app, WM_USER, 0, 0);
3058 
3059     while (GetMessageA(&msg, NULL, 0, 0))
3060     {
3061         TranslateMessage(&msg);
3062         DispatchMessageA(&msg);
3063     }
3064     DestroyWindow(hwnd_app);
3065 }
3066 
TestMsg_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)3067 static HRESULT WINAPI TestMsg_IClassFactory_CreateInstance(
3068     LPCLASSFACTORY iface,
3069     LPUNKNOWN pUnkOuter,
3070     REFIID riid,
3071     LPVOID *ppvObj)
3072 {
3073     *ppvObj = NULL;
3074     SendMessageA(hwnd_app, WM_USER+2, 0, 0);
3075     return S_OK;
3076 }
3077 
3078 static IClassFactoryVtbl TestMsgClassFactory_Vtbl =
3079 {
3080     Test_IClassFactory_QueryInterface,
3081     Test_IClassFactory_AddRef,
3082     Test_IClassFactory_Release,
3083     TestMsg_IClassFactory_CreateInstance,
3084     Test_IClassFactory_LockServer
3085 };
3086 
3087 static IClassFactory TestMsg_ClassFactory = { &TestMsgClassFactory_Vtbl };
3088 
test_call_from_message(void)3089 static void test_call_from_message(void)
3090 {
3091     MSG msg;
3092     IStream *pStream;
3093     HRESULT hr;
3094     IClassFactory *proxy;
3095     DWORD tid;
3096     HANDLE thread;
3097     IUnknown *object;
3098 
3099     hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3100     ok(hwnd_app != NULL, "Window creation failed\n");
3101 
3102     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3103     ok_ole_success(hr, CreateStreamOnHGlobal);
3104     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestMsg_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3105 
3106     ok_more_than_one_lock();
3107 
3108     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3109     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
3110     ok_ole_success(hr, CoReleaseMarshalData);
3111     IStream_Release(pStream);
3112 
3113     ok_more_than_one_lock();
3114 
3115     /* start message re-entrancy test */
3116     hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
3117     ok_ole_success(hr, IClassFactory_CreateInstance);
3118 
3119     IClassFactory_Release(proxy);
3120 
3121     ok_no_locks();
3122 
3123     end_host_object(tid, thread);
3124 
3125     while (GetMessageA(&msg, NULL, 0, 0))
3126     {
3127         TranslateMessage(&msg);
3128         DispatchMessageA(&msg);
3129     }
3130     DestroyWindow(hwnd_app);
3131 }
3132 
test_WM_QUIT_handling(void)3133 static void test_WM_QUIT_handling(void)
3134 {
3135     MSG msg;
3136 
3137     hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3138     ok(hwnd_app != NULL, "Window creation failed\n");
3139 
3140     /* start WM_QUIT handling test */
3141     PostMessageA(hwnd_app, WM_USER+1, 0, 0);
3142 
3143     while (GetMessageA(&msg, NULL, 0, 0))
3144     {
3145         TranslateMessage(&msg);
3146         DispatchMessageA(&msg);
3147     }
3148 }
3149 
round_global_size(SIZE_T size)3150 static SIZE_T round_global_size(SIZE_T size)
3151 {
3152     static SIZE_T global_size_alignment = -1;
3153     if (global_size_alignment == -1)
3154     {
3155         void *p = GlobalAlloc(GMEM_FIXED, 1);
3156         global_size_alignment = GlobalSize(p);
3157         GlobalFree(p);
3158     }
3159 
3160     return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1));
3161 }
3162 
test_freethreadedmarshaldata(IStream * pStream,MSHCTX mshctx,void * ptr,DWORD mshlflags)3163 static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void *ptr, DWORD mshlflags)
3164 {
3165     HGLOBAL hglobal;
3166     DWORD size;
3167     char *marshal_data;
3168     HRESULT hr;
3169 
3170     hr = GetHGlobalFromStream(pStream, &hglobal);
3171     ok_ole_success(hr, GetHGlobalFromStream);
3172 
3173     size = GlobalSize(hglobal);
3174 
3175     marshal_data = GlobalLock(hglobal);
3176 
3177     if (mshctx == MSHCTX_INPROC)
3178     {
3179         DWORD expected_size = round_global_size(3*sizeof(DWORD) + sizeof(GUID));
3180         ok(size == expected_size ||
3181            broken(size == (2*sizeof(DWORD))) /* Win9x & NT4 */,
3182            "size should have been %d instead of %d\n", expected_size, size);
3183 
3184         ok(*(DWORD *)marshal_data == mshlflags, "expected 0x%x, but got 0x%x for mshctx\n", mshlflags, *(DWORD *)marshal_data);
3185         marshal_data += sizeof(DWORD);
3186         ok(*(void **)marshal_data == ptr, "expected %p, but got %p for mshctx\n", ptr, *(void **)marshal_data);
3187         marshal_data += sizeof(void *);
3188         if (sizeof(void*) == 4 && size >= 3*sizeof(DWORD))
3189         {
3190             ok(*(DWORD *)marshal_data == 0, "expected 0x0, but got 0x%x\n", *(DWORD *)marshal_data);
3191             marshal_data += sizeof(DWORD);
3192         }
3193         if (size >= 3*sizeof(DWORD) + sizeof(GUID))
3194         {
3195             trace("got guid data: %s\n", wine_dbgstr_guid((GUID *)marshal_data));
3196         }
3197     }
3198     else
3199     {
3200         ok(size > sizeof(DWORD), "size should have been > sizeof(DWORD), not %d\n", size);
3201         ok(*(DWORD *)marshal_data == 0x574f454d /* MEOW */,
3202             "marshal data should be filled by standard marshal and start with MEOW signature\n");
3203     }
3204 
3205     GlobalUnlock(hglobal);
3206 }
3207 
test_freethreadedmarshaler(void)3208 static void test_freethreadedmarshaler(void)
3209 {
3210     HRESULT hr;
3211     IUnknown *pFTUnknown;
3212     IMarshal *pFTMarshal;
3213     IStream *pStream;
3214     IUnknown *pProxy;
3215     static const LARGE_INTEGER llZero;
3216     CLSID clsid;
3217 
3218     cLocks = 0;
3219     hr = CoCreateFreeThreadedMarshaler(NULL, &pFTUnknown);
3220     ok_ole_success(hr, CoCreateFreeThreadedMarshaler);
3221     hr = IUnknown_QueryInterface(pFTUnknown, &IID_IMarshal, (void **)&pFTMarshal);
3222     ok_ole_success(hr, IUnknown_QueryInterface);
3223     IUnknown_Release(pFTUnknown);
3224 
3225     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3226     ok_ole_success(hr, CreateStreamOnHGlobal);
3227 
3228     /* inproc normal marshaling */
3229 
3230     hr = IMarshal_GetUnmarshalClass(pFTMarshal, &IID_IClassFactory,
3231             &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &clsid);
3232     ok_ole_success(hr, IMarshal_GetUnmarshalClass);
3233     ok(IsEqualIID(&clsid, &CLSID_InProcFreeMarshaler), "clsid = %s\n",
3234             wine_dbgstr_guid(&clsid));
3235 
3236     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3237         &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3238     ok_ole_success(hr, IMarshal_MarshalInterface);
3239 
3240     ok_more_than_one_lock();
3241 
3242     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_NORMAL);
3243 
3244     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3245     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3246     ok_ole_success(hr, IMarshal_UnmarshalInterface);
3247 
3248     IUnknown_Release(pProxy);
3249 
3250     ok_no_locks();
3251 
3252     /* inproc table-strong marshaling */
3253 
3254     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3255     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3256         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
3257         MSHLFLAGS_TABLESTRONG);
3258     ok_ole_success(hr, IMarshal_MarshalInterface);
3259 
3260     ok_more_than_one_lock();
3261 
3262     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLESTRONG);
3263 
3264     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3265     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3266     ok_ole_success(hr, IMarshal_UnmarshalInterface);
3267 
3268     IUnknown_Release(pProxy);
3269 
3270     ok_more_than_one_lock();
3271 
3272     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3273     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
3274     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
3275 
3276     ok_no_locks();
3277 
3278     /* inproc table-weak marshaling */
3279 
3280     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3281     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3282         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
3283         MSHLFLAGS_TABLEWEAK);
3284     ok_ole_success(hr, IMarshal_MarshalInterface);
3285 
3286     ok_no_locks();
3287 
3288     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLEWEAK);
3289 
3290     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3291     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3292     ok_ole_success(hr, IMarshal_UnmarshalInterface);
3293 
3294     ok_more_than_one_lock();
3295 
3296     IUnknown_Release(pProxy);
3297 
3298     ok_no_locks();
3299 
3300     /* inproc normal marshaling (for extraordinary cases) */
3301 
3302     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3303     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3304         &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3305     ok_ole_success(hr, IMarshal_MarshalInterface);
3306 
3307     ok_more_than_one_lock();
3308 
3309     /* this call shows that DisconnectObject does nothing */
3310     hr = IMarshal_DisconnectObject(pFTMarshal, 0);
3311     ok_ole_success(hr, IMarshal_DisconnectObject);
3312 
3313     ok_more_than_one_lock();
3314 
3315     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3316     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
3317     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
3318 
3319     ok_no_locks();
3320 
3321     /* doesn't enforce marshaling rules here and allows us to unmarshal the
3322      * interface, even though it was freed above */
3323     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3324     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3325     ok_ole_success(hr, IMarshal_UnmarshalInterface);
3326 
3327     ok_no_locks();
3328 
3329     /* local normal marshaling */
3330 
3331     hr = IMarshal_GetUnmarshalClass(pFTMarshal, &IID_IClassFactory,
3332             &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL, &clsid);
3333     ok_ole_success(hr, IMarshal_GetUnmarshalClass);
3334     ok(IsEqualIID(&clsid, &CLSID_StdMarshal), "clsid = %s\n",
3335             wine_dbgstr_guid(&clsid));
3336 
3337     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3338     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
3339     ok_ole_success(hr, IMarshal_MarshalInterface);
3340 
3341     ok_more_than_one_lock();
3342 
3343     test_freethreadedmarshaldata(pStream, MSHCTX_LOCAL, &Test_ClassFactory, MSHLFLAGS_NORMAL);
3344 
3345     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3346     hr = CoReleaseMarshalData(pStream);
3347     ok_ole_success(hr, CoReleaseMarshalData);
3348 
3349     ok_no_locks();
3350 
3351     IStream_Release(pStream);
3352     IMarshal_Release(pFTMarshal);
3353 }
3354 
reg_unreg_wine_test_class(BOOL Register)3355 static HRESULT reg_unreg_wine_test_class(BOOL Register)
3356 {
3357     HRESULT hr;
3358     char buffer[256];
3359     LPOLESTR pszClsid;
3360     HKEY hkey;
3361     DWORD dwDisposition;
3362     DWORD error;
3363 
3364     hr = StringFromCLSID(&CLSID_WineTest, &pszClsid);
3365     ok_ole_success(hr, "StringFromCLSID");
3366     strcpy(buffer, "CLSID\\");
3367     WideCharToMultiByte(CP_ACP, 0, pszClsid, -1, buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), NULL, NULL);
3368     CoTaskMemFree(pszClsid);
3369     strcat(buffer, "\\InprocHandler32");
3370     if (Register)
3371     {
3372         error = RegCreateKeyExA(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
3373         if (error == ERROR_ACCESS_DENIED)
3374         {
3375             skip("Not authorized to modify the Classes key\n");
3376             return E_FAIL;
3377         }
3378         ok(error == ERROR_SUCCESS, "RegCreateKeyEx failed with error %d\n", error);
3379         if (error != ERROR_SUCCESS) hr = E_FAIL;
3380         error = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const unsigned char *)"\"ole32.dll\"", strlen("\"ole32.dll\"") + 1);
3381         ok(error == ERROR_SUCCESS, "RegSetValueEx failed with error %d\n", error);
3382         if (error != ERROR_SUCCESS) hr = E_FAIL;
3383         RegCloseKey(hkey);
3384     }
3385     else
3386     {
3387         RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
3388         *strrchr(buffer, '\\') = '\0';
3389         RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
3390     }
3391     return hr;
3392 }
3393 
test_inproc_handler(void)3394 static void test_inproc_handler(void)
3395 {
3396     HRESULT hr;
3397     IUnknown *pObject;
3398     IUnknown *pObject2;
3399 
3400     if (FAILED(reg_unreg_wine_test_class(TRUE)))
3401         return;
3402 
3403     hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pObject);
3404     ok_ole_success(hr, "CoCreateInstance");
3405 
3406     if (SUCCEEDED(hr))
3407     {
3408         hr = IUnknown_QueryInterface(pObject, &IID_IWineTest, (void **)&pObject2);
3409         ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface on handler for invalid interface returned 0x%08x instead of E_NOINTERFACE\n", hr);
3410 
3411         /* it's a handler as it supports IOleObject */
3412         hr = IUnknown_QueryInterface(pObject, &IID_IOleObject, (void **)&pObject2);
3413         ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
3414         IUnknown_Release(pObject2);
3415 
3416         IUnknown_Release(pObject);
3417     }
3418 
3419     reg_unreg_wine_test_class(FALSE);
3420 }
3421 
Test_SMI_QueryInterface(IStdMarshalInfo * iface,REFIID riid,LPVOID * ppvObj)3422 static HRESULT WINAPI Test_SMI_QueryInterface(
3423     IStdMarshalInfo *iface,
3424     REFIID riid,
3425     LPVOID *ppvObj)
3426 {
3427     if (ppvObj == NULL) return E_POINTER;
3428 
3429     if (IsEqualGUID(riid, &IID_IUnknown) ||
3430         IsEqualGUID(riid, &IID_IStdMarshalInfo))
3431     {
3432         *ppvObj = iface;
3433         IStdMarshalInfo_AddRef(iface);
3434         return S_OK;
3435     }
3436 
3437     return E_NOINTERFACE;
3438 }
3439 
Test_SMI_AddRef(IStdMarshalInfo * iface)3440 static ULONG WINAPI Test_SMI_AddRef(IStdMarshalInfo *iface)
3441 {
3442     LockModule();
3443     return 2; /* non-heap-based object */
3444 }
3445 
Test_SMI_Release(IStdMarshalInfo * iface)3446 static ULONG WINAPI Test_SMI_Release(IStdMarshalInfo *iface)
3447 {
3448     UnlockModule();
3449     return 1; /* non-heap-based object */
3450 }
3451 
Test_SMI_GetClassForHandler(IStdMarshalInfo * iface,DWORD dwDestContext,void * pvDestContext,CLSID * pClsid)3452 static HRESULT WINAPI Test_SMI_GetClassForHandler(
3453     IStdMarshalInfo *iface,
3454     DWORD dwDestContext,
3455     void *pvDestContext,
3456     CLSID *pClsid)
3457 {
3458     *pClsid = CLSID_WineTest;
3459     return S_OK;
3460 }
3461 
3462 static const IStdMarshalInfoVtbl Test_SMI_Vtbl =
3463 {
3464     Test_SMI_QueryInterface,
3465     Test_SMI_AddRef,
3466     Test_SMI_Release,
3467     Test_SMI_GetClassForHandler
3468 };
3469 
3470 static IStdMarshalInfo Test_SMI = {&Test_SMI_Vtbl};
3471 
test_handler_marshaling(void)3472 static void test_handler_marshaling(void)
3473 {
3474     HRESULT hr;
3475     IStream *pStream = NULL;
3476     IUnknown *pProxy = NULL;
3477     IUnknown *pObject;
3478     DWORD tid;
3479     HANDLE thread;
3480     static const LARGE_INTEGER ullZero;
3481 
3482     if (FAILED(reg_unreg_wine_test_class(TRUE)))
3483         return;
3484     cLocks = 0;
3485 
3486     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3487     ok_ole_success(hr, "CreateStreamOnHGlobal");
3488     tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_SMI, MSHLFLAGS_NORMAL, &thread);
3489 
3490     ok_more_than_one_lock();
3491 
3492     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3493     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
3494     ok_ole_success(hr, "CoUnmarshalInterface");
3495     IStream_Release(pStream);
3496 
3497     if(hr == S_OK)
3498     {
3499         ok_more_than_one_lock();
3500 
3501         hr = IUnknown_QueryInterface(pProxy, &IID_IWineTest, (void **)&pObject);
3502         ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface with unknown IID should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3503 
3504         /* it's a handler as it supports IOleObject */
3505         hr = IUnknown_QueryInterface(pProxy, &IID_IOleObject, (void **)&pObject);
3506         todo_wine
3507         ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
3508         if (SUCCEEDED(hr)) IUnknown_Release(pObject);
3509 
3510         IUnknown_Release(pProxy);
3511 
3512         ok_no_locks();
3513     }
3514 
3515     end_host_object(tid, thread);
3516     reg_unreg_wine_test_class(FALSE);
3517 
3518     /* FIXME: test IPersist interface has the same effect as IStdMarshalInfo */
3519 }
3520 
3521 
test_client_security(void)3522 static void test_client_security(void)
3523 {
3524     HRESULT hr;
3525     IStream *pStream = NULL;
3526     IClassFactory *pProxy = NULL;
3527     IUnknown *pProxy2 = NULL;
3528     IUnknown *pUnknown1 = NULL;
3529     IUnknown *pUnknown2 = NULL;
3530     IClientSecurity *pCliSec = NULL;
3531     IMarshal *pMarshal;
3532     DWORD tid;
3533     HANDLE thread;
3534     static const LARGE_INTEGER ullZero;
3535     DWORD dwAuthnSvc;
3536     DWORD dwAuthzSvc;
3537     OLECHAR *pServerPrincName;
3538     DWORD dwAuthnLevel;
3539     DWORD dwImpLevel;
3540     void *pAuthInfo;
3541     DWORD dwCapabilities;
3542     void *pv;
3543 
3544     cLocks = 0;
3545 
3546     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3547     ok_ole_success(hr, "CreateStreamOnHGlobal");
3548     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3549 
3550     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3551     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
3552     ok_ole_success(hr, "CoUnmarshalInterface");
3553     IStream_Release(pStream);
3554 
3555     hr = IClassFactory_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pUnknown1);
3556     ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
3557 
3558     hr = IClassFactory_QueryInterface(pProxy, &IID_IRemUnknown, (LPVOID*)&pProxy2);
3559     ok_ole_success(hr, "IUnknown_QueryInterface IID_IStream");
3560 
3561     hr = IUnknown_QueryInterface(pProxy2, &IID_IUnknown, (LPVOID*)&pUnknown2);
3562     ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
3563 
3564     ok(pUnknown1 == pUnknown2, "both proxy's IUnknowns should be the same - %p, %p\n", pUnknown1, pUnknown2);
3565 
3566     hr = IClassFactory_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pMarshal);
3567     ok_ole_success(hr, "IUnknown_QueryInterface IID_IMarshal");
3568 
3569     hr = IClassFactory_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pCliSec);
3570     ok_ole_success(hr, "IUnknown_QueryInterface IID_IClientSecurity");
3571 
3572     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3573     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket (all NULLs)");
3574 
3575     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pMarshal, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3576     todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_QueryBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3577 
3578     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
3579     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket");
3580 
3581     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, RPC_C_IMP_LEVEL_IMPERSONATE, pAuthInfo, dwCapabilities);
3582     todo_wine ok_ole_success(hr, "IClientSecurity_SetBlanket");
3583 
3584     hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IWineTest, &pv);
3585     ok(hr == E_NOINTERFACE, "COM call should have succeeded instead of returning 0x%08x\n", hr);
3586 
3587     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pMarshal, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
3588     todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_SetBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3589 
3590     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, 0xdeadbeef, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
3591     todo_wine ok(hr == E_INVALIDARG, "IClientSecurity_SetBlanke with invalid dwAuthnSvc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
3592 
3593     CoTaskMemFree(pServerPrincName);
3594 
3595     hr = IClientSecurity_QueryBlanket(pCliSec, pUnknown1, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
3596     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket(IUnknown)");
3597 
3598     CoTaskMemFree(pServerPrincName);
3599 
3600     IClassFactory_Release(pProxy);
3601     IUnknown_Release(pProxy2);
3602     IUnknown_Release(pUnknown1);
3603     IUnknown_Release(pUnknown2);
3604     IMarshal_Release(pMarshal);
3605     IClientSecurity_Release(pCliSec);
3606 
3607     end_host_object(tid, thread);
3608 }
3609 
3610 static HANDLE heventShutdown;
3611 
LockModuleOOP(void)3612 static void LockModuleOOP(void)
3613 {
3614     InterlockedIncrement(&cLocks); /* for test purposes only */
3615     CoAddRefServerProcess();
3616 }
3617 
UnlockModuleOOP(void)3618 static void UnlockModuleOOP(void)
3619 {
3620     InterlockedDecrement(&cLocks); /* for test purposes only */
3621     if (!CoReleaseServerProcess())
3622         SetEvent(heventShutdown);
3623 }
3624 
3625 static HWND hwnd_app;
3626 
3627 struct local_server
3628 {
3629     IPersist IPersist_iface; /* a nice short interface */
3630 };
3631 
local_server_QueryInterface(IPersist * iface,REFIID iid,void ** obj)3632 static HRESULT WINAPI local_server_QueryInterface(IPersist *iface, REFIID iid, void **obj)
3633 {
3634     *obj = NULL;
3635 
3636     if (IsEqualGUID(iid, &IID_IUnknown) ||
3637         IsEqualGUID(iid, &IID_IPersist))
3638         *obj = iface;
3639 
3640     if (*obj)
3641     {
3642         IPersist_AddRef(iface);
3643         return S_OK;
3644     }
3645     return E_NOINTERFACE;
3646 }
3647 
local_server_AddRef(IPersist * iface)3648 static ULONG WINAPI local_server_AddRef(IPersist *iface)
3649 {
3650     return 2;
3651 }
3652 
local_server_Release(IPersist * iface)3653 static ULONG WINAPI local_server_Release(IPersist *iface)
3654 {
3655     return 1;
3656 }
3657 
local_server_GetClassID(IPersist * iface,CLSID * clsid)3658 static HRESULT WINAPI local_server_GetClassID(IPersist *iface, CLSID *clsid)
3659 {
3660     HRESULT hr;
3661 
3662     *clsid = IID_IUnknown;
3663 
3664     /* Test calling CoDisconnectObject within a COM call */
3665     hr = CoDisconnectObject((IUnknown *)iface, 0);
3666     ok(hr == S_OK, "got %08x\n", hr);
3667 
3668     /* Initialize and uninitialize the apartment to show that we
3669      * remain in the autojoined mta */
3670     hr = pCoInitializeEx( NULL, COINIT_MULTITHREADED );
3671     ok( hr == S_FALSE, "got %08x\n", hr );
3672     CoUninitialize();
3673 
3674     return S_OK;
3675 }
3676 
3677 static const IPersistVtbl local_server_persist_vtbl =
3678 {
3679     local_server_QueryInterface,
3680     local_server_AddRef,
3681     local_server_Release,
3682     local_server_GetClassID
3683 };
3684 
3685 struct local_server local_server_class =
3686 {
3687     {&local_server_persist_vtbl}
3688 };
3689 
TestOOP_IClassFactory_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID * ppvObj)3690 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
3691     LPCLASSFACTORY iface,
3692     REFIID riid,
3693     LPVOID *ppvObj)
3694 {
3695     if (ppvObj == NULL) return E_POINTER;
3696 
3697     if (IsEqualGUID(riid, &IID_IUnknown) ||
3698         IsEqualGUID(riid, &IID_IClassFactory))
3699     {
3700         *ppvObj = iface;
3701         IClassFactory_AddRef(iface);
3702         return S_OK;
3703     }
3704 
3705     return E_NOINTERFACE;
3706 }
3707 
TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)3708 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
3709 {
3710     return 2; /* non-heap-based object */
3711 }
3712 
TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)3713 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
3714 {
3715     return 1; /* non-heap-based object */
3716 }
3717 
TestOOP_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)3718 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
3719     LPCLASSFACTORY iface,
3720     LPUNKNOWN pUnkOuter,
3721     REFIID riid,
3722     LPVOID *ppvObj)
3723 {
3724     IPersist *persist = &local_server_class.IPersist_iface;
3725     HRESULT hr;
3726     IPersist_AddRef( persist );
3727     hr = IPersist_QueryInterface( persist, riid, ppvObj );
3728     IPersist_Release( persist );
3729     return hr;
3730 }
3731 
TestOOP_IClassFactory_LockServer(LPCLASSFACTORY iface,BOOL fLock)3732 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
3733     LPCLASSFACTORY iface,
3734     BOOL fLock)
3735 {
3736     if (fLock)
3737         LockModuleOOP();
3738     else
3739         UnlockModuleOOP();
3740     return S_OK;
3741 }
3742 
3743 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
3744 {
3745     TestOOP_IClassFactory_QueryInterface,
3746     TestOOP_IClassFactory_AddRef,
3747     TestOOP_IClassFactory_Release,
3748     TestOOP_IClassFactory_CreateInstance,
3749     TestOOP_IClassFactory_LockServer
3750 };
3751 
3752 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
3753 
test_register_local_server(void)3754 static void test_register_local_server(void)
3755 {
3756     DWORD cookie;
3757     HRESULT hr;
3758     HANDLE ready_event;
3759     DWORD wait;
3760     HANDLE handles[2];
3761 
3762     heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
3763     ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
3764     handles[0] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
3765     handles[1] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event");
3766 
3767 again:
3768     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
3769                                CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
3770     ok_ole_success(hr, CoRegisterClassObject);
3771 
3772     SetEvent(ready_event);
3773 
3774     do
3775     {
3776         wait = MsgWaitForMultipleObjects(2, handles, FALSE, 30000, QS_ALLINPUT);
3777         if (wait == WAIT_OBJECT_0+2)
3778         {
3779             MSG msg;
3780 
3781             if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
3782             {
3783                 trace("Message 0x%x\n", msg.message);
3784                 TranslateMessage(&msg);
3785                 DispatchMessageA(&msg);
3786             }
3787         }
3788         else if (wait == WAIT_OBJECT_0+1)
3789         {
3790             hr = CoRevokeClassObject(cookie);
3791             ok_ole_success(hr, CoRevokeClassObject);
3792             goto again;
3793         }
3794     }
3795     while (wait == WAIT_OBJECT_0+2);
3796 
3797     ok( wait == WAIT_OBJECT_0, "quit event wait timed out\n" );
3798     hr = CoRevokeClassObject(cookie);
3799     ok_ole_success(hr, CoRevokeClassObject);
3800     CloseHandle(handles[0]);
3801     CloseHandle(handles[1]);
3802 }
3803 
create_target_process(const char * arg)3804 static HANDLE create_target_process(const char *arg)
3805 {
3806     char **argv;
3807     char cmdline[MAX_PATH];
3808     BOOL ret;
3809     PROCESS_INFORMATION pi;
3810     STARTUPINFOA si = { 0 };
3811     si.cb = sizeof(si);
3812 
3813     pi.hThread = NULL;
3814     pi.hProcess = NULL;
3815     winetest_get_mainargs( &argv );
3816     sprintf(cmdline, "\"%s\" %s %s", argv[0], argv[1], arg);
3817     ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3818     ok(ret, "CreateProcess failed with error: %u\n", GetLastError());
3819     if (pi.hThread) CloseHandle(pi.hThread);
3820     return pi.hProcess;
3821 }
3822 
3823 /* tests functions commonly used by out of process COM servers */
test_local_server(void)3824 static void test_local_server(void)
3825 {
3826     DWORD cookie;
3827     HRESULT hr;
3828     IClassFactory * cf;
3829     IPersist *persist;
3830     DWORD ret;
3831     HANDLE process;
3832     HANDLE quit_event;
3833     HANDLE ready_event;
3834     HANDLE repeat_event;
3835     CLSID clsid;
3836 
3837     heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
3838 
3839     cLocks = 0;
3840 
3841     /* Start the object suspended */
3842     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
3843         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
3844     ok_ole_success(hr, CoRegisterClassObject);
3845 
3846     /* ... and CoGetClassObject does not find it and fails when it looks for the
3847      * class in the registry */
3848     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
3849         NULL, &IID_IClassFactory, (LPVOID*)&cf);
3850     ok(hr == REGDB_E_CLASSNOTREG || /* NT */
3851        hr == S_OK /* Win9x */,
3852         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
3853 
3854     /* Resume the object suspended above ... */
3855     hr = CoResumeClassObjects();
3856     ok_ole_success(hr, CoResumeClassObjects);
3857 
3858     /* ... and now it should succeed */
3859     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
3860         NULL, &IID_IClassFactory, (LPVOID*)&cf);
3861     ok_ole_success(hr, CoGetClassObject);
3862 
3863     /* Now check the locking is working */
3864     /* NOTE: we are accessing the class directly, not through a proxy */
3865 
3866     ok_no_locks();
3867 
3868     hr = IClassFactory_LockServer(cf, TRUE);
3869     ok_ole_success(hr, IClassFactory_LockServer);
3870 
3871     ok_more_than_one_lock();
3872 
3873     IClassFactory_LockServer(cf, FALSE);
3874     ok_ole_success(hr, IClassFactory_LockServer);
3875 
3876     ok_no_locks();
3877 
3878     IClassFactory_Release(cf);
3879 
3880     /* wait for shutdown signal */
3881     ret = WaitForSingleObject(heventShutdown, 0);
3882     ok(ret != WAIT_TIMEOUT, "Server didn't shut down\n");
3883 
3884     /* try to connect again after SCM has suspended registered class objects */
3885     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
3886         &IID_IClassFactory, (LPVOID*)&cf);
3887     ok(hr == CO_E_SERVER_STOPPING || /* NT */
3888        hr == REGDB_E_CLASSNOTREG || /* win2k */
3889        hr == S_OK /* Win9x */,
3890         "CoGetClassObject should have returned CO_E_SERVER_STOPPING or REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
3891 
3892     hr = CoRevokeClassObject(cookie);
3893     ok_ole_success(hr, CoRevokeClassObject);
3894 
3895     CloseHandle(heventShutdown);
3896 
3897     process = create_target_process("-Embedding");
3898     ok(process != NULL, "couldn't start local server process, error was %d\n", GetLastError());
3899 
3900     ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
3901     ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
3902 
3903     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3904     ok_ole_success(hr, CoCreateInstance);
3905 
3906     IPersist_Release(persist);
3907 
3908     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3909     ok(hr == REGDB_E_CLASSNOTREG, "Second CoCreateInstance on REGCLS_SINGLEUSE object should have failed\n");
3910 
3911     /* Re-register the class and try calling CoDisconnectObject from within a call to that object */
3912     repeat_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event");
3913     SetEvent(repeat_event);
3914     CloseHandle(repeat_event);
3915 
3916     ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
3917     CloseHandle(ready_event);
3918 
3919     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3920     ok_ole_success(hr, CoCreateInstance);
3921 
3922     /* GetClassID will call CoDisconnectObject */
3923     IPersist_GetClassID(persist, &clsid);
3924     IPersist_Release(persist);
3925 
3926     quit_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
3927     SetEvent(quit_event);
3928 
3929     winetest_wait_child_process( process );
3930     CloseHandle(quit_event);
3931     CloseHandle(process);
3932 }
3933 
3934 struct git_params
3935 {
3936 	DWORD cookie;
3937 	IGlobalInterfaceTable *git;
3938 };
3939 
get_global_interface_proc(LPVOID pv)3940 static DWORD CALLBACK get_global_interface_proc(LPVOID pv)
3941 {
3942 	HRESULT hr;
3943 	struct git_params *params = pv;
3944 	IClassFactory *cf;
3945 
3946 	hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
3947 	ok(hr == CO_E_NOTINITIALIZED ||
3948 		broken(hr == E_UNEXPECTED) /* win2k */ ||
3949 		broken(hr == S_OK) /* NT 4 */,
3950 		"IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED or E_UNEXPECTED instead of 0x%08x\n",
3951 		hr);
3952 	if (hr == S_OK)
3953 		IClassFactory_Release(cf);
3954 
3955 	CoInitialize(NULL);
3956 
3957 	hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
3958 	ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
3959 
3960 	IClassFactory_Release(cf);
3961 
3962 	CoUninitialize();
3963 
3964 	return hr;
3965 }
3966 
test_globalinterfacetable(void)3967 static void test_globalinterfacetable(void)
3968 {
3969 	HRESULT hr;
3970 	IGlobalInterfaceTable *git;
3971 	DWORD cookie;
3972 	HANDLE thread;
3973 	DWORD tid;
3974 	struct git_params params;
3975 	DWORD ret;
3976         IUnknown *object;
3977         IClassFactory *cf;
3978         ULONG ref;
3979 
3980         trace("test_globalinterfacetable\n");
3981 	cLocks = 0;
3982 
3983 	hr = pDllGetClassObject(&CLSID_StdGlobalInterfaceTable, &IID_IClassFactory, (void**)&cf);
3984 	ok(hr == S_OK, "got 0x%08x\n", hr);
3985 
3986 	hr = IClassFactory_QueryInterface(cf, &IID_IGlobalInterfaceTable, (void**)&object);
3987 	ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
3988 
3989 	IClassFactory_Release(cf);
3990 
3991 	hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)&git);
3992 	ok_ole_success(hr, CoCreateInstance);
3993 
3994 	ref = IGlobalInterfaceTable_AddRef(git);
3995 	ok(ref == 1, "ref=%d\n", ref);
3996 	ref = IGlobalInterfaceTable_AddRef(git);
3997 	ok(ref == 1, "ref=%d\n", ref);
3998 
3999 	ref = IGlobalInterfaceTable_Release(git);
4000 	ok(ref == 1, "ref=%d\n", ref);
4001 	ref = IGlobalInterfaceTable_Release(git);
4002 	ok(ref == 1, "ref=%d\n", ref);
4003 
4004 	hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&Test_ClassFactory, &IID_IClassFactory, &cookie);
4005 	ok_ole_success(hr, IGlobalInterfaceTable_RegisterInterfaceInGlobal);
4006 
4007 	ok_more_than_one_lock();
4008 
4009 	params.cookie = cookie;
4010 	params.git = git;
4011 	/* note: params is on stack so we MUST wait for get_global_interface_proc
4012 	 * to exit before we can return */
4013 	thread = CreateThread(NULL, 0, get_global_interface_proc, &params, 0, &tid);
4014 
4015 	ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
4016 	while (ret == WAIT_OBJECT_0 + 1)
4017 	{
4018 		MSG msg;
4019 		while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
4020 			DispatchMessageA(&msg);
4021 		ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
4022 	}
4023 
4024 	CloseHandle(thread);
4025 
4026 	/* test getting interface from global with different iid */
4027 	hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, cookie, &IID_IUnknown, (void **)&object);
4028 	ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
4029 	IUnknown_Release(object);
4030 
4031 	/* test getting interface from global with same iid */
4032 	hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, cookie, &IID_IClassFactory, (void **)&object);
4033 	ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
4034 	IUnknown_Release(object);
4035 
4036 	hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, cookie);
4037 	ok_ole_success(hr, IGlobalInterfaceTable_RevokeInterfaceFromGlobal);
4038 
4039 	ok_no_locks();
4040 
4041 	IGlobalInterfaceTable_Release(git);
4042 }
4043 
test_manualresetevent(void)4044 static void test_manualresetevent(void)
4045 {
4046     ISynchronizeHandle *sync_handle;
4047     ISynchronize *psync1, *psync2;
4048     IUnknown *punk;
4049     HANDLE handle;
4050     LONG ref;
4051     HRESULT hr;
4052 
4053     hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&punk);
4054     ok(hr == S_OK, "Got 0x%08x\n", hr);
4055     ok(!!punk, "Got NULL.\n");
4056     IUnknown_Release(punk);
4057 
4058     hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_ISynchronize, (void**)&psync1);
4059     ok(hr == S_OK, "Got 0x%08x\n", hr);
4060     ok(!!psync1, "Got NULL.\n");
4061 
4062     hr = ISynchronize_Wait(psync1, 0, 5);
4063     ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4064 
4065     hr = ISynchronize_Reset(psync1);
4066     ok(hr == S_OK, "Got 0x%08x\n", hr);
4067     hr = ISynchronize_Signal(psync1);
4068     ok(hr == S_OK, "Got 0x%08x\n", hr);
4069     hr = ISynchronize_Wait(psync1, 0, 5);
4070     ok(hr == S_OK, "Got 0x%08x\n", hr);
4071     hr = ISynchronize_Wait(psync1, 0, 5);
4072     ok(hr == S_OK, "Got 0x%08x\n", hr);
4073     hr = ISynchronize_Reset(psync1);
4074     ok(hr == S_OK, "Got 0x%08x\n", hr);
4075     hr = ISynchronize_Wait(psync1, 0, 5);
4076     ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4077 
4078     hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_ISynchronize, (void**)&psync2);
4079     ok(hr == S_OK, "Got 0x%08x\n", hr);
4080     ok(!!psync2, "Got NULL.\n");
4081     ok(psync1 != psync2, "psync1 == psync2.\n");
4082 
4083     hr = ISynchronize_QueryInterface(psync2, &IID_ISynchronizeHandle, (void**)&sync_handle);
4084     ok(hr == S_OK, "QueryInterface(IID_ISynchronizeHandle) failed: %08x\n", hr);
4085 
4086     handle = NULL;
4087     hr = ISynchronizeHandle_GetHandle(sync_handle, &handle);
4088     ok(hr == S_OK, "GetHandle failed: %08x\n", hr);
4089     ok(handle != NULL && handle != INVALID_HANDLE_VALUE, "handle = %p\n", handle);
4090 
4091     ISynchronizeHandle_Release(sync_handle);
4092 
4093     hr = ISynchronize_Wait(psync2, 0, 5);
4094     ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4095 
4096     hr = ISynchronize_Reset(psync1);
4097     ok(hr == S_OK, "Got 0x%08x\n", hr);
4098     hr = ISynchronize_Reset(psync2);
4099     ok(hr == S_OK, "Got 0x%08x\n", hr);
4100     hr = ISynchronize_Signal(psync1);
4101     ok(hr == S_OK, "Got 0x%08x\n", hr);
4102     hr = ISynchronize_Wait(psync2, 0, 5);
4103     ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4104 
4105     ref = ISynchronize_AddRef(psync1);
4106     ok(ref == 2, "Got ref: %d\n", ref);
4107     ref = ISynchronize_AddRef(psync1);
4108     ok(ref == 3, "Got ref: %d\n", ref);
4109     ref = ISynchronize_Release(psync1);
4110     ok(ref == 2, "Got nonzero ref: %d\n", ref);
4111     ref = ISynchronize_Release(psync2);
4112     ok(!ref, "Got nonzero ref: %d\n", ref);
4113     ref = ISynchronize_Release(psync1);
4114     ok(ref == 1, "Got nonzero ref: %d\n", ref);
4115     ref = ISynchronize_Release(psync1);
4116     ok(!ref, "Got nonzero ref: %d\n", ref);
4117 }
4118 
implicit_mta_unmarshal_proc(void * param)4119 static DWORD CALLBACK implicit_mta_unmarshal_proc(void *param)
4120 {
4121     IStream *stream = param;
4122     IClassFactory *cf;
4123     IUnknown *proxy;
4124     HRESULT hr;
4125 
4126     IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
4127     hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
4128     ok_ole_success(hr, CoUnmarshalInterface);
4129 
4130     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4131     ok_ole_success(hr, IClassFactory_CreateInstance);
4132 
4133     IUnknown_Release(proxy);
4134 
4135     /* But if we initialize an STA in this apartment, it becomes the wrong one. */
4136     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4137 
4138     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4139     ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
4140 
4141     CoUninitialize();
4142 
4143     ok_more_than_one_lock();
4144     ok_non_zero_external_conn();
4145 
4146     IClassFactory_Release(cf);
4147 
4148     ok_no_locks();
4149     ok_zero_external_conn();
4150     ok_last_release_closes(TRUE);
4151     return 0;
4152 }
4153 
implicit_mta_use_proc(void * param)4154 static DWORD CALLBACK implicit_mta_use_proc(void *param)
4155 {
4156     IClassFactory *cf = param;
4157     IUnknown *proxy;
4158     HRESULT hr;
4159 
4160     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4161     ok_ole_success(hr, IClassFactory_CreateInstance);
4162 
4163     IUnknown_Release(proxy);
4164 
4165     /* But if we initialize an STA in this apartment, it becomes the wrong one. */
4166     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4167 
4168     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4169     ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
4170 
4171     CoUninitialize();
4172     return 0;
4173 }
4174 
4175 struct implicit_mta_marshal_data
4176 {
4177     IStream *stream;
4178     HANDLE start;
4179     HANDLE stop;
4180 };
4181 
implicit_mta_marshal_proc(void * param)4182 static DWORD CALLBACK implicit_mta_marshal_proc(void *param)
4183 {
4184     struct implicit_mta_marshal_data *data = param;
4185     HRESULT hr;
4186 
4187     hr = CoMarshalInterface(data->stream, &IID_IClassFactory,
4188         (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
4189     ok_ole_success(hr, CoMarshalInterface);
4190 
4191     SetEvent(data->start);
4192 
4193     ok(!WaitForSingleObject(data->stop, 1000), "wait failed\n");
4194     return 0;
4195 }
4196 
test_implicit_mta(void)4197 static void test_implicit_mta(void)
4198 {
4199     struct implicit_mta_marshal_data data;
4200     HANDLE host_thread, thread;
4201     IClassFactory *cf;
4202     IUnknown *proxy;
4203     IStream *stream;
4204     HRESULT hr;
4205     DWORD tid;
4206 
4207     cLocks = 0;
4208     external_connections = 0;
4209 
4210     CoInitializeEx(NULL, COINIT_MULTITHREADED);
4211 
4212     /* Firstly: we can unmarshal and use an object while in the implicit MTA. */
4213     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4214     ok_ole_success(hr, CreateStreamOnHGlobal);
4215     tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
4216 
4217     ok_more_than_one_lock();
4218     ok_non_zero_external_conn();
4219 
4220     thread = CreateThread(NULL, 0, implicit_mta_unmarshal_proc, stream, 0, NULL);
4221     ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4222     CloseHandle(thread);
4223 
4224     IStream_Release(stream);
4225     end_host_object(tid, host_thread);
4226 
4227     /* Secondly: we can unmarshal an object into the real MTA and then use it
4228      * from the implicit MTA. */
4229     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4230     ok_ole_success(hr, CreateStreamOnHGlobal);
4231     tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
4232 
4233     ok_more_than_one_lock();
4234     ok_non_zero_external_conn();
4235 
4236     IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
4237     hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
4238     ok_ole_success(hr, CoUnmarshalInterface);
4239 
4240     thread = CreateThread(NULL, 0, implicit_mta_use_proc, cf, 0, NULL);
4241     ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4242     CloseHandle(thread);
4243 
4244     IClassFactory_Release(cf);
4245     IStream_Release(stream);
4246 
4247     ok_no_locks();
4248     ok_non_zero_external_conn();
4249     ok_last_release_closes(TRUE);
4250 
4251     end_host_object(tid, host_thread);
4252 
4253     /* Thirdly: we can marshal an object from the implicit MTA and then
4254      * unmarshal it into the real one. */
4255     data.start = CreateEventA(NULL, FALSE, FALSE, NULL);
4256     data.stop  = CreateEventA(NULL, FALSE, FALSE, NULL);
4257 
4258     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.stream);
4259     ok_ole_success(hr, CreateStreamOnHGlobal);
4260 
4261     thread = CreateThread(NULL, 0, implicit_mta_marshal_proc, &data, 0, NULL);
4262     ok(!WaitForSingleObject(data.start, 1000), "wait failed\n");
4263 
4264     IStream_Seek(data.stream, ullZero, STREAM_SEEK_SET, NULL);
4265     hr = CoUnmarshalInterface(data.stream, &IID_IClassFactory, (void **)&cf);
4266     ok_ole_success(hr, CoUnmarshalInterface);
4267 
4268     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4269     ok_ole_success(hr, IClassFactory_CreateInstance);
4270 
4271     IUnknown_Release(proxy);
4272 
4273     SetEvent(data.stop);
4274     ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4275     CloseHandle(thread);
4276 
4277     IStream_Release(data.stream);
4278 
4279     CoUninitialize();
4280 }
4281 
debugstr_iid(REFIID riid)4282 static const char *debugstr_iid(REFIID riid)
4283 {
4284     static char name[256];
4285     HKEY hkeyInterface;
4286     WCHAR bufferW[39];
4287     char buffer[39];
4288     LONG name_size = sizeof(name);
4289     StringFromGUID2(riid, bufferW, ARRAY_SIZE(bufferW));
4290     WideCharToMultiByte(CP_ACP, 0, bufferW, ARRAY_SIZE(bufferW), buffer, sizeof(buffer), NULL, NULL);
4291     if (RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_QUERY_VALUE, &hkeyInterface) != ERROR_SUCCESS)
4292     {
4293         memcpy(name, buffer, sizeof(buffer));
4294         goto done;
4295     }
4296     if (RegQueryValueA(hkeyInterface, buffer, name, &name_size) != ERROR_SUCCESS)
4297     {
4298         memcpy(name, buffer, sizeof(buffer));
4299         goto done;
4300     }
4301     RegCloseKey(hkeyInterface);
4302 done:
4303     return name;
4304 }
4305 
TestChannelHook_QueryInterface(IChannelHook * iface,REFIID riid,void ** ppv)4306 static HRESULT WINAPI TestChannelHook_QueryInterface(IChannelHook *iface, REFIID riid, void **ppv)
4307 {
4308     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IChannelHook))
4309     {
4310         *ppv = iface;
4311         IChannelHook_AddRef(iface);
4312         return S_OK;
4313     }
4314 
4315     *ppv = NULL;
4316     return E_NOINTERFACE;
4317 }
4318 
TestChannelHook_AddRef(IChannelHook * iface)4319 static ULONG WINAPI TestChannelHook_AddRef(IChannelHook *iface)
4320 {
4321     return 2;
4322 }
4323 
TestChannelHook_Release(IChannelHook * iface)4324 static ULONG WINAPI TestChannelHook_Release(IChannelHook *iface)
4325 {
4326     return 1;
4327 }
4328 
4329 static BOOL new_hook_struct;
4330 static int method, server_tid;
4331 static GUID causality;
4332 
4333 struct new_hook_info
4334 {
4335     IID iid;
4336     GUID causality;
4337     DWORD server_pid;
4338     DWORD server_tid;
4339     WORD method;
4340 };
4341 
TestChannelHook_ClientGetSize(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG * pDataSize)4342 static void WINAPI TestChannelHook_ClientGetSize(
4343     IChannelHook *iface,
4344     REFGUID uExtent,
4345     REFIID  riid,
4346     ULONG  *pDataSize )
4347 {
4348     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4349     trace("TestChannelHook_ClientGetSize\n");
4350     trace("\t%s\n", debugstr_iid(riid));
4351     if (info->cbSize != sizeof(*info))
4352         new_hook_struct = TRUE;
4353 
4354     if (!new_hook_struct)
4355     {
4356         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4357         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4358         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4359         ok(!info->pObject, "pObject should be NULL\n");
4360         if (method == 3)
4361             causality = info->uCausality;
4362         else
4363             ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4364     }
4365     else
4366     {
4367         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4368         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4369            GetCurrentProcessId());
4370         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4371            server_tid);
4372         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4373         if (method == 3)
4374             causality = new_info->causality;
4375         else
4376             ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4377     }
4378 
4379     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4380 
4381     *pDataSize = 1;
4382 }
4383 
TestChannelHook_ClientFillBuffer(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG * pDataSize,void * pDataBuffer)4384 static void WINAPI TestChannelHook_ClientFillBuffer(
4385     IChannelHook *iface,
4386     REFGUID uExtent,
4387     REFIID  riid,
4388     ULONG  *pDataSize,
4389     void   *pDataBuffer )
4390 {
4391     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4392     trace("TestChannelHook_ClientFillBuffer\n");
4393 
4394     if (!new_hook_struct)
4395     {
4396         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4397         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4398         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4399         ok(!info->pObject, "pObject should be NULL\n");
4400         ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4401     }
4402     else
4403     {
4404         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4405         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4406            GetCurrentProcessId());
4407         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4408            server_tid);
4409         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4410         ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4411     }
4412 
4413     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4414 
4415     *(unsigned char *)pDataBuffer = 0xcc;
4416     *pDataSize = 1;
4417 }
4418 
TestChannelHook_ClientNotify(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG cbDataSize,void * pDataBuffer,DWORD lDataRep,HRESULT hrFault)4419 static void WINAPI TestChannelHook_ClientNotify(
4420     IChannelHook *iface,
4421     REFGUID uExtent,
4422     REFIID  riid,
4423     ULONG   cbDataSize,
4424     void   *pDataBuffer,
4425     DWORD   lDataRep,
4426     HRESULT hrFault )
4427 {
4428     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4429     trace("TestChannelHook_ClientNotify hrFault = 0x%08x\n", hrFault);
4430 
4431     if (!new_hook_struct)
4432     {
4433         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4434         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4435         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4436         todo_wine {
4437             ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4438         }
4439         ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4440     }
4441     else
4442     {
4443         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4444         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4445            GetCurrentProcessId());
4446         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4447            server_tid);
4448         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4449         ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4450     }
4451 
4452     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4453 }
4454 
TestChannelHook_ServerNotify(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG cbDataSize,void * pDataBuffer,DWORD lDataRep)4455 static void WINAPI TestChannelHook_ServerNotify(
4456     IChannelHook *iface,
4457     REFGUID uExtent,
4458     REFIID  riid,
4459     ULONG   cbDataSize,
4460     void   *pDataBuffer,
4461     DWORD   lDataRep )
4462 {
4463     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4464     trace("TestChannelHook_ServerNotify\n");
4465 
4466     if (!new_hook_struct)
4467     {
4468         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4469         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4470         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4471         ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4472         ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4473     }
4474     else
4475     {
4476         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4477         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4478            GetCurrentProcessId());
4479         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4480            server_tid);
4481         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4482         ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4483     }
4484 
4485     ok(cbDataSize == 1, "cbDataSize should have been 1 instead of %d\n", cbDataSize);
4486     ok(*(unsigned char *)pDataBuffer == 0xcc, "pDataBuffer should have contained 0xcc instead of 0x%x\n", *(unsigned char *)pDataBuffer);
4487     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4488 }
4489 
TestChannelHook_ServerGetSize(IChannelHook * iface,REFGUID uExtent,REFIID riid,HRESULT hrFault,ULONG * pDataSize)4490 static void WINAPI TestChannelHook_ServerGetSize(
4491     IChannelHook *iface,
4492     REFGUID uExtent,
4493     REFIID  riid,
4494     HRESULT hrFault,
4495     ULONG  *pDataSize )
4496 {
4497     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4498     trace("TestChannelHook_ServerGetSize\n");
4499     trace("\t%s\n", debugstr_iid(riid));
4500     if (!new_hook_struct)
4501     {
4502         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4503         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4504         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4505         ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4506         ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4507     }
4508     else
4509     {
4510         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4511         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4512            GetCurrentProcessId());
4513         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4514            server_tid);
4515         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4516         ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4517     }
4518 
4519     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4520     if (hrFault != S_OK)
4521         trace("\thrFault = 0x%08x\n", hrFault);
4522 
4523     *pDataSize = 0;
4524 }
4525 
TestChannelHook_ServerFillBuffer(IChannelHook * iface,REFGUID uExtent,REFIID riid,ULONG * pDataSize,void * pDataBuffer,HRESULT hrFault)4526 static void WINAPI TestChannelHook_ServerFillBuffer(
4527     IChannelHook *iface,
4528     REFGUID uExtent,
4529     REFIID  riid,
4530     ULONG  *pDataSize,
4531     void   *pDataBuffer,
4532     HRESULT hrFault )
4533 {
4534     trace("TestChannelHook_ServerFillBuffer\n");
4535     ok(0, "TestChannelHook_ServerFillBuffer shouldn't be called\n");
4536 }
4537 
4538 static const IChannelHookVtbl TestChannelHookVtbl =
4539 {
4540     TestChannelHook_QueryInterface,
4541     TestChannelHook_AddRef,
4542     TestChannelHook_Release,
4543     TestChannelHook_ClientGetSize,
4544     TestChannelHook_ClientFillBuffer,
4545     TestChannelHook_ClientNotify,
4546     TestChannelHook_ServerNotify,
4547     TestChannelHook_ServerGetSize,
4548     TestChannelHook_ServerFillBuffer,
4549 };
4550 
4551 static IChannelHook TestChannelHook = { &TestChannelHookVtbl };
4552 
test_channel_hook(void)4553 static void test_channel_hook(void)
4554 {
4555     IClassFactory *cf = NULL;
4556     DWORD tid;
4557     IUnknown *proxy = NULL;
4558     HANDLE thread;
4559     HRESULT hr;
4560 
4561     struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
4562                                             MSHLFLAGS_NORMAL, &MessageFilter };
4563 
4564     hr = CoRegisterChannelHook(&EXTENTID_WineTest, &TestChannelHook);
4565     ok_ole_success(hr, CoRegisterChannelHook);
4566 
4567     hr = CoRegisterMessageFilter(&MessageFilter, NULL);
4568     ok_ole_success(hr, CoRegisterMessageFilter);
4569 
4570     cLocks = 0;
4571 
4572     hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
4573     ok_ole_success(hr, CreateStreamOnHGlobal);
4574     tid = start_host_object2(&object_data, &thread);
4575     server_tid = tid;
4576 
4577     ok_more_than_one_lock();
4578 
4579     IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
4580     hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
4581     ok_ole_success(hr, CoUnmarshalInterface);
4582     IStream_Release(object_data.stream);
4583 
4584     ok_more_than_one_lock();
4585 
4586     method = 3;
4587     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
4588     ok_ole_success(hr, IClassFactory_CreateInstance);
4589 
4590     method = 5;
4591     IUnknown_Release(proxy);
4592 
4593     IClassFactory_Release(cf);
4594 
4595     ok_no_locks();
4596 
4597     end_host_object(tid, thread);
4598 
4599     hr = CoRegisterMessageFilter(NULL, NULL);
4600     ok_ole_success(hr, CoRegisterMessageFilter);
4601 }
4602 
START_TEST(marshal)4603 START_TEST(marshal)
4604 {
4605     HMODULE hOle32 = GetModuleHandleA("ole32");
4606     int argc;
4607     char **argv;
4608 
4609     if (!GetProcAddress(hOle32, "CoRegisterSurrogateEx")) {
4610         win_skip("skipping test on win9x\n");
4611         return;
4612     }
4613 
4614     pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx");
4615     pDllGetClassObject = (void*)GetProcAddress(hOle32, "DllGetClassObject");
4616 
4617     argc = winetest_get_mainargs( &argv );
4618     if (argc > 2 && (!strcmp(argv[2], "-Embedding")))
4619     {
4620         pCoInitializeEx(NULL, COINIT_MULTITHREADED);
4621         test_register_local_server();
4622         CoUninitialize();
4623 
4624         return;
4625     }
4626 
4627     register_test_window();
4628 
4629     test_cocreateinstance_proxy();
4630     test_implicit_mta();
4631 
4632     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4633 
4634     /* FIXME: test CoCreateInstanceEx */
4635 
4636     /* lifecycle management and marshaling tests */
4637     do
4638     {
4639         test_no_marshaler();
4640         test_normal_marshal_and_release();
4641         test_normal_marshal_and_unmarshal();
4642         test_marshal_and_unmarshal_invalid();
4643         test_same_apartment_unmarshal_failure();
4644         test_interthread_marshal_and_unmarshal();
4645         test_proxy_marshal_and_unmarshal();
4646         test_proxy_marshal_and_unmarshal2();
4647         test_proxy_marshal_and_unmarshal_weak();
4648         test_proxy_marshal_and_unmarshal_strong();
4649         test_marshal_stub_apartment_shutdown();
4650         test_marshal_proxy_apartment_shutdown();
4651         test_marshal_proxy_mta_apartment_shutdown();
4652         test_no_couninitialize_server();
4653         test_no_couninitialize_client();
4654         test_tableweak_marshal_and_unmarshal_twice();
4655         test_tableweak_marshal_releasedata1();
4656         test_tableweak_marshal_releasedata2();
4657         test_tableweak_and_normal_marshal_and_unmarshal();
4658         test_tableweak_and_normal_marshal_and_releasedata();
4659         test_two_tableweak_marshal_and_releasedata();
4660         test_tablestrong_marshal_and_unmarshal_twice();
4661         test_lock_object_external();
4662         test_disconnect_stub();
4663         test_normal_marshal_and_unmarshal_twice();
4664 
4665         with_external_conn = !with_external_conn;
4666     } while (with_external_conn);
4667 
4668     test_marshal_channel_buffer();
4669     test_StdMarshal_custom_marshaling();
4670     test_DfMarshal_custom_marshaling();
4671     test_CoGetStandardMarshal();
4672     test_hresult_marshaling();
4673     test_proxy_used_in_wrong_thread();
4674     test_message_filter();
4675     test_bad_marshal_stream();
4676     test_proxy_interfaces();
4677     test_stubbuffer(&IID_IClassFactory);
4678     test_proxybuffer(&IID_IClassFactory);
4679     test_message_reentrancy();
4680     test_call_from_message();
4681     test_WM_QUIT_handling();
4682     test_freethreadedmarshaler();
4683     test_inproc_handler();
4684     test_handler_marshaling();
4685     test_client_security();
4686 
4687     test_local_server();
4688 
4689     test_globalinterfacetable();
4690     test_manualresetevent();
4691     test_crash_couninitialize();
4692 
4693     /* must be last test as channel hooks can't be unregistered */
4694     test_channel_hook();
4695 
4696     CoUninitialize();
4697 }
4698