[OLE32_WINETEST] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / modules / rostests / winetests / ole32 / marshal.c
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
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
171 static void LockModule(void)
172 {
173 InterlockedIncrement(&cLocks);
174 }
175
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
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
192 static ULONG WINAPI ExternalConnection_AddRef(IExternalConnection *iface)
193 {
194 return 2;
195 }
196
197 static ULONG WINAPI ExternalConnection_Release(IExternalConnection *iface)
198 {
199 return 1;
200 }
201
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
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
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
246 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
247 {
248 LockModule();
249 return 2; /* non-heap-based object */
250 }
251
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
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
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
313 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
314 {
315 LockModule();
316 return 2; /* non-heap-based object */
317 }
318
319 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
320 {
321 UnlockModule();
322 return 1; /* non-heap-based object */
323 }
324
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
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
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
366 static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
367 {
368 return 2;
369 }
370
371 static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
372 {
373 return 1;
374 }
375
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
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
409 static ULONG WINAPI OleClientSite_AddRef(IOleClientSite *iface)
410 {
411 return 2;
412 }
413
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
434 static StubBufferWrapper *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
435 {
436 return CONTAINING_RECORD(iface, StubBufferWrapper, IRpcStubBuffer_iface);
437 }
438
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
454 static ULONG WINAPI RpcStubBuffer_AddRef(IRpcStubBuffer *iface)
455 {
456 StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
457 return InterlockedIncrement(&This->ref);
458 }
459
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
471 static HRESULT WINAPI RpcStubBuffer_Connect(IRpcStubBuffer *iface, IUnknown *pUnkServer)
472 {
473 ok(0, "unexpected call\n");
474 return E_NOTIMPL;
475 }
476
477 static void WINAPI RpcStubBuffer_Disconnect(IRpcStubBuffer *iface)
478 {
479 CHECK_EXPECT(Disconnect);
480 }
481
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
500 static IRpcStubBuffer *WINAPI RpcStubBuffer_IsIIDSupported(IRpcStubBuffer *iface, REFIID riid)
501 {
502 ok(0, "unexpected call\n");
503 return NULL;
504 }
505
506 static ULONG WINAPI RpcStubBuffer_CountRefs(IRpcStubBuffer *iface)
507 {
508 ok(0, "unexpected call\n");
509 return E_NOTIMPL;
510 }
511
512 static HRESULT WINAPI RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer *iface, void **ppv)
513 {
514 ok(0, "unexpected call\n");
515 return E_NOTIMPL;
516 }
517
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
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
551 static ULONG WINAPI PSFactoryBuffer_AddRef(IPSFactoryBuffer *iface)
552 {
553 return 2;
554 }
555
556 static ULONG WINAPI PSFactoryBuffer_Release(IPSFactoryBuffer *iface)
557 {
558 return 1;
559 }
560
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
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
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
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
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. */
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
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 */
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 */
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 */
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 */
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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
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
1384 static ULONG WINAPI CustomMarshal_AddRef(IMarshal *iface)
1385 {
1386 return 2;
1387 }
1388
1389 static ULONG WINAPI CustomMarshal_Release(IMarshal *iface)
1390 {
1391 return 1;
1392 }
1393
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
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
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
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
1447 static HRESULT WINAPI CustomMarshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
1448 {
1449 ok(0, "unexpected call\n");
1450 return E_NOTIMPL;
1451 }
1452
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
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
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
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 */
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 */
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 */
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 */
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
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
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 */
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 */
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 */
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
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 */
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
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
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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
2584 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
2585 {
2586 return 2; /* non-heap object */
2587 }
2588
2589 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
2590 {
2591 return 1; /* non-heap object */
2592 }
2593
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
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
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
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 */
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 */
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
2784 static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
2785 {
2786 return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
2787 }
2788
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
2801 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
2802 {
2803 HeapUnknown *This = impl_from_IUnknown(iface);
2804 return InterlockedIncrement((LONG*)&This->refs);
2805 }
2806
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
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
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
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
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
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
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
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
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))