22a67960120415167d0e1f67a8f65e59f57f7994
[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((IUnknown*)&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 IUnknown *pProxy = NULL;
1209 DWORD tid;
1210 HANDLE thread;
1211
1212 cLocks = 0;
1213 external_connections = 0;
1214
1215 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1216 ok_ole_success(hr, CreateStreamOnHGlobal);
1217 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1218
1219 ok_more_than_one_lock();
1220 ok_non_zero_external_conn();
1221
1222 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1223 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1224 ok_ole_success(hr, CoUnmarshalInterface);
1225 IStream_Release(pStream);
1226
1227 ok_more_than_one_lock();
1228 ok_non_zero_external_conn();
1229
1230 CoUninitialize();
1231
1232 ok_no_locks();
1233 ok_zero_external_conn();
1234 ok_last_release_closes(TRUE);
1235
1236 IUnknown_Release(pProxy);
1237
1238 ok_no_locks();
1239
1240 end_host_object(tid, thread);
1241
1242 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1243 }
1244
1245 /* tests that proxies are released when the containing mta apartment is destroyed */
1246 static void test_marshal_proxy_mta_apartment_shutdown(void)
1247 {
1248 HRESULT hr;
1249 IStream *pStream = NULL;
1250 IUnknown *pProxy = NULL;
1251 DWORD tid;
1252 HANDLE thread;
1253
1254 CoUninitialize();
1255 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1256
1257 cLocks = 0;
1258 external_connections = 0;
1259
1260 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1261 ok_ole_success(hr, CreateStreamOnHGlobal);
1262 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1263
1264 ok_more_than_one_lock();
1265 ok_non_zero_external_conn();
1266
1267 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1268 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1269 ok_ole_success(hr, CoUnmarshalInterface);
1270 IStream_Release(pStream);
1271
1272 ok_more_than_one_lock();
1273 ok_non_zero_external_conn();
1274
1275 CoUninitialize();
1276
1277 ok_no_locks();
1278 ok_zero_external_conn();
1279 ok_last_release_closes(TRUE);
1280
1281 IUnknown_Release(pProxy);
1282
1283 ok_no_locks();
1284
1285 end_host_object(tid, thread);
1286
1287 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1288 }
1289
1290 static void test_marshal_channel_buffer(void)
1291 {
1292 DWORD registration_key;
1293 IUnknown *proxy = NULL;
1294 IOleWindow *ole_window;
1295 HWND hwnd;
1296 CLSID clsid;
1297 DWORD tid;
1298 HANDLE thread;
1299 HRESULT hr;
1300
1301 struct host_object_data object_data = { NULL, &IID_IOleClientSite, (IUnknown*)&Test_OleClientSite,
1302 MSHLFLAGS_NORMAL, NULL, (IUnknown*)&PSFactoryBuffer,
1303 &CLSID_WineTestPSFactoryBuffer };
1304
1305 cLocks = 0;
1306 external_connections = 0;
1307
1308 hr = CoGetPSClsid(&IID_IOleWindow, &clsid);
1309 ok_ole_success(hr, "CoGetPSClsid");
1310
1311 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer,
1312 (void **)&ps_factory_buffer);
1313 ok_ole_success(hr, "CoGetClassObject");
1314
1315 hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
1316 ok_ole_success(hr, CreateStreamOnHGlobal);
1317 tid = start_host_object2(&object_data, &thread);
1318
1319 IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
1320 hr = CoUnmarshalInterface(object_data.stream, &IID_IUnknown, (void **)&proxy);
1321 ok_ole_success(hr, CoUnmarshalInterface);
1322 IStream_Release(object_data.stream);
1323
1324 hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
1325 CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &registration_key);
1326 ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
1327
1328 hr = CoRegisterPSClsid(&IID_IOleWindow, &CLSID_WineTestPSFactoryBuffer);
1329 ok(hr == S_OK, "CoRegisterPSClsid failed: %08x\n", hr);
1330
1331 SET_EXPECT(CreateStub);
1332 SET_EXPECT(CreateProxy);
1333 hr = IUnknown_QueryInterface(proxy, &IID_IOleWindow, (void**)&ole_window);
1334 ok(hr == S_OK, "Could not get IOleWindow iface: %08x\n", hr);
1335 CHECK_CALLED(CreateStub);
1336 CHECK_CALLED(CreateProxy);
1337
1338 SET_EXPECT(Invoke);
1339 SET_EXPECT(GetWindow);
1340 hr = IOleWindow_GetWindow(ole_window, &hwnd);
1341 ok(hr == S_OK, "GetWindow failed: %08x\n", hr);
1342 ok((DWORD)(DWORD_PTR)hwnd == 0xdeadbeef, "hwnd = %p\n", hwnd);
1343 CHECK_CALLED(Invoke);
1344 CHECK_CALLED(GetWindow);
1345
1346 IOleWindow_Release(ole_window);
1347
1348 SET_EXPECT(Disconnect);
1349 IUnknown_Release(proxy);
1350 todo_wine
1351 CHECK_CALLED(Disconnect);
1352
1353 hr = CoRevokeClassObject(registration_key);
1354 ok(hr == S_OK, "CoRevokeClassObject failed: %08x\n", hr);
1355
1356 end_host_object(tid, thread);
1357 }
1358
1359 static const CLSID *unmarshal_class;
1360 DEFINE_EXPECT(CustomMarshal_GetUnmarshalClass);
1361 DEFINE_EXPECT(CustomMarshal_GetMarshalSizeMax);
1362 DEFINE_EXPECT(CustomMarshal_MarshalInterface);
1363
1364 static HRESULT WINAPI CustomMarshal_QueryInterface(IMarshal *iface, REFIID riid, void **ppv)
1365 {
1366 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal)) {
1367 *ppv = iface;
1368 }
1369 else
1370 {
1371 *ppv = NULL;
1372 return E_NOINTERFACE;
1373 }
1374 IUnknown_AddRef((IUnknown*)*ppv);
1375 return S_OK;
1376 }
1377
1378 static ULONG WINAPI CustomMarshal_AddRef(IMarshal *iface)
1379 {
1380 return 2;
1381 }
1382
1383 static ULONG WINAPI CustomMarshal_Release(IMarshal *iface)
1384 {
1385 return 1;
1386 }
1387
1388 static HRESULT WINAPI CustomMarshal_GetUnmarshalClass(IMarshal *iface, REFIID riid,
1389 void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *clsid)
1390 {
1391 CHECK_EXPECT(CustomMarshal_GetUnmarshalClass);
1392 *clsid = *unmarshal_class;
1393 return S_OK;
1394 }
1395
1396 static HRESULT WINAPI CustomMarshal_GetMarshalSizeMax(IMarshal *iface, REFIID riid,
1397 void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *size)
1398 {
1399 CHECK_EXPECT(CustomMarshal_GetMarshalSizeMax);
1400 ok(size != NULL, "size = NULL\n");
1401
1402 *size = 0;
1403 return S_OK;
1404 }
1405
1406 static HRESULT WINAPI CustomMarshal_MarshalInterface(IMarshal *iface, IStream *stream,
1407 REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
1408 {
1409 IMarshal *std_marshal;
1410 STATSTG stat;
1411 HRESULT hr;
1412
1413 CHECK_EXPECT(CustomMarshal_MarshalInterface);
1414
1415 if(unmarshal_class != &CLSID_StdMarshal)
1416 return S_OK;
1417
1418 hr = IStream_Stat(stream, &stat, STATFLAG_DEFAULT);
1419 ok_ole_success(hr, IStream_Stat);
1420 ok(U(stat.cbSize).LowPart == 0, "stream is not empty (%d)\n", U(stat.cbSize).LowPart);
1421 ok(U(stat.cbSize).HighPart == 0, "stream is not empty (%d)\n", U(stat.cbSize).HighPart);
1422
1423 hr = CoGetStandardMarshal(riid, (IUnknown*)iface,
1424 dwDestContext, NULL, mshlflags, &std_marshal);
1425 ok_ole_success(hr, CoGetStandardMarshal);
1426 hr = IMarshal_MarshalInterface(std_marshal, stream, riid, pv,
1427 dwDestContext, pvDestContext, mshlflags);
1428 ok_ole_success(hr, IMarshal_MarshalInterface);
1429 IMarshal_Release(std_marshal);
1430
1431 return S_OK;
1432 }
1433
1434 static HRESULT WINAPI CustomMarshal_UnmarshalInterface(IMarshal *iface,
1435 IStream *stream, REFIID riid, void **ppv)
1436 {
1437 ok(0, "unexpected call\n");
1438 return E_NOTIMPL;
1439 }
1440
1441 static HRESULT WINAPI CustomMarshal_ReleaseMarshalData(IMarshal *iface, IStream *stream)
1442 {
1443 ok(0, "unexpected call\n");
1444 return E_NOTIMPL;
1445 }
1446
1447 static HRESULT WINAPI CustomMarshal_DisconnectObject(IMarshal *iface, DWORD res)
1448 {
1449 ok(0, "unexpected call\n");
1450 return E_NOTIMPL;
1451 }
1452
1453 static IMarshalVtbl CustomMarshalVtbl =
1454 {
1455 CustomMarshal_QueryInterface,
1456 CustomMarshal_AddRef,
1457 CustomMarshal_Release,
1458 CustomMarshal_GetUnmarshalClass,
1459 CustomMarshal_GetMarshalSizeMax,
1460 CustomMarshal_MarshalInterface,
1461 CustomMarshal_UnmarshalInterface,
1462 CustomMarshal_ReleaseMarshalData,
1463 CustomMarshal_DisconnectObject
1464 };
1465
1466 static IMarshal CustomMarshal = { &CustomMarshalVtbl };
1467
1468 static void test_StdMarshal_custom_marshaling(void)
1469 {
1470 IStream *stream;
1471 IUnknown *unk;
1472 DWORD size;
1473 HRESULT hr;
1474
1475 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1476 ok_ole_success(hr, CreateStreamOnHGlobal);
1477
1478 unmarshal_class = &CLSID_StdMarshal;
1479 SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1480 SET_EXPECT(CustomMarshal_MarshalInterface);
1481 hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1482 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1483 ok_ole_success(hr, CoMarshalInterface);
1484 CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1485 CHECK_CALLED(CustomMarshal_MarshalInterface);
1486
1487 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1488 ok_ole_success(hr, IStream_Seek);
1489 hr = CoUnmarshalInterface(stream, &IID_IUnknown, (void**)&unk);
1490 ok_ole_success(hr, CoUnmarshalInterface);
1491 ok(unk == (IUnknown*)&CustomMarshal, "unk != &CustomMarshal\n");
1492 IUnknown_Release(unk);
1493 IStream_Release(stream);
1494
1495 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1496 ok_ole_success(hr, CreateStreamOnHGlobal);
1497
1498 SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1499 SET_EXPECT(CustomMarshal_MarshalInterface);
1500 hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1501 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1502 ok_ole_success(hr, CoMarshalInterface);
1503 CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1504 CHECK_CALLED(CustomMarshal_MarshalInterface);
1505
1506 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1507 ok_ole_success(hr, IStream_Seek);
1508 hr = CoReleaseMarshalData(stream);
1509 ok_ole_success(hr, CoReleaseMarshalData);
1510 IStream_Release(stream);
1511
1512 SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1513 hr = CoGetMarshalSizeMax(&size, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1514 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1515 ok_ole_success(hr, CoGetMarshalSizeMax);
1516 CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1517 ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF));
1518 }
1519
1520 static void test_DfMarshal_custom_marshaling(void)
1521 {
1522 DWORD size, read;
1523 IStream *stream;
1524 OBJREF objref;
1525 HRESULT hr;
1526
1527 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1528 ok_ole_success(hr, CreateStreamOnHGlobal);
1529
1530 unmarshal_class = &CLSID_DfMarshal;
1531 SET_EXPECT(CustomMarshal_GetUnmarshalClass);
1532 SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1533 SET_EXPECT(CustomMarshal_MarshalInterface);
1534 hr = CoMarshalInterface(stream, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1535 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1536 ok_ole_success(hr, CoMarshalInterface);
1537 CHECK_CALLED(CustomMarshal_GetUnmarshalClass);
1538 CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1539 CHECK_CALLED(CustomMarshal_MarshalInterface);
1540
1541 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1542 ok_ole_success(hr, IStream_Seek);
1543 size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData);
1544 hr = IStream_Read(stream, &objref, size, &read);
1545 ok_ole_success(hr, IStream_Read);
1546 ok(read == size, "read = %d, expected %d\n", read, size);
1547 ok(objref.signature == OBJREF_SIGNATURE, "objref.signature = %x\n",
1548 objref.signature);
1549 ok(objref.flags == OBJREF_CUSTOM, "objref.flags = %x\n", objref.flags);
1550 ok(IsEqualIID(&objref.iid, &IID_IUnknown), "objref.iid = %s\n",
1551 wine_dbgstr_guid(&objref.iid));
1552 ok(IsEqualIID(&objref.u_objref.u_custom.clsid, &CLSID_DfMarshal),
1553 "custom.clsid = %s\n", wine_dbgstr_guid(&objref.u_objref.u_custom.clsid));
1554 ok(!objref.u_objref.u_custom.cbExtension, "custom.cbExtension = %d\n",
1555 objref.u_objref.u_custom.cbExtension);
1556 ok(!objref.u_objref.u_custom.size, "custom.size = %d\n",
1557 objref.u_objref.u_custom.size);
1558
1559 IStream_Release(stream);
1560
1561 SET_EXPECT(CustomMarshal_GetMarshalSizeMax);
1562 hr = CoGetMarshalSizeMax(&size, &IID_IUnknown, (IUnknown*)&CustomMarshal,
1563 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1564 ok_ole_success(hr, CoGetMarshalSizeMax);
1565 CHECK_CALLED(CustomMarshal_GetMarshalSizeMax);
1566 ok(size == sizeof(OBJREF), "size = %d, expected %d\n", size, (int)sizeof(OBJREF));
1567 }
1568
1569 static void test_CoGetStandardMarshal(void)
1570 {
1571 DUALSTRINGARRAY *dualstringarr;
1572 STDOBJREF *stdobjref;
1573 OBJREF objref;
1574 IMarshal *marshal;
1575 DWORD size, read;
1576 IStream *stream;
1577 IUnknown *unk;
1578 CLSID clsid;
1579 HRESULT hr;
1580
1581 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1582 ok_ole_success(hr, CreateStreamOnHGlobal);
1583
1584 hr = CoGetStandardMarshal(&IID_IUnknown, &Test_Unknown,
1585 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &marshal);
1586 ok_ole_success(hr, CoGetStandardMarshal);
1587
1588 hr = IMarshal_GetUnmarshalClass(marshal, &IID_IUnknown, &Test_Unknown,
1589 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &clsid);
1590 ok_ole_success(hr, IMarshal_GetUnmarshalClass);
1591 ok(IsEqualGUID(&clsid, &CLSID_StdMarshal), "clsid = %s\n", wine_dbgstr_guid(&clsid));
1592
1593 hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IUnknown, &Test_Unknown,
1594 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &size);
1595 ok_ole_success(hr, IMarshal_GetMarshalSizeMax);
1596 hr = CoGetMarshalSizeMax(&read, &IID_IUnknown, &Test_Unknown,
1597 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1598 ok_ole_success(hr, CoGetMarshalSizeMax);
1599 ok(size == read, "IMarshal_GetMarshalSizeMax size = %d, expected %d\n", size, read);
1600
1601 hr = IMarshal_MarshalInterface(marshal, stream, &IID_IUnknown,
1602 &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1603 ok_ole_success(hr, IMarshal_MarshalInterface);
1604
1605 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1606 ok_ole_success(hr, IStream_Seek);
1607 size = FIELD_OFFSET(OBJREF, u_objref.u_standard.saResAddr.aStringArray);
1608 hr = IStream_Read(stream, &objref, size, &read);
1609 ok_ole_success(hr, IStream_Read);
1610 ok(read == size, "read = %d, expected %d\n", read, size);
1611 ok(objref.signature == OBJREF_SIGNATURE, "objref.signature = %x\n",
1612 objref.signature);
1613 ok(objref.flags == OBJREF_STANDARD, "objref.flags = %x\n", objref.flags);
1614 ok(IsEqualIID(&objref.iid, &IID_IUnknown), "objref.iid = %s\n",
1615 wine_dbgstr_guid(&objref.iid));
1616 stdobjref = &objref.u_objref.u_standard.std;
1617 ok(stdobjref->flags == 0, "stdobjref.flags = %d\n", stdobjref->flags);
1618 ok(stdobjref->cPublicRefs == 5, "stdobjref.cPublicRefs = %d\n",
1619 stdobjref->cPublicRefs);
1620 dualstringarr = &objref.u_objref.u_standard.saResAddr;
1621 ok(dualstringarr->wNumEntries == 0, "dualstringarr.wNumEntries = %d\n",
1622 dualstringarr->wNumEntries);
1623 ok(dualstringarr->wSecurityOffset == 0, "dualstringarr.wSecurityOffset = %d\n",
1624 dualstringarr->wSecurityOffset);
1625
1626 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1627 ok_ole_success(hr, IStream_Seek);
1628 hr = IMarshal_UnmarshalInterface(marshal, stream, &IID_IUnknown, (void**)&unk);
1629 ok_ole_success(hr, IMarshal_UnmarshalInterface);
1630 IUnknown_Release(unk);
1631
1632 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1633 ok_ole_success(hr, IStream_Seek);
1634 hr = IMarshal_MarshalInterface(marshal, stream, &IID_IUnknown,
1635 &Test_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1636 ok_ole_success(hr, IMarshal_MarshalInterface);
1637
1638 hr = IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1639 ok_ole_success(hr, IStream_Seek);
1640 hr = IMarshal_ReleaseMarshalData(marshal, stream);
1641 ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1642 IStream_Release(stream);
1643
1644 IMarshal_Release(marshal);
1645 }
1646 struct ncu_params
1647 {
1648 LPSTREAM stream;
1649 HANDLE marshal_event;
1650 HANDLE unmarshal_event;
1651 };
1652
1653 /* helper for test_no_couninitialize_server */
1654 static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p)
1655 {
1656 struct ncu_params *ncu_params = p;
1657 HRESULT hr;
1658
1659 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1660
1661 hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1662 ok_ole_success(hr, CoMarshalInterface);
1663
1664 SetEvent(ncu_params->marshal_event);
1665
1666 ok( !WaitForSingleObject(ncu_params->unmarshal_event, 10000), "wait timed out\n" );
1667
1668 /* die without calling CoUninitialize */
1669
1670 return 0;
1671 }
1672
1673 /* tests apartment that an apartment with a stub is released without deadlock
1674 * if the owning thread exits */
1675 static void test_no_couninitialize_server(void)
1676 {
1677 HRESULT hr;
1678 IStream *pStream = NULL;
1679 IUnknown *pProxy = NULL;
1680 DWORD tid;
1681 HANDLE thread;
1682 struct ncu_params ncu_params;
1683
1684 cLocks = 0;
1685 external_connections = 0;
1686
1687 ncu_params.marshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
1688 ncu_params.unmarshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
1689
1690 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1691 ok_ole_success(hr, CreateStreamOnHGlobal);
1692 ncu_params.stream = pStream;
1693
1694 thread = CreateThread(NULL, 0, no_couninitialize_server_proc, &ncu_params, 0, &tid);
1695
1696 ok( !WaitForSingleObject(ncu_params.marshal_event, 10000), "wait timed out\n" );
1697 ok_more_than_one_lock();
1698 ok_non_zero_external_conn();
1699
1700 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1701 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1702 ok_ole_success(hr, CoUnmarshalInterface);
1703 IStream_Release(pStream);
1704
1705 ok_more_than_one_lock();
1706 ok_non_zero_external_conn();
1707
1708 SetEvent(ncu_params.unmarshal_event);
1709 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1710
1711 ok_no_locks();
1712 todo_wine {
1713 ok_zero_external_conn();
1714 ok_last_release_closes(FALSE);
1715 }
1716
1717 CloseHandle(thread);
1718 CloseHandle(ncu_params.marshal_event);
1719 CloseHandle(ncu_params.unmarshal_event);
1720
1721 IUnknown_Release(pProxy);
1722
1723 ok_no_locks();
1724 }
1725
1726 /* STA -> STA call during DLL_THREAD_DETACH */
1727 static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p)
1728 {
1729 struct ncu_params *ncu_params = p;
1730 HRESULT hr;
1731 IUnknown *pProxy = NULL;
1732
1733 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1734
1735 hr = CoUnmarshalInterface(ncu_params->stream, &IID_IClassFactory, (void **)&pProxy);
1736 ok_ole_success(hr, CoUnmarshalInterface);
1737 IStream_Release(ncu_params->stream);
1738
1739 ok_more_than_one_lock();
1740
1741 /* die without calling CoUninitialize */
1742
1743 return 0;
1744 }
1745
1746 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
1747 static void test_no_couninitialize_client(void)
1748 {
1749 HRESULT hr;
1750 IStream *pStream = NULL;
1751 DWORD tid;
1752 DWORD host_tid;
1753 HANDLE thread;
1754 HANDLE host_thread;
1755 struct ncu_params ncu_params;
1756
1757 cLocks = 0;
1758 external_connections = 0;
1759
1760 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1761 ok_ole_success(hr, CreateStreamOnHGlobal);
1762 ncu_params.stream = pStream;
1763
1764 /* NOTE: assumes start_host_object uses an STA to host the object, as MTAs
1765 * always deadlock when called from within DllMain */
1766 host_tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
1767 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1768
1769 ok_more_than_one_lock();
1770 ok_non_zero_external_conn();
1771
1772 thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
1773
1774 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1775 CloseHandle(thread);
1776
1777 ok_no_locks();
1778 ok_zero_external_conn();
1779 ok_last_release_closes(TRUE);
1780
1781 end_host_object(host_tid, host_thread);
1782 }
1783
1784 static BOOL crash_thread_success;
1785
1786 static DWORD CALLBACK crash_couninitialize_proc(void *p)
1787 {
1788 IStream *stream;
1789 HRESULT hr;
1790
1791 cLocks = 0;
1792
1793 CoInitialize(NULL);
1794
1795 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1796 ok_ole_success(hr, CreateStreamOnHGlobal);
1797
1798 hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1799 ok_ole_success(hr, CoMarshalInterface);
1800
1801 IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1802
1803 hr = CoReleaseMarshalData(stream);
1804 ok_ole_success(hr, CoReleaseMarshalData);
1805
1806 ok_no_locks();
1807
1808 hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1809 ok_ole_success(hr, CoMarshalInterface);
1810
1811 ok_more_than_one_lock();
1812
1813 trace("CoUninitialize >>>\n");
1814 CoUninitialize();
1815 trace("CoUninitialize <<<\n");
1816
1817 ok_no_locks();
1818
1819 IStream_Release(stream);
1820 crash_thread_success = TRUE;
1821 return 0;
1822 }
1823
1824 static void test_crash_couninitialize(void)
1825 {
1826 HANDLE thread;
1827 DWORD tid;
1828
1829 if(!GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateActCtxW")) {
1830 win_skip("Skipping crash tests on win2k.\n");
1831 return;
1832 }
1833
1834 crash_thread_success = FALSE;
1835 thread = CreateThread(NULL, 0, crash_couninitialize_proc, NULL, 0, &tid);
1836 ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1837 CloseHandle(thread);
1838 ok(crash_thread_success, "Crash thread failed\n");
1839 }
1840
1841 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
1842 static void test_tableweak_marshal_and_unmarshal_twice(void)
1843 {
1844 HRESULT hr;
1845 IStream *pStream = NULL;
1846 IUnknown *pProxy1 = NULL;
1847 IUnknown *pProxy2 = NULL;
1848 DWORD tid;
1849 HANDLE thread;
1850
1851 cLocks = 0;
1852 external_connections = 0;
1853
1854 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1855 ok_ole_success(hr, CreateStreamOnHGlobal);
1856 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1857
1858 ok_more_than_one_lock();
1859 ok_zero_external_conn();
1860
1861 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1862 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1863 ok_ole_success(hr, CoUnmarshalInterface);
1864
1865 ok_more_than_one_lock();
1866 ok_non_zero_external_conn();
1867
1868 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1869 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1870 ok_ole_success(hr, CoUnmarshalInterface);
1871
1872 ok_more_than_one_lock();
1873
1874 IUnknown_Release(pProxy1);
1875 ok_non_zero_external_conn();
1876 IUnknown_Release(pProxy2);
1877 ok_zero_external_conn();
1878 ok_last_release_closes(TRUE);
1879
1880 /* When IExternalConnection is present COM's lifetime management
1881 * behaviour is altered; the remaining weak ref prevents stub shutdown. */
1882 if (with_external_conn)
1883 {
1884 ok_more_than_one_lock();
1885 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1886 release_host_object(tid, 0);
1887 }
1888
1889 /* Without IExternalConnection this line is shows the difference between weak and strong table marshaling
1890 * weak has cLocks == 0, strong has cLocks > 0. */
1891 ok_no_locks();
1892
1893 IStream_Release(pStream);
1894 end_host_object(tid, thread);
1895 }
1896
1897 /* tests releasing after unmarshaling one object */
1898 static void test_tableweak_marshal_releasedata1(void)
1899 {
1900 HRESULT hr;
1901 IStream *pStream = NULL;
1902 IUnknown *pProxy1 = NULL;
1903 IUnknown *pProxy2 = NULL;
1904 DWORD tid;
1905 HANDLE thread;
1906
1907 cLocks = 0;
1908 external_connections = 0;
1909
1910 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1911 ok_ole_success(hr, CreateStreamOnHGlobal);
1912 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1913
1914 ok_more_than_one_lock();
1915 ok_zero_external_conn();
1916
1917 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1918 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1919 ok_ole_success(hr, CoUnmarshalInterface);
1920
1921 ok_more_than_one_lock();
1922 ok_non_zero_external_conn();
1923
1924 /* release the remaining reference on the object by calling
1925 * CoReleaseMarshalData in the hosting thread */
1926 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1927 release_host_object(tid, 0);
1928
1929 ok_more_than_one_lock();
1930 ok_non_zero_external_conn();
1931
1932 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1933 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1934 ok_ole_success(hr, CoUnmarshalInterface);
1935 IStream_Release(pStream);
1936
1937 ok_more_than_one_lock();
1938 ok_non_zero_external_conn();
1939
1940 IUnknown_Release(pProxy1);
1941
1942 if (pProxy2)
1943 {
1944 ok_non_zero_external_conn();
1945 IUnknown_Release(pProxy2);
1946 }
1947
1948 /* this line is shows the difference between weak and strong table marshaling:
1949 * weak has cLocks == 0
1950 * strong has cLocks > 0 */
1951 ok_no_locks();
1952 ok_zero_external_conn();
1953 ok_last_release_closes(TRUE);
1954
1955 end_host_object(tid, thread);
1956 }
1957
1958 /* tests releasing after unmarshaling one object */
1959 static void test_tableweak_marshal_releasedata2(void)
1960 {
1961 HRESULT hr;
1962 IStream *pStream = NULL;
1963 IUnknown *pProxy = NULL;
1964 DWORD tid;
1965 HANDLE thread;
1966
1967 cLocks = 0;
1968 external_connections = 0;
1969
1970 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1971 ok_ole_success(hr, CreateStreamOnHGlobal);
1972 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1973
1974 ok_more_than_one_lock();
1975 ok_zero_external_conn();
1976
1977 /* release the remaining reference on the object by calling
1978 * CoReleaseMarshalData in the hosting thread */
1979 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1980 release_host_object(tid, 0);
1981
1982 ok_no_locks();
1983
1984 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1985 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1986 todo_wine
1987 {
1988 ok(hr == CO_E_OBJNOTREG,
1989 "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08x instead\n",
1990 hr);
1991 }
1992 IStream_Release(pStream);
1993
1994 ok_no_locks();
1995 ok_zero_external_conn();
1996
1997 end_host_object(tid, thread);
1998 }
1999
2000 struct duo_marshal_data
2001 {
2002 MSHLFLAGS marshal_flags1, marshal_flags2;
2003 IStream *pStream1, *pStream2;
2004 HANDLE hReadyEvent;
2005 HANDLE hQuitEvent;
2006 };
2007
2008 static DWORD CALLBACK duo_marshal_thread_proc(void *p)
2009 {
2010 HRESULT hr;
2011 struct duo_marshal_data *data = p;
2012 HANDLE hQuitEvent = data->hQuitEvent;
2013 MSG msg;
2014
2015 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2016
2017 hr = CoMarshalInterface(data->pStream1, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags1);
2018 ok_ole_success(hr, "CoMarshalInterface");
2019
2020 hr = CoMarshalInterface(data->pStream2, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags2);
2021 ok_ole_success(hr, "CoMarshalInterface");
2022
2023 /* force the message queue to be created before signaling parent thread */
2024 PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
2025
2026 SetEvent(data->hReadyEvent);
2027
2028 while (WAIT_OBJECT_0 + 1 == MsgWaitForMultipleObjects(1, &hQuitEvent, FALSE, 10000, QS_ALLINPUT))
2029 {
2030 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
2031 {
2032 if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
2033 {
2034 CoReleaseMarshalData(msg.wParam == 1 ? data->pStream1 : data->pStream2);
2035 SetEvent((HANDLE)msg.lParam);
2036 }
2037 else
2038 DispatchMessageA(&msg);
2039 }
2040 }
2041 CloseHandle(hQuitEvent);
2042
2043 CoUninitialize();
2044
2045 return 0;
2046 }
2047
2048 /* tests interaction between table-weak and normal marshalling of an object */
2049 static void test_tableweak_and_normal_marshal_and_unmarshal(void)
2050 {
2051 HRESULT hr;
2052 IUnknown *pProxyWeak = NULL;
2053 IUnknown *pProxyNormal = NULL;
2054 DWORD tid;
2055 HANDLE thread;
2056 struct duo_marshal_data data;
2057
2058 cLocks = 0;
2059 external_connections = 0;
2060
2061 data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2062 data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2063 data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2064 data.marshal_flags2 = MSHLFLAGS_NORMAL;
2065 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2066 ok_ole_success(hr, CreateStreamOnHGlobal);
2067 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2068 ok_ole_success(hr, CreateStreamOnHGlobal);
2069
2070 thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2071 ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2072 CloseHandle(data.hReadyEvent);
2073
2074 ok_more_than_one_lock();
2075 ok_non_zero_external_conn();
2076
2077 /* weak */
2078 IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2079 hr = CoUnmarshalInterface(data.pStream1, &IID_IClassFactory, (void **)&pProxyWeak);
2080 ok_ole_success(hr, CoUnmarshalInterface);
2081
2082 ok_more_than_one_lock();
2083
2084 /* normal */
2085 IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2086 hr = CoUnmarshalInterface(data.pStream2, &IID_IClassFactory, (void **)&pProxyNormal);
2087 ok_ole_success(hr, CoUnmarshalInterface);
2088
2089 ok_more_than_one_lock();
2090
2091 IUnknown_Release(pProxyNormal);
2092
2093 ok_more_than_one_lock();
2094 ok_non_zero_external_conn();
2095
2096 IUnknown_Release(pProxyWeak);
2097
2098 ok_zero_external_conn();
2099 ok_last_release_closes(TRUE);
2100
2101 /* When IExternalConnection is present COM's lifetime management
2102 * behaviour is altered; the remaining weak ref prevents stub shutdown. */
2103 if (with_external_conn)
2104 {
2105 ok_more_than_one_lock();
2106 IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2107 release_host_object(tid, 1);
2108 }
2109 ok_no_locks();
2110
2111 IStream_Release(data.pStream1);
2112 IStream_Release(data.pStream2);
2113
2114 SetEvent(data.hQuitEvent);
2115 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2116 CloseHandle(thread);
2117 }
2118
2119 static void test_tableweak_and_normal_marshal_and_releasedata(void)
2120 {
2121 HRESULT hr;
2122 DWORD tid;
2123 HANDLE thread;
2124 struct duo_marshal_data data;
2125
2126 cLocks = 0;
2127 external_connections = 0;
2128
2129 data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2130 data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2131 data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2132 data.marshal_flags2 = MSHLFLAGS_NORMAL;
2133 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2134 ok_ole_success(hr, CreateStreamOnHGlobal);
2135 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2136 ok_ole_success(hr, CreateStreamOnHGlobal);
2137
2138 thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2139 ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2140 CloseHandle(data.hReadyEvent);
2141
2142 ok_more_than_one_lock();
2143 ok_non_zero_external_conn();
2144
2145 /* release normal - which in the non-external conn case will free the object despite the weak ref. */
2146 IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2147 release_host_object(tid, 2);
2148
2149 ok_zero_external_conn();
2150 ok_last_release_closes(TRUE);
2151
2152 if (with_external_conn)
2153 {
2154 ok_more_than_one_lock();
2155 IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2156 release_host_object(tid, 1);
2157 }
2158
2159 ok_no_locks();
2160
2161 IStream_Release(data.pStream1);
2162 IStream_Release(data.pStream2);
2163
2164 SetEvent(data.hQuitEvent);
2165 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2166 CloseHandle(thread);
2167 }
2168
2169 static void test_two_tableweak_marshal_and_releasedata(void)
2170 {
2171 HRESULT hr;
2172 DWORD tid;
2173 HANDLE thread;
2174 struct duo_marshal_data data;
2175
2176 cLocks = 0;
2177 external_connections = 0;
2178
2179 data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2180 data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2181 data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
2182 data.marshal_flags2 = MSHLFLAGS_TABLEWEAK;
2183 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
2184 ok_ole_success(hr, CreateStreamOnHGlobal);
2185 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
2186 ok_ole_success(hr, CreateStreamOnHGlobal);
2187
2188 thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
2189 ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
2190 CloseHandle(data.hReadyEvent);
2191
2192 ok_more_than_one_lock();
2193 ok_zero_external_conn();
2194
2195 /* release one weak ref - the remaining weak ref will keep the obj alive */
2196 IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
2197 release_host_object(tid, 1);
2198
2199 ok_more_than_one_lock();
2200
2201 IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
2202 release_host_object(tid, 2);
2203
2204 ok_no_locks();
2205
2206 IStream_Release(data.pStream1);
2207 IStream_Release(data.pStream2);
2208
2209 SetEvent(data.hQuitEvent);
2210 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2211 CloseHandle(thread);
2212 }
2213
2214 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
2215 static void test_tablestrong_marshal_and_unmarshal_twice(void)
2216 {
2217 HRESULT hr;
2218 IStream *pStream = NULL;
2219 IUnknown *pProxy1 = NULL;
2220 IUnknown *pProxy2 = NULL;
2221 DWORD tid;
2222 HANDLE thread;
2223
2224 cLocks = 0;
2225 external_connections = 0;
2226
2227 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2228 ok_ole_success(hr, CreateStreamOnHGlobal);
2229 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
2230
2231 ok_more_than_one_lock();
2232 ok_non_zero_external_conn();
2233
2234 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2235 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2236 ok_ole_success(hr, CoUnmarshalInterface);
2237
2238 ok_more_than_one_lock();
2239
2240 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2241 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
2242 ok_ole_success(hr, CoUnmarshalInterface);
2243
2244 ok_more_than_one_lock();
2245
2246 if (pProxy1) IUnknown_Release(pProxy1);
2247 if (pProxy2) IUnknown_Release(pProxy2);
2248
2249 /* this line is shows the difference between weak and strong table marshaling:
2250 * weak has cLocks == 0
2251 * strong has cLocks > 0 */
2252 ok_more_than_one_lock();
2253
2254 /* release the remaining reference on the object by calling
2255 * CoReleaseMarshalData in the hosting thread */
2256 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2257 release_host_object(tid, 0);
2258 IStream_Release(pStream);
2259
2260 ok_no_locks();
2261 ok_zero_external_conn();
2262 ok_last_release_closes(TRUE);
2263
2264 end_host_object(tid, thread);
2265 }
2266
2267 /* tests CoLockObjectExternal */
2268 static void test_lock_object_external(void)
2269 {
2270 HRESULT hr;
2271 IStream *pStream = NULL;
2272
2273 cLocks = 0;
2274 external_connections = 0;
2275
2276 /* test the stub manager creation aspect of CoLockObjectExternal when the
2277 * object hasn't been marshaled yet */
2278 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2279
2280 ok_more_than_one_lock();
2281 ok_non_zero_external_conn();
2282
2283 CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2284
2285 ok_no_locks();
2286 ok_non_zero_external_conn();
2287 external_connections = 0;
2288
2289 /* test our empty stub manager being handled correctly in
2290 * CoMarshalInterface */
2291 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2292
2293 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2294 ok_ole_success(hr, CreateStreamOnHGlobal);
2295 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2296 ok_ole_success(hr, CoMarshalInterface);
2297
2298 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2299
2300 ok_more_than_one_lock();
2301 ok_non_zero_external_conn();
2302
2303 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2304 hr = CoReleaseMarshalData(pStream);
2305 ok_ole_success(hr, CoReleaseMarshalData);
2306 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2307
2308 ok_more_than_one_lock();
2309 ok_non_zero_external_conn();
2310 ok_last_release_closes(TRUE);
2311
2312 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
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_no_locks();
2321 ok_zero_external_conn();
2322 ok_last_release_closes(TRUE);
2323
2324 /* test CoLockObjectExternal releases reference to object with
2325 * fLastUnlockReleases as TRUE and there are only strong references on
2326 * the object */
2327 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
2328
2329 ok_more_than_one_lock();
2330 ok_non_zero_external_conn();
2331
2332 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
2333
2334 ok_no_locks();
2335 ok_zero_external_conn();
2336 ok_last_release_closes(FALSE);
2337
2338 /* test CoLockObjectExternal doesn't release the last reference to an
2339 * object with fLastUnlockReleases as TRUE and there is a weak reference
2340 * on the object */
2341 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
2342 ok_ole_success(hr, CoMarshalInterface);
2343
2344 ok_more_than_one_lock();
2345 ok_zero_external_conn();
2346
2347 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
2348
2349 ok_more_than_one_lock();
2350 ok_non_zero_external_conn();
2351
2352 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
2353
2354 ok_more_than_one_lock();
2355 ok_zero_external_conn();
2356 ok_last_release_closes(FALSE);
2357
2358 CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2359
2360 ok_no_locks();
2361
2362 IStream_Release(pStream);
2363 }
2364
2365 /* tests disconnecting stubs */
2366 static void test_disconnect_stub(void)
2367 {
2368 HRESULT hr;
2369 IStream *pStream = NULL;
2370
2371 cLocks = 0;
2372 external_connections = 0;
2373
2374 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2375 ok_ole_success(hr, CreateStreamOnHGlobal);
2376 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2377 ok_ole_success(hr, CoMarshalInterface);
2378
2379 ok_non_zero_external_conn();
2380
2381 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2382
2383 ok_more_than_one_lock();
2384 ok_non_zero_external_conn();
2385
2386 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2387 hr = CoReleaseMarshalData(pStream);
2388 ok_ole_success(hr, CoReleaseMarshalData);
2389 IStream_Release(pStream);
2390
2391 ok_more_than_one_lock();
2392 ok_non_zero_external_conn();
2393
2394 CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2395
2396 ok_no_locks();
2397 ok_non_zero_external_conn();
2398
2399 hr = CoDisconnectObject(NULL, 0);
2400 ok( hr == E_INVALIDARG, "wrong status %x\n", hr );
2401 }
2402
2403 /* tests failure case of a same-thread marshal and unmarshal twice */
2404 static void test_normal_marshal_and_unmarshal_twice(void)
2405 {
2406 HRESULT hr;
2407 IStream *pStream = NULL;
2408 IUnknown *pProxy1 = NULL;
2409 IUnknown *pProxy2 = NULL;
2410
2411 cLocks = 0;
2412 external_connections = 0;
2413
2414 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2415 ok_ole_success(hr, CreateStreamOnHGlobal);
2416 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2417 ok_ole_success(hr, CoMarshalInterface);
2418
2419 ok_more_than_one_lock();
2420 ok_non_zero_external_conn();
2421
2422 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2423 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2424 ok_ole_success(hr, CoUnmarshalInterface);
2425
2426 ok_more_than_one_lock();
2427 ok_zero_external_conn();
2428 ok_last_release_closes(FALSE);
2429
2430 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2431 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
2432 ok(hr == CO_E_OBJNOTCONNECTED,
2433 "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08x\n", hr);
2434
2435 IStream_Release(pStream);
2436
2437 ok_more_than_one_lock();
2438
2439 IUnknown_Release(pProxy1);
2440
2441 ok_no_locks();
2442 }
2443
2444 /* tests success case of marshaling and unmarshaling an HRESULT */
2445 static void test_hresult_marshaling(void)
2446 {
2447 HRESULT hr;
2448 HRESULT hr_marshaled = 0;
2449 IStream *pStream = NULL;
2450 static const HRESULT E_DEADBEEF = 0xdeadbeef;
2451
2452 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2453 ok_ole_success(hr, CreateStreamOnHGlobal);
2454
2455 hr = CoMarshalHresult(pStream, E_DEADBEEF);
2456 ok_ole_success(hr, CoMarshalHresult);
2457
2458 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2459 hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
2460 ok_ole_success(hr, IStream_Read);
2461
2462 ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
2463
2464 hr_marshaled = 0;
2465 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2466 hr = CoUnmarshalHresult(pStream, &hr_marshaled);
2467 ok_ole_success(hr, CoUnmarshalHresult);
2468
2469 ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
2470
2471 IStream_Release(pStream);
2472 }
2473
2474
2475 /* helper for test_proxy_used_in_wrong_thread */
2476 static DWORD CALLBACK bad_thread_proc(LPVOID p)
2477 {
2478 IClassFactory * cf = p;
2479 HRESULT hr;
2480 IUnknown * proxy = NULL;
2481
2482 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2483 todo_wine
2484 ok(hr == CO_E_NOTINITIALIZED,
2485 "COM should have failed with CO_E_NOTINITIALIZED on using proxy without apartment, but instead returned 0x%08x\n",
2486 hr);
2487
2488 hr = IClassFactory_QueryInterface(cf, &IID_IMultiQI, (LPVOID *)&proxy);
2489 /* Win9x returns S_OK, whilst NT returns RPC_E_WRONG_THREAD */
2490 trace("call to proxy's QueryInterface for local interface without apartment returned 0x%08x\n", hr);
2491 if (SUCCEEDED(hr))
2492 IUnknown_Release(proxy);
2493
2494 hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
2495 /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
2496 trace("call to proxy's QueryInterface without apartment returned 0x%08x\n", hr);
2497 if (SUCCEEDED(hr))
2498 IUnknown_Release(proxy);
2499
2500 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
2501
2502 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2503 if (proxy) IUnknown_Release(proxy);
2504 ok(hr == RPC_E_WRONG_THREAD,
2505 "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08x\n",
2506 hr);
2507
2508 hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
2509 /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
2510 trace("call to proxy's QueryInterface from wrong apartment returned 0x%08x\n", hr);
2511
2512 /* now be really bad and release the proxy from the wrong apartment */
2513 IClassFactory_Release(cf);
2514
2515 CoUninitialize();
2516
2517 return 0;
2518 }
2519
2520 /* tests failure case of a using a proxy in the wrong apartment */
2521 static void test_proxy_used_in_wrong_thread(void)
2522 {
2523 HRESULT hr;
2524 IStream *pStream = NULL;
2525 IUnknown *pProxy = NULL;
2526 DWORD tid, tid2;
2527 HANDLE thread;
2528 HANDLE host_thread;
2529
2530 cLocks = 0;
2531
2532 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2533 ok_ole_success(hr, CreateStreamOnHGlobal);
2534 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
2535
2536 ok_more_than_one_lock();
2537
2538 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2539 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
2540 ok_ole_success(hr, CoUnmarshalInterface);
2541 IStream_Release(pStream);
2542
2543 ok_more_than_one_lock();
2544
2545 /* do a call that will fail, but result in IRemUnknown being used by the proxy */
2546 IUnknown_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream);
2547
2548 /* create a thread that we can misbehave in */
2549 thread = CreateThread(NULL, 0, bad_thread_proc, pProxy, 0, &tid2);
2550
2551 ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2552 CloseHandle(thread);
2553
2554 /* do release statement on Win9x that we should have done above */
2555 if (!GetProcAddress(GetModuleHandleA("ole32"), "CoRegisterSurrogateEx"))
2556 IUnknown_Release(pProxy);
2557
2558 ok_no_locks();
2559
2560 end_host_object(tid, host_thread);
2561 }
2562
2563 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
2564 {
2565 if (ppvObj == NULL) return E_POINTER;
2566
2567 if (IsEqualGUID(riid, &IID_IUnknown) ||
2568 IsEqualGUID(riid, &IID_IClassFactory))
2569 {
2570 *ppvObj = iface;
2571 IMessageFilter_AddRef(iface);
2572 return S_OK;
2573 }
2574
2575 return E_NOINTERFACE;
2576 }
2577
2578 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
2579 {
2580 return 2; /* non-heap object */
2581 }
2582
2583 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
2584 {
2585 return 1; /* non-heap object */
2586 }
2587
2588 static DWORD WINAPI MessageFilter_HandleInComingCall(
2589 IMessageFilter *iface,
2590 DWORD dwCallType,
2591 HTASK threadIDCaller,
2592 DWORD dwTickCount,
2593 LPINTERFACEINFO lpInterfaceInfo)
2594 {
2595 static int callcount = 0;
2596 DWORD ret;
2597 trace("HandleInComingCall\n");
2598 switch (callcount)
2599 {
2600 case 0:
2601 ret = SERVERCALL_REJECTED;
2602 break;
2603 case 1:
2604 ret = SERVERCALL_RETRYLATER;
2605 break;
2606 default:
2607 ret = SERVERCALL_ISHANDLED;
2608 break;
2609 }
2610 callcount++;
2611 return ret;
2612 }
2613
2614 static DWORD WINAPI MessageFilter_RetryRejectedCall(
2615 IMessageFilter *iface,
2616 HTASK threadIDCallee,
2617 DWORD dwTickCount,
2618 DWORD dwRejectType)
2619 {
2620 trace("RetryRejectedCall\n");
2621 return 0;
2622 }
2623
2624 static DWORD WINAPI MessageFilter_MessagePending(
2625 IMessageFilter *iface,
2626 HTASK threadIDCallee,
2627 DWORD dwTickCount,
2628 DWORD dwPendingType)
2629 {
2630 trace("MessagePending\n");
2631 return PENDINGMSG_WAITNOPROCESS;
2632 }
2633
2634 static const IMessageFilterVtbl MessageFilter_Vtbl =
2635 {
2636 MessageFilter_QueryInterface,
2637 MessageFilter_AddRef,
2638 MessageFilter_Release,
2639 MessageFilter_HandleInComingCall,
2640 MessageFilter_RetryRejectedCall,
2641 MessageFilter_MessagePending
2642 };
2643
2644 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
2645
2646 static void test_message_filter(void)
2647 {
2648 HRESULT hr;
2649 IClassFactory *cf = NULL;
2650 DWORD tid;
2651 IUnknown *proxy = NULL;
2652 IMessageFilter *prev_filter = NULL;
2653 HANDLE thread;
2654
2655 struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
2656 MSHLFLAGS_NORMAL, &MessageFilter };
2657
2658 cLocks = 0;
2659
2660 hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
2661 ok_ole_success(hr, CreateStreamOnHGlobal);
2662 tid = start_host_object2(&object_data, &thread);
2663
2664 ok_more_than_one_lock();
2665
2666 IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
2667 hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
2668 ok_ole_success(hr, CoUnmarshalInterface);
2669 IStream_Release(object_data.stream);
2670
2671 ok_more_than_one_lock();
2672
2673 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2674 ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08x instead\n", hr);
2675 if (proxy) IUnknown_Release(proxy);
2676 proxy = NULL;
2677
2678 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
2679 ok_ole_success(hr, CoRegisterMessageFilter);
2680
2681 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2682 ok_ole_success(hr, IClassFactory_CreateInstance);
2683
2684 IUnknown_Release(proxy);
2685
2686 IClassFactory_Release(cf);
2687
2688 ok_no_locks();
2689
2690 end_host_object(tid, thread);
2691
2692 hr = CoRegisterMessageFilter(prev_filter, NULL);
2693 ok_ole_success(hr, CoRegisterMessageFilter);
2694 }
2695
2696 /* test failure case of trying to unmarshal from bad stream */
2697 static void test_bad_marshal_stream(void)
2698 {
2699 HRESULT hr;
2700 IStream *pStream = NULL;
2701
2702 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2703 ok_ole_success(hr, CreateStreamOnHGlobal);
2704 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2705 ok_ole_success(hr, CoMarshalInterface);
2706
2707 ok_more_than_one_lock();
2708
2709 /* try to read beyond end of stream */
2710 hr = CoReleaseMarshalData(pStream);
2711 ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08x instead\n", hr);
2712
2713 /* now release for real */
2714 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2715 hr = CoReleaseMarshalData(pStream);
2716 ok_ole_success(hr, CoReleaseMarshalData);
2717
2718 IStream_Release(pStream);
2719 }
2720
2721 /* tests that proxies implement certain interfaces */
2722 static void test_proxy_interfaces(void)
2723 {
2724 HRESULT hr;
2725 IStream *pStream = NULL;
2726 IUnknown *pProxy = NULL;
2727 IUnknown *pOtherUnknown = NULL;
2728 DWORD tid;
2729 HANDLE thread;
2730
2731 cLocks = 0;
2732
2733 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2734 ok_ole_success(hr, CreateStreamOnHGlobal);
2735 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2736
2737 ok_more_than_one_lock();
2738
2739 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2740 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
2741 ok_ole_success(hr, CoUnmarshalInterface);
2742 IStream_Release(pStream);
2743
2744 ok_more_than_one_lock();
2745
2746 hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
2747 ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
2748 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2749
2750 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
2751 ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity);
2752 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2753
2754 hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
2755 ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
2756 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2757
2758 hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
2759 ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal);
2760 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2761
2762 /* IMarshal2 is also supported on NT-based systems, but is pretty much
2763 * useless as it has no more methods over IMarshal that it inherits from. */
2764
2765 IUnknown_Release(pProxy);
2766
2767 ok_no_locks();
2768
2769 end_host_object(tid, thread);
2770 }
2771
2772 typedef struct
2773 {
2774 IUnknown IUnknown_iface;
2775 ULONG refs;
2776 } HeapUnknown;
2777
2778 static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
2779 {
2780 return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
2781 }
2782
2783 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2784 {
2785 if (IsEqualIID(riid, &IID_IUnknown))
2786 {
2787 IUnknown_AddRef(iface);
2788 *ppv = iface;
2789 return S_OK;
2790 }
2791 *ppv = NULL;
2792 return E_NOINTERFACE;
2793 }
2794
2795 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
2796 {
2797 HeapUnknown *This = impl_from_IUnknown(iface);
2798 return InterlockedIncrement((LONG*)&This->refs);
2799 }
2800
2801 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
2802 {
2803 HeapUnknown *This = impl_from_IUnknown(iface);
2804 ULONG refs = InterlockedDecrement((LONG*)&This->refs);
2805 if (!refs) HeapFree(GetProcessHeap(), 0, This);
2806 return refs;
2807 }
2808
2809 static const IUnknownVtbl HeapUnknown_Vtbl =
2810 {
2811 HeapUnknown_QueryInterface,
2812 HeapUnknown_AddRef,
2813 HeapUnknown_Release
2814 };
2815
2816 static void test_proxybuffer(REFIID riid)
2817 {
2818 HRESULT hr;
2819 IPSFactoryBuffer *psfb;
2820 IRpcProxyBuffer *proxy;
2821 LPVOID lpvtbl;
2822 ULONG refs;
2823 CLSID clsid;
2824 HeapUnknown *pUnkOuter = HeapAlloc(GetProcessHeap(), 0, sizeof(*pUnkOuter));
2825
2826 pUnkOuter->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
2827 pUnkOuter->refs = 1;
2828
2829 hr = CoGetPSClsid(riid, &clsid);
2830 ok_ole_success(hr, CoGetPSClsid);
2831
2832 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
2833 ok_ole_success(hr, CoGetClassObject);
2834
2835 hr = IPSFactoryBuffer_CreateProxy(psfb, &pUnkOuter->IUnknown_iface, riid, &proxy, &lpvtbl);
2836 ok_ole_success(hr, IPSFactoryBuffer_CreateProxy);
2837 ok(lpvtbl != NULL, "IPSFactoryBuffer_CreateProxy succeeded, but returned a NULL vtable!\n");
2838
2839 /* release our reference to the outer unknown object - the PS factory
2840 * buffer will have AddRef's it in the CreateProxy call */
2841 refs = IUnknown_Release(&pUnkOuter->IUnknown_iface);
2842 ok(refs == 1, "Ref count of outer unknown should have been 1 instead of %d\n", refs);
2843
2844 /* Not checking return, unreliable on native. Maybe it leaks references? */
2845 IPSFactoryBuffer_Release(psfb);
2846
2847 refs = IUnknown_Release((IUnknown *)lpvtbl);
2848 ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2849
2850 refs = IRpcProxyBuffer_Release(proxy);
2851 ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2852 }
2853
2854 static void test_stubbuffer(REFIID riid)
2855 {
2856 HRESULT hr;
2857 IPSFactoryBuffer *psfb;
2858 IRpcStubBuffer *stub;
2859 ULONG refs;
2860 CLSID clsid;
2861
2862 cLocks = 0;
2863
2864 hr = CoGetPSClsid(riid, &clsid);
2865 ok_ole_success(hr, CoGetPSClsid);
2866
2867 hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
2868 ok_ole_success(hr, CoGetClassObject);
2869
2870 hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
2871 ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
2872
2873 /* Not checking return, unreliable on native. Maybe it leaks references? */
2874 IPSFactoryBuffer_Release(psfb);
2875
2876 ok_more_than_one_lock();
2877
2878 IRpcStubBuffer_Disconnect(stub);
2879
2880 ok_no_locks();
2881
2882 refs = IRpcStubBuffer_Release(stub);
2883 ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2884 }
2885
2886 static HWND hwnd_app;
2887
2888 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
2889 LPCLASSFACTORY iface,
2890 LPUNKNOWN pUnkOuter,
2891 REFIID riid,
2892 LPVOID *ppvObj)
2893 {
2894 DWORD_PTR res;
2895 if (IsEqualIID(riid, &IID_IWineTest))
2896 {
2897 BOOL ret = SendMessageTimeoutA(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
2898 ok(ret, "Timed out sending a message to originating window during RPC call\n");
2899 }
2900 *ppvObj = NULL;
2901 return S_FALSE;
2902 }
2903
2904 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
2905 {
2906 Test_IClassFactory_QueryInterface,
2907 Test_IClassFactory_AddRef,
2908 Test_IClassFactory_Release,
2909 TestRE_IClassFactory_CreateInstance,
2910 Test_IClassFactory_LockServer
2911 };
2912
2913 static IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
2914
2915 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
2916 {
2917 switch (msg)
2918 {
2919 case WM_USER:
2920 {
2921 HRESULT hr;
2922 IStream *pStream = NULL;
2923 IClassFactory *proxy = NULL;
2924 IUnknown *object;
2925 DWORD tid;
2926 HANDLE thread;
2927
2928 cLocks = 0;
2929
2930 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2931 ok_ole_success(hr, CreateStreamOnHGlobal);
2932 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2933
2934 ok_more_than_one_lock();
2935
2936 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2937 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2938 ok_ole_success(hr, CoReleaseMarshalData);
2939 IStream_Release(pStream);
2940
2941 ok_more_than_one_lock();
2942
2943 /* note the use of the magic IID_IWineTest value to tell remote thread
2944 * to try to send a message back to us */
2945 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IWineTest, (void **)&object);
2946 ok(hr == S_FALSE, "expected S_FALSE, got %d\n", hr);
2947
2948 IClassFactory_Release(proxy);
2949
2950 ok_no_locks();
2951
2952 end_host_object(tid, thread);
2953
2954 PostMessageA(hwnd, WM_QUIT, 0, 0);
2955
2956 return 0;
2957 }
2958 case WM_USER+1:
2959 {
2960 HRESULT hr;
2961 IStream *pStream = NULL;
2962 IClassFactory *proxy = NULL;
2963 IUnknown *object;
2964 DWORD tid;
2965 HANDLE thread;
2966
2967 cLocks = 0;
2968
2969 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2970 ok_ole_success(hr, CreateStreamOnHGlobal);
2971 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2972
2973 ok_more_than_one_lock();
2974
2975 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2976 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2977 ok_ole_success(hr, CoReleaseMarshalData);
2978 IStream_Release(pStream);
2979
2980 ok_more_than_one_lock();
2981
2982 /* post quit message before a doing a COM call to show that a pending
2983 * WM_QUIT message doesn't stop the call from succeeding */
2984 PostMessageA(hwnd, WM_QUIT, 0, 0);
2985 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
2986 ok(hr == S_FALSE, "IClassFactory_CreateInstance returned 0x%08x, expected S_FALSE\n", hr);
2987
2988 IClassFactory_Release(proxy);
2989
2990 ok_no_locks();
2991
2992 end_host_object(tid, thread);
2993
2994 return 0;
2995 }
2996 case WM_USER+2:
2997 {
2998 HRESULT hr;
2999 IStream *pStream = NULL;
3000 IClassFactory *proxy = NULL;
3001 IUnknown *object;
3002 DWORD tid;
3003 HANDLE thread;
3004
3005 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3006 ok_ole_success(hr, CreateStreamOnHGlobal);
3007 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3008
3009 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3010 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
3011 ok_ole_success(hr, CoReleaseMarshalData);
3012 IStream_Release(pStream);
3013
3014 /* shows that COM calls executed during the processing of sent
3015 * messages should fail */
3016 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
3017 ok(hr == RPC_E_CANTCALLOUT_ININPUTSYNCCALL,
3018 "COM call during processing of sent message should return RPC_E_CANTCALLOUT_ININPUTSYNCCALL instead of 0x%08x\n", hr);
3019
3020 IClassFactory_Release(proxy);
3021
3022 end_host_object(tid, thread);
3023
3024 PostQuitMessage(0);
3025
3026 return 0;
3027 }
3028 default:
3029 return DefWindowProcA(hwnd, msg, wparam, lparam);
3030 }
3031 }
3032
3033 static void register_test_window(void)
3034 {
3035 WNDCLASSA wndclass;
3036
3037 memset(&wndclass, 0, sizeof(wndclass));
3038 wndclass.lpfnWndProc = window_proc;
3039 wndclass.lpszClassName = "WineCOMTest";
3040 RegisterClassA(&wndclass);
3041 }
3042
3043 static void test_message_reentrancy(void)
3044 {
3045 MSG msg;
3046
3047 hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3048 ok(hwnd_app != NULL, "Window creation failed\n");
3049
3050 /* start message re-entrancy test */
3051 PostMessageA(hwnd_app, WM_USER, 0, 0);
3052
3053 while (GetMessageA(&msg, NULL, 0, 0))
3054 {
3055 TranslateMessage(&msg);
3056 DispatchMessageA(&msg);
3057 }
3058 DestroyWindow(hwnd_app);
3059 }
3060
3061 static HRESULT WINAPI TestMsg_IClassFactory_CreateInstance(
3062 LPCLASSFACTORY iface,
3063 LPUNKNOWN pUnkOuter,
3064 REFIID riid,
3065 LPVOID *ppvObj)
3066 {
3067 *ppvObj = NULL;
3068 SendMessageA(hwnd_app, WM_USER+2, 0, 0);
3069 return S_OK;
3070 }
3071
3072 static IClassFactoryVtbl TestMsgClassFactory_Vtbl =
3073 {
3074 Test_IClassFactory_QueryInterface,
3075 Test_IClassFactory_AddRef,
3076 Test_IClassFactory_Release,
3077 TestMsg_IClassFactory_CreateInstance,
3078 Test_IClassFactory_LockServer
3079 };
3080
3081 static IClassFactory TestMsg_ClassFactory = { &TestMsgClassFactory_Vtbl };
3082
3083 static void test_call_from_message(void)
3084 {
3085 MSG msg;
3086 IStream *pStream;
3087 HRESULT hr;
3088 IClassFactory *proxy;
3089 DWORD tid;
3090 HANDLE thread;
3091 IUnknown *object;
3092
3093 hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3094 ok(hwnd_app != NULL, "Window creation failed\n");
3095
3096 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3097 ok_ole_success(hr, CreateStreamOnHGlobal);
3098 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestMsg_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3099
3100 ok_more_than_one_lock();
3101
3102 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3103 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
3104 ok_ole_success(hr, CoReleaseMarshalData);
3105 IStream_Release(pStream);
3106
3107 ok_more_than_one_lock();
3108
3109 /* start message re-entrancy test */
3110 hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
3111 ok_ole_success(hr, IClassFactory_CreateInstance);
3112
3113 IClassFactory_Release(proxy);
3114
3115 ok_no_locks();
3116
3117 end_host_object(tid, thread);
3118
3119 while (GetMessageA(&msg, NULL, 0, 0))
3120 {
3121 TranslateMessage(&msg);
3122 DispatchMessageA(&msg);
3123 }
3124 DestroyWindow(hwnd_app);
3125 }
3126
3127 static void test_WM_QUIT_handling(void)
3128 {
3129 MSG msg;
3130
3131 hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
3132 ok(hwnd_app != NULL, "Window creation failed\n");
3133
3134 /* start WM_QUIT handling test */
3135 PostMessageA(hwnd_app, WM_USER+1, 0, 0);
3136
3137 while (GetMessageA(&msg, NULL, 0, 0))
3138 {
3139 TranslateMessage(&msg);
3140 DispatchMessageA(&msg);
3141 }
3142 }
3143
3144 static SIZE_T round_global_size(SIZE_T size)
3145 {
3146 static SIZE_T global_size_alignment = -1;
3147 if (global_size_alignment == -1)
3148 {
3149 void *p = GlobalAlloc(GMEM_FIXED, 1);
3150 global_size_alignment = GlobalSize(p);
3151 GlobalFree(p);
3152 }
3153
3154 return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1));
3155 }
3156
3157 static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void *ptr, DWORD mshlflags)
3158 {
3159 HGLOBAL hglobal;
3160 DWORD size;
3161 char *marshal_data;
3162 HRESULT hr;
3163
3164 hr = GetHGlobalFromStream(pStream, &hglobal);
3165 ok_ole_success(hr, GetHGlobalFromStream);
3166
3167 size = GlobalSize(hglobal);
3168
3169 marshal_data = GlobalLock(hglobal);
3170
3171 if (mshctx == MSHCTX_INPROC)
3172 {
3173 DWORD expected_size = round_global_size(3*sizeof(DWORD) + sizeof(GUID));
3174 ok(size == expected_size ||
3175 broken(size == (2*sizeof(DWORD))) /* Win9x & NT4 */,
3176 "size should have been %d instead of %d\n", expected_size, size);
3177
3178 ok(*(DWORD *)marshal_data == mshlflags, "expected 0x%x, but got 0x%x for mshctx\n", mshlflags, *(DWORD *)marshal_data);
3179 marshal_data += sizeof(DWORD);
3180 ok(*(void **)marshal_data == ptr, "expected %p, but got %p for mshctx\n", ptr, *(void **)marshal_data);
3181 marshal_data += sizeof(void *);
3182 if (sizeof(void*) == 4 && size >= 3*sizeof(DWORD))
3183 {
3184 ok(*(DWORD *)marshal_data == 0, "expected 0x0, but got 0x%x\n", *(DWORD *)marshal_data);
3185 marshal_data += sizeof(DWORD);
3186 }
3187 if (size >= 3*sizeof(DWORD) + sizeof(GUID))
3188 {
3189 trace("got guid data: %s\n", wine_dbgstr_guid((GUID *)marshal_data));
3190 }
3191 }
3192 else
3193 {
3194 ok(size > sizeof(DWORD), "size should have been > sizeof(DWORD), not %d\n", size);
3195 ok(*(DWORD *)marshal_data == 0x574f454d /* MEOW */,
3196 "marshal data should be filled by standard marshal and start with MEOW signature\n");
3197 }
3198
3199 GlobalUnlock(hglobal);
3200 }
3201
3202 static void test_freethreadedmarshaler(void)
3203 {
3204 HRESULT hr;
3205 IUnknown *pFTUnknown;
3206 IMarshal *pFTMarshal;
3207 IStream *pStream;
3208 IUnknown *pProxy;
3209 static const LARGE_INTEGER llZero;
3210 CLSID clsid;
3211
3212 cLocks = 0;
3213 hr = CoCreateFreeThreadedMarshaler(NULL, &pFTUnknown);
3214 ok_ole_success(hr, CoCreateFreeThreadedMarshaler);
3215 hr = IUnknown_QueryInterface(pFTUnknown, &IID_IMarshal, (void **)&pFTMarshal);
3216 ok_ole_success(hr, IUnknown_QueryInterface);
3217 IUnknown_Release(pFTUnknown);
3218
3219 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3220 ok_ole_success(hr, CreateStreamOnHGlobal);
3221
3222 /* inproc normal marshaling */
3223
3224 hr = IMarshal_GetUnmarshalClass(pFTMarshal, &IID_IClassFactory,
3225 &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &clsid);
3226 ok_ole_success(hr, IMarshal_GetUnmarshalClass);
3227 ok(IsEqualIID(&clsid, &CLSID_InProcFreeMarshaler), "clsid = %s\n",
3228 wine_dbgstr_guid(&clsid));
3229
3230 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3231 &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3232 ok_ole_success(hr, IMarshal_MarshalInterface);
3233
3234 ok_more_than_one_lock();
3235
3236 test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_NORMAL);
3237
3238 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3239 hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3240 ok_ole_success(hr, IMarshal_UnmarshalInterface);
3241
3242 IUnknown_Release(pProxy);
3243
3244 ok_no_locks();
3245
3246 /* inproc table-strong marshaling */
3247
3248 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3249 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3250 (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
3251 MSHLFLAGS_TABLESTRONG);
3252 ok_ole_success(hr, IMarshal_MarshalInterface);
3253
3254 ok_more_than_one_lock();
3255
3256 test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLESTRONG);
3257
3258 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3259 hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3260 ok_ole_success(hr, IMarshal_UnmarshalInterface);
3261
3262 IUnknown_Release(pProxy);
3263
3264 ok_more_than_one_lock();
3265
3266 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3267 hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
3268 ok_ole_success(hr, IMarshal_ReleaseMarshalData);
3269
3270 ok_no_locks();
3271
3272 /* inproc table-weak marshaling */
3273
3274 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3275 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3276 (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
3277 MSHLFLAGS_TABLEWEAK);
3278 ok_ole_success(hr, IMarshal_MarshalInterface);
3279
3280 ok_no_locks();
3281
3282 test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLEWEAK);
3283
3284 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3285 hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3286 ok_ole_success(hr, IMarshal_UnmarshalInterface);
3287
3288 ok_more_than_one_lock();
3289
3290 IUnknown_Release(pProxy);
3291
3292 ok_no_locks();
3293
3294 /* inproc normal marshaling (for extraordinary cases) */
3295
3296 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3297 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
3298 &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3299 ok_ole_success(hr, IMarshal_MarshalInterface);
3300
3301 ok_more_than_one_lock();
3302
3303 /* this call shows that DisconnectObject does nothing */
3304 hr = IMarshal_DisconnectObject(pFTMarshal, 0);
3305 ok_ole_success(hr, IMarshal_DisconnectObject);
3306
3307 ok_more_than_one_lock();
3308
3309 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3310 hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
3311 ok_ole_success(hr, IMarshal_ReleaseMarshalData);
3312
3313 ok_no_locks();
3314
3315 /* doesn't enforce marshaling rules here and allows us to unmarshal the
3316 * interface, even though it was freed above */
3317 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3318 hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3319 ok_ole_success(hr, IMarshal_UnmarshalInterface);
3320
3321 ok_no_locks();
3322
3323 /* local normal marshaling */
3324
3325 hr = IMarshal_GetUnmarshalClass(pFTMarshal, &IID_IClassFactory,
3326 &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL, &clsid);
3327 ok_ole_success(hr, IMarshal_GetUnmarshalClass);
3328 ok(IsEqualIID(&clsid, &CLSID_StdMarshal), "clsid = %s\n",
3329 wine_dbgstr_guid(&clsid));
3330
3331 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3332 hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
3333 ok_ole_success(hr, IMarshal_MarshalInterface);
3334
3335 ok_more_than_one_lock();
3336
3337 test_freethreadedmarshaldata(pStream, MSHCTX_LOCAL, &Test_ClassFactory, MSHLFLAGS_NORMAL);
3338
3339 IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3340 hr = CoReleaseMarshalData(pStream);
3341 ok_ole_success(hr, CoReleaseMarshalData);
3342
3343 ok_no_locks();
3344
3345 IStream_Release(pStream);
3346 IMarshal_Release(pFTMarshal);
3347 }
3348
3349 static HRESULT reg_unreg_wine_test_class(BOOL Register)
3350 {
3351 HRESULT hr;
3352 char buffer[256];
3353 LPOLESTR pszClsid;
3354 HKEY hkey;
3355 DWORD dwDisposition;
3356 DWORD error;
3357
3358 hr = StringFromCLSID(&CLSID_WineTest, &pszClsid);
3359 ok_ole_success(hr, "StringFromCLSID");
3360 strcpy(buffer, "CLSID\\");
3361 WideCharToMultiByte(CP_ACP, 0, pszClsid, -1, buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), NULL, NULL);
3362 CoTaskMemFree(pszClsid);
3363 strcat(buffer, "\\InprocHandler32");
3364 if (Register)
3365 {
3366 error = RegCreateKeyExA(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
3367 if (error == ERROR_ACCESS_DENIED)
3368 {
3369 skip("Not authorized to modify the Classes key\n");
3370 return E_FAIL;
3371 }
3372 ok(error == ERROR_SUCCESS, "RegCreateKeyEx failed with error %d\n", error);
3373 if (error != ERROR_SUCCESS) hr = E_FAIL;
3374 error = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const unsigned char *)"\"ole32.dll\"", strlen("\"ole32.dll\"") + 1);
3375 ok(error == ERROR_SUCCESS, "RegSetValueEx failed with error %d\n", error);
3376 if (error != ERROR_SUCCESS) hr = E_FAIL;
3377 RegCloseKey(hkey);
3378 }
3379 else
3380 {
3381 RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
3382 *strrchr(buffer, '\\') = '\0';
3383 RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
3384 }
3385 return hr;
3386 }
3387
3388 static void test_inproc_handler(void)
3389 {
3390 HRESULT hr;
3391 IUnknown *pObject;
3392 IUnknown *pObject2;
3393
3394 if (FAILED(reg_unreg_wine_test_class(TRUE)))
3395 return;
3396
3397 hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pObject);
3398 ok_ole_success(hr, "CoCreateInstance");
3399
3400 if (SUCCEEDED(hr))
3401 {
3402 hr = IUnknown_QueryInterface(pObject, &IID_IWineTest, (void **)&pObject2);
3403 ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface on handler for invalid interface returned 0x%08x instead of E_NOINTERFACE\n", hr);
3404
3405 /* it's a handler as it supports IOleObject */
3406 hr = IUnknown_QueryInterface(pObject, &IID_IOleObject, (void **)&pObject2);
3407 ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
3408 IUnknown_Release(pObject2);
3409
3410 IUnknown_Release(pObject);
3411 }
3412
3413 reg_unreg_wine_test_class(FALSE);
3414 }
3415
3416 static HRESULT WINAPI Test_SMI_QueryInterface(
3417 IStdMarshalInfo *iface,
3418 REFIID riid,
3419 LPVOID *ppvObj)
3420 {
3421 if (ppvObj == NULL) return E_POINTER;
3422
3423 if (IsEqualGUID(riid, &IID_IUnknown) ||
3424 IsEqualGUID(riid, &IID_IStdMarshalInfo))
3425 {
3426 *ppvObj = iface;
3427 IStdMarshalInfo_AddRef(iface);
3428 return S_OK;
3429 }
3430
3431 return E_NOINTERFACE;
3432 }
3433
3434 static ULONG WINAPI Test_SMI_AddRef(IStdMarshalInfo *iface)
3435 {
3436 LockModule();
3437 return 2; /* non-heap-based object */
3438 }
3439
3440 static ULONG WINAPI Test_SMI_Release(IStdMarshalInfo *iface)
3441 {
3442 UnlockModule();
3443 return 1; /* non-heap-based object */
3444 }
3445
3446 static HRESULT WINAPI Test_SMI_GetClassForHandler(
3447 IStdMarshalInfo *iface,
3448 DWORD dwDestContext,
3449 void *pvDestContext,
3450 CLSID *pClsid)
3451 {
3452 *pClsid = CLSID_WineTest;
3453 return S_OK;
3454 }
3455
3456 static const IStdMarshalInfoVtbl Test_SMI_Vtbl =
3457 {
3458 Test_SMI_QueryInterface,
3459 Test_SMI_AddRef,
3460 Test_SMI_Release,
3461 Test_SMI_GetClassForHandler
3462 };
3463
3464 static IStdMarshalInfo Test_SMI = {&Test_SMI_Vtbl};
3465
3466 static void test_handler_marshaling(void)
3467 {
3468 HRESULT hr;
3469 IStream *pStream = NULL;
3470 IUnknown *pProxy = NULL;
3471 IUnknown *pObject;
3472 DWORD tid;
3473 HANDLE thread;
3474 static const LARGE_INTEGER ullZero;
3475
3476 if (FAILED(reg_unreg_wine_test_class(TRUE)))
3477 return;
3478 cLocks = 0;
3479
3480 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3481 ok_ole_success(hr, "CreateStreamOnHGlobal");
3482 tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_SMI, MSHLFLAGS_NORMAL, &thread);
3483
3484 ok_more_than_one_lock();
3485
3486 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3487 hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
3488 ok_ole_success(hr, "CoUnmarshalInterface");
3489 IStream_Release(pStream);
3490
3491 if(hr == S_OK)
3492 {
3493 ok_more_than_one_lock();
3494
3495 hr = IUnknown_QueryInterface(pProxy, &IID_IWineTest, (void **)&pObject);
3496 ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface with unknown IID should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3497
3498 /* it's a handler as it supports IOleObject */
3499 hr = IUnknown_QueryInterface(pProxy, &IID_IOleObject, (void **)&pObject);
3500 todo_wine
3501 ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
3502 if (SUCCEEDED(hr)) IUnknown_Release(pObject);
3503
3504 IUnknown_Release(pProxy);
3505
3506 ok_no_locks();
3507 }
3508
3509 end_host_object(tid, thread);
3510 reg_unreg_wine_test_class(FALSE);
3511
3512 /* FIXME: test IPersist interface has the same effect as IStdMarshalInfo */
3513 }
3514
3515
3516 static void test_client_security(void)
3517 {
3518 HRESULT hr;
3519 IStream *pStream = NULL;
3520 IClassFactory *pProxy = NULL;
3521 IUnknown *pProxy2 = NULL;
3522 IUnknown *pUnknown1 = NULL;
3523 IUnknown *pUnknown2 = NULL;
3524 IClientSecurity *pCliSec = NULL;
3525 IMarshal *pMarshal;
3526 DWORD tid;
3527 HANDLE thread;
3528 static const LARGE_INTEGER ullZero;
3529 DWORD dwAuthnSvc;
3530 DWORD dwAuthzSvc;
3531 OLECHAR *pServerPrincName;
3532 DWORD dwAuthnLevel;
3533 DWORD dwImpLevel;
3534 void *pAuthInfo;
3535 DWORD dwCapabilities;
3536 void *pv;
3537
3538 cLocks = 0;
3539
3540 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3541 ok_ole_success(hr, "CreateStreamOnHGlobal");
3542 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3543
3544 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3545 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
3546 ok_ole_success(hr, "CoUnmarshalInterface");
3547 IStream_Release(pStream);
3548
3549 hr = IClassFactory_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pUnknown1);
3550 ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
3551
3552 hr = IClassFactory_QueryInterface(pProxy, &IID_IRemUnknown, (LPVOID*)&pProxy2);
3553 ok_ole_success(hr, "IUnknown_QueryInterface IID_IStream");
3554
3555 hr = IUnknown_QueryInterface(pProxy2, &IID_IUnknown, (LPVOID*)&pUnknown2);
3556 ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
3557
3558 ok(pUnknown1 == pUnknown2, "both proxy's IUnknowns should be the same - %p, %p\n", pUnknown1, pUnknown2);
3559
3560 hr = IClassFactory_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pMarshal);
3561 ok_ole_success(hr, "IUnknown_QueryInterface IID_IMarshal");
3562
3563 hr = IClassFactory_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pCliSec);
3564 ok_ole_success(hr, "IUnknown_QueryInterface IID_IClientSecurity");
3565
3566 hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3567 todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket (all NULLs)");
3568
3569 hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pMarshal, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3570 todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_QueryBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3571
3572 hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
3573 todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket");
3574
3575 hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, RPC_C_IMP_LEVEL_IMPERSONATE, pAuthInfo, dwCapabilities);
3576 todo_wine ok_ole_success(hr, "IClientSecurity_SetBlanket");
3577
3578 hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IWineTest, &pv);
3579 ok(hr == E_NOINTERFACE, "COM call should have succeeded instead of returning 0x%08x\n", hr);
3580
3581 hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pMarshal, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
3582 todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_SetBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3583
3584 hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, 0xdeadbeef, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
3585 todo_wine ok(hr == E_INVALIDARG, "IClientSecurity_SetBlanke with invalid dwAuthnSvc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
3586
3587 CoTaskMemFree(pServerPrincName);
3588
3589 hr = IClientSecurity_QueryBlanket(pCliSec, pUnknown1, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
3590 todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket(IUnknown)");
3591
3592 CoTaskMemFree(pServerPrincName);
3593
3594 IClassFactory_Release(pProxy);
3595 IUnknown_Release(pProxy2);
3596 IUnknown_Release(pUnknown1);
3597 IUnknown_Release(pUnknown2);
3598 IMarshal_Release(pMarshal);
3599 IClientSecurity_Release(pCliSec);
3600
3601 end_host_object(tid, thread);
3602 }
3603
3604 static HANDLE heventShutdown;
3605
3606 static void LockModuleOOP(void)
3607 {
3608 InterlockedIncrement(&cLocks); /* for test purposes only */
3609 CoAddRefServerProcess();
3610 }
3611
3612 static void UnlockModuleOOP(void)
3613 {
3614 InterlockedDecrement(&cLocks); /* for test purposes only */
3615 if (!CoReleaseServerProcess())
3616 SetEvent(heventShutdown);
3617 }
3618
3619 static HWND hwnd_app;
3620
3621 struct local_server
3622 {
3623 IPersist IPersist_iface; /* a nice short interface */
3624 };
3625
3626 static HRESULT WINAPI local_server_QueryInterface(IPersist *iface, REFIID iid, void **obj)
3627 {
3628 *obj = NULL;
3629
3630 if (IsEqualGUID(iid, &IID_IUnknown) ||
3631 IsEqualGUID(iid, &IID_IPersist))
3632 *obj = iface;
3633
3634 if (*obj)
3635 {
3636 IPersist_AddRef(iface);
3637 return S_OK;
3638 }
3639 return E_NOINTERFACE;
3640 }
3641
3642 static ULONG WINAPI local_server_AddRef(IPersist *iface)
3643 {
3644 return 2;
3645 }
3646
3647 static ULONG WINAPI local_server_Release(IPersist *iface)
3648 {
3649 return 1;
3650 }
3651
3652 static HRESULT WINAPI local_server_GetClassID(IPersist *iface, CLSID *clsid)
3653 {
3654 HRESULT hr;
3655
3656 *clsid = IID_IUnknown;
3657
3658 /* Test calling CoDisconnectObject within a COM call */
3659 hr = CoDisconnectObject((IUnknown *)iface, 0);
3660 ok(hr == S_OK, "got %08x\n", hr);
3661
3662 /* Initialize and uninitialize the apartment to show that we
3663 * remain in the autojoined mta */
3664 hr = pCoInitializeEx( NULL, COINIT_MULTITHREADED );
3665 ok( hr == S_FALSE, "got %08x\n", hr );
3666 CoUninitialize();
3667
3668 return S_OK;
3669 }
3670
3671 static const IPersistVtbl local_server_persist_vtbl =
3672 {
3673 local_server_QueryInterface,
3674 local_server_AddRef,
3675 local_server_Release,
3676 local_server_GetClassID
3677 };
3678
3679 struct local_server local_server_class =
3680 {
3681 {&local_server_persist_vtbl}
3682 };
3683
3684 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
3685 LPCLASSFACTORY iface,
3686 REFIID riid,
3687 LPVOID *ppvObj)
3688 {
3689 if (ppvObj == NULL) return E_POINTER;
3690
3691 if (IsEqualGUID(riid, &IID_IUnknown) ||
3692 IsEqualGUID(riid, &IID_IClassFactory))
3693 {
3694 *ppvObj = iface;
3695 IClassFactory_AddRef(iface);
3696 return S_OK;
3697 }
3698
3699 return E_NOINTERFACE;
3700 }
3701
3702 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
3703 {
3704 return 2; /* non-heap-based object */
3705 }
3706
3707 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
3708 {
3709 return 1; /* non-heap-based object */
3710 }
3711
3712 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
3713 LPCLASSFACTORY iface,
3714 LPUNKNOWN pUnkOuter,
3715 REFIID riid,
3716 LPVOID *ppvObj)
3717 {
3718 IPersist *persist = &local_server_class.IPersist_iface;
3719 HRESULT hr;
3720 IPersist_AddRef( persist );
3721 hr = IPersist_QueryInterface( persist, riid, ppvObj );
3722 IPersist_Release( persist );
3723 return hr;
3724 }
3725
3726 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
3727 LPCLASSFACTORY iface,
3728 BOOL fLock)
3729 {
3730 if (fLock)
3731 LockModuleOOP();
3732 else
3733 UnlockModuleOOP();
3734 return S_OK;
3735 }
3736
3737 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
3738 {
3739 TestOOP_IClassFactory_QueryInterface,
3740 TestOOP_IClassFactory_AddRef,
3741 TestOOP_IClassFactory_Release,
3742 TestOOP_IClassFactory_CreateInstance,
3743 TestOOP_IClassFactory_LockServer
3744 };
3745
3746 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
3747
3748 static void test_register_local_server(void)
3749 {
3750 DWORD cookie;
3751 HRESULT hr;
3752 HANDLE ready_event;
3753 DWORD wait;
3754 HANDLE handles[2];
3755
3756 heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
3757 ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
3758 handles[0] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
3759 handles[1] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event");
3760
3761 again:
3762 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
3763 CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
3764 ok_ole_success(hr, CoRegisterClassObject);
3765
3766 SetEvent(ready_event);
3767
3768 do
3769 {
3770 wait = MsgWaitForMultipleObjects(2, handles, FALSE, 30000, QS_ALLINPUT);
3771 if (wait == WAIT_OBJECT_0+2)
3772 {
3773 MSG msg;
3774
3775 if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
3776 {
3777 trace("Message 0x%x\n", msg.message);
3778 TranslateMessage(&msg);
3779 DispatchMessageA(&msg);
3780 }
3781 }
3782 else if (wait == WAIT_OBJECT_0+1)
3783 {
3784 hr = CoRevokeClassObject(cookie);
3785 ok_ole_success(hr, CoRevokeClassObject);
3786 goto again;
3787 }
3788 }
3789 while (wait == WAIT_OBJECT_0+2);
3790
3791 ok( wait == WAIT_OBJECT_0, "quit event wait timed out\n" );
3792 hr = CoRevokeClassObject(cookie);
3793 ok_ole_success(hr, CoRevokeClassObject);
3794 CloseHandle(handles[0]);
3795 CloseHandle(handles[1]);
3796 }
3797
3798 static HANDLE create_target_process(const char *arg)
3799 {
3800 char **argv;
3801 char cmdline[MAX_PATH];
3802 BOOL ret;
3803 PROCESS_INFORMATION pi;
3804 STARTUPINFOA si = { 0 };
3805 si.cb = sizeof(si);
3806
3807 pi.hThread = NULL;
3808 pi.hProcess = NULL;
3809 winetest_get_mainargs( &argv );
3810 sprintf(cmdline, "\"%s\" %s %s", argv[0], argv[1], arg);
3811 ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3812 ok(ret, "CreateProcess failed with error: %u\n", GetLastError());
3813 if (pi.hThread) CloseHandle(pi.hThread);
3814 return pi.hProcess;
3815 }
3816
3817 /* tests functions commonly used by out of process COM servers */
3818 static void test_local_server(void)
3819 {
3820 DWORD cookie;
3821 HRESULT hr;
3822 IClassFactory * cf;
3823 IPersist *persist;
3824 DWORD ret;
3825 HANDLE process;
3826 HANDLE quit_event;
3827 HANDLE ready_event;
3828 HANDLE repeat_event;
3829 CLSID clsid;
3830
3831 heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
3832
3833 cLocks = 0;
3834
3835 /* Start the object suspended */
3836 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
3837 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
3838 ok_ole_success(hr, CoRegisterClassObject);
3839
3840 /* ... and CoGetClassObject does not find it and fails when it looks for the
3841 * class in the registry */
3842 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
3843 NULL, &IID_IClassFactory, (LPVOID*)&cf);
3844 ok(hr == REGDB_E_CLASSNOTREG || /* NT */
3845 hr == S_OK /* Win9x */,
3846 "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
3847
3848 /* Resume the object suspended above ... */
3849 hr = CoResumeClassObjects();
3850 ok_ole_success(hr, CoResumeClassObjects);
3851
3852 /* ... and now it should succeed */
3853 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
3854 NULL, &IID_IClassFactory, (LPVOID*)&cf);
3855 ok_ole_success(hr, CoGetClassObject);
3856
3857 /* Now check the locking is working */
3858 /* NOTE: we are accessing the class directly, not through a proxy */
3859
3860 ok_no_locks();
3861
3862 hr = IClassFactory_LockServer(cf, TRUE);
3863 ok_ole_success(hr, IClassFactory_LockServer);
3864
3865 ok_more_than_one_lock();
3866
3867 IClassFactory_LockServer(cf, FALSE);
3868 ok_ole_success(hr, IClassFactory_LockServer);
3869
3870 ok_no_locks();
3871
3872 IClassFactory_Release(cf);
3873
3874 /* wait for shutdown signal */
3875 ret = WaitForSingleObject(heventShutdown, 0);
3876 ok(ret != WAIT_TIMEOUT, "Server didn't shut down\n");
3877
3878 /* try to connect again after SCM has suspended registered class objects */
3879 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
3880 &IID_IClassFactory, (LPVOID*)&cf);
3881 ok(hr == CO_E_SERVER_STOPPING || /* NT */
3882 hr == REGDB_E_CLASSNOTREG || /* win2k */
3883 hr == S_OK /* Win9x */,
3884 "CoGetClassObject should have returned CO_E_SERVER_STOPPING or REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
3885
3886 hr = CoRevokeClassObject(cookie);
3887 ok_ole_success(hr, CoRevokeClassObject);
3888
3889 CloseHandle(heventShutdown);
3890
3891 process = create_target_process("-Embedding");
3892 ok(process != NULL, "couldn't start local server process, error was %d\n", GetLastError());
3893
3894 ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
3895 ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
3896
3897 hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3898 ok_ole_success(hr, CoCreateInstance);
3899
3900 IPersist_Release(persist);
3901
3902 hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3903 ok(hr == REGDB_E_CLASSNOTREG, "Second CoCreateInstance on REGCLS_SINGLEUSE object should have failed\n");
3904
3905 /* Re-register the class and try calling CoDisconnectObject from within a call to that object */
3906 repeat_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event");
3907 SetEvent(repeat_event);
3908 CloseHandle(repeat_event);
3909
3910 ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
3911 CloseHandle(ready_event);
3912
3913 hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3914 ok_ole_success(hr, CoCreateInstance);
3915
3916 /* GetClassID will call CoDisconnectObject */
3917 IPersist_GetClassID(persist, &clsid);
3918 IPersist_Release(persist);
3919
3920 quit_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
3921 SetEvent(quit_event);
3922
3923 winetest_wait_child_process( process );
3924 CloseHandle(quit_event);
3925 CloseHandle(process);
3926 }
3927
3928 struct git_params
3929 {
3930 DWORD cookie;
3931 IGlobalInterfaceTable *git;
3932 };
3933
3934 static DWORD CALLBACK get_global_interface_proc(LPVOID pv)
3935 {
3936 HRESULT hr;
3937 struct git_params *params = pv;
3938 IClassFactory *cf;
3939
3940 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
3941 ok(hr == CO_E_NOTINITIALIZED ||
3942 broken(hr == E_UNEXPECTED) /* win2k */ ||
3943 broken(hr == S_OK) /* NT 4 */,
3944 "IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED or E_UNEXPECTED instead of 0x%08x\n",
3945 hr);
3946 if (hr == S_OK)
3947 IClassFactory_Release(cf);
3948
3949 CoInitialize(NULL);
3950
3951 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
3952 ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
3953
3954 IClassFactory_Release(cf);
3955
3956 CoUninitialize();
3957
3958 return hr;
3959 }
3960
3961 static void test_globalinterfacetable(void)
3962 {
3963 HRESULT hr;
3964 IGlobalInterfaceTable *git;
3965 DWORD cookie;
3966 HANDLE thread;
3967 DWORD tid;
3968 struct git_params params;
3969 DWORD ret;
3970 IUnknown *object;
3971 IClassFactory *cf;
3972 ULONG ref;
3973
3974 trace("test_globalinterfacetable\n");
3975 cLocks = 0;
3976
3977 hr = pDllGetClassObject(&CLSID_StdGlobalInterfaceTable, &IID_IClassFactory, (void**)&cf);
3978 ok(hr == S_OK, "got 0x%08x\n", hr);
3979
3980 hr = IClassFactory_QueryInterface(cf, &IID_IGlobalInterfaceTable, (void**)&object);
3981 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
3982
3983 IClassFactory_Release(cf);
3984
3985 hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)&git);
3986 ok_ole_success(hr, CoCreateInstance);
3987
3988 ref = IGlobalInterfaceTable_AddRef(git);
3989 ok(ref == 1, "ref=%d\n", ref);
3990 ref = IGlobalInterfaceTable_AddRef(git);
3991 ok(ref == 1, "ref=%d\n", ref);
3992
3993 ref = IGlobalInterfaceTable_Release(git);
3994 ok(ref == 1, "ref=%d\n", ref);
3995 ref = IGlobalInterfaceTable_Release(git);
3996 ok(ref == 1, "ref=%d\n", ref);
3997
3998 hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&Test_ClassFactory, &IID_IClassFactory, &cookie);
3999 ok_ole_success(hr, IGlobalInterfaceTable_RegisterInterfaceInGlobal);
4000
4001 ok_more_than_one_lock();
4002
4003 params.cookie = cookie;
4004 params.git = git;
4005 /* note: params is on stack so we MUST wait for get_global_interface_proc
4006 * to exit before we can return */
4007 thread = CreateThread(NULL, 0, get_global_interface_proc, &params, 0, &tid);
4008
4009 ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
4010 while (ret == WAIT_OBJECT_0 + 1)
4011 {
4012 MSG msg;
4013 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
4014 DispatchMessageA(&msg);
4015 ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
4016 }
4017
4018 CloseHandle(thread);
4019
4020 /* test getting interface from global with different iid */
4021 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, cookie, &IID_IUnknown, (void **)&object);
4022 ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
4023 IUnknown_Release(object);
4024
4025 /* test getting interface from global with same iid */
4026 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, cookie, &IID_IClassFactory, (void **)&object);
4027 ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
4028 IUnknown_Release(object);
4029
4030 hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, cookie);
4031 ok_ole_success(hr, IGlobalInterfaceTable_RevokeInterfaceFromGlobal);
4032
4033 ok_no_locks();
4034
4035 IGlobalInterfaceTable_Release(git);
4036 }
4037
4038 static void test_manualresetevent(void)
4039 {
4040 ISynchronizeHandle *sync_handle;
4041 ISynchronize *psync1, *psync2;
4042 IUnknown *punk;
4043 HANDLE handle;
4044 LONG ref;
4045 HRESULT hr;
4046
4047 hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&punk);
4048 ok(hr == S_OK, "Got 0x%08x\n", hr);
4049 ok(!!punk, "Got NULL.\n");
4050 IUnknown_Release(punk);
4051
4052 hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_ISynchronize, (void**)&psync1);
4053 ok(hr == S_OK, "Got 0x%08x\n", hr);
4054 ok(!!psync1, "Got NULL.\n");
4055
4056 hr = ISynchronize_Wait(psync1, 0, 5);
4057 ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4058
4059 hr = ISynchronize_Reset(psync1);
4060 ok(hr == S_OK, "Got 0x%08x\n", hr);
4061 hr = ISynchronize_Signal(psync1);
4062 ok(hr == S_OK, "Got 0x%08x\n", hr);
4063 hr = ISynchronize_Wait(psync1, 0, 5);
4064 ok(hr == S_OK, "Got 0x%08x\n", hr);
4065 hr = ISynchronize_Wait(psync1, 0, 5);
4066 ok(hr == S_OK, "Got 0x%08x\n", hr);
4067 hr = ISynchronize_Reset(psync1);
4068 ok(hr == S_OK, "Got 0x%08x\n", hr);
4069 hr = ISynchronize_Wait(psync1, 0, 5);
4070 ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4071
4072 hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_ISynchronize, (void**)&psync2);
4073 ok(hr == S_OK, "Got 0x%08x\n", hr);
4074 ok(!!psync2, "Got NULL.\n");
4075 ok(psync1 != psync2, "psync1 == psync2.\n");
4076
4077 hr = ISynchronize_QueryInterface(psync2, &IID_ISynchronizeHandle, (void**)&sync_handle);
4078 ok(hr == S_OK, "QueryInterface(IID_ISynchronizeHandle) failed: %08x\n", hr);
4079
4080 handle = NULL;
4081 hr = ISynchronizeHandle_GetHandle(sync_handle, &handle);
4082 ok(hr == S_OK, "GetHandle failed: %08x\n", hr);
4083 ok(handle != NULL && handle != INVALID_HANDLE_VALUE, "handle = %p\n", handle);
4084
4085 ISynchronizeHandle_Release(sync_handle);
4086
4087 hr = ISynchronize_Wait(psync2, 0, 5);
4088 ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4089
4090 hr = ISynchronize_Reset(psync1);
4091 ok(hr == S_OK, "Got 0x%08x\n", hr);
4092 hr = ISynchronize_Reset(psync2);
4093 ok(hr == S_OK, "Got 0x%08x\n", hr);
4094 hr = ISynchronize_Signal(psync1);
4095 ok(hr == S_OK, "Got 0x%08x\n", hr);
4096 hr = ISynchronize_Wait(psync2, 0, 5);
4097 ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
4098
4099 ref = ISynchronize_AddRef(psync1);
4100 ok(ref == 2, "Got ref: %d\n", ref);
4101 ref = ISynchronize_AddRef(psync1);
4102 ok(ref == 3, "Got ref: %d\n", ref);
4103 ref = ISynchronize_Release(psync1);
4104 ok(ref == 2, "Got nonzero ref: %d\n", ref);
4105 ref = ISynchronize_Release(psync2);
4106 ok(!ref, "Got nonzero ref: %d\n", ref);
4107 ref = ISynchronize_Release(psync1);
4108 ok(ref == 1, "Got nonzero ref: %d\n", ref);
4109 ref = ISynchronize_Release(psync1);
4110 ok(!ref, "Got nonzero ref: %d\n", ref);
4111 }
4112
4113 static DWORD CALLBACK implicit_mta_unmarshal_proc(void *param)
4114 {
4115 IStream *stream = param;
4116 IClassFactory *cf;
4117 IUnknown *proxy;
4118 HRESULT hr;
4119
4120 IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
4121 hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
4122 ok_ole_success(hr, CoUnmarshalInterface);
4123
4124 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4125 ok_ole_success(hr, IClassFactory_CreateInstance);
4126
4127 IUnknown_Release(proxy);
4128
4129 /* But if we initialize an STA in this apartment, it becomes the wrong one. */
4130 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4131
4132 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4133 ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
4134
4135 CoUninitialize();
4136
4137 ok_more_than_one_lock();
4138 ok_non_zero_external_conn();
4139
4140 IClassFactory_Release(cf);
4141
4142 ok_no_locks();
4143 ok_zero_external_conn();
4144 ok_last_release_closes(TRUE);
4145 return 0;
4146 }
4147
4148 static DWORD CALLBACK implicit_mta_use_proc(void *param)
4149 {
4150 IClassFactory *cf = param;
4151 IUnknown *proxy;
4152 HRESULT hr;
4153
4154 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4155 ok_ole_success(hr, IClassFactory_CreateInstance);
4156
4157 IUnknown_Release(proxy);
4158
4159 /* But if we initialize an STA in this apartment, it becomes the wrong one. */
4160 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4161
4162 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4163 ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
4164
4165 CoUninitialize();
4166 return 0;
4167 }
4168
4169 struct implicit_mta_marshal_data
4170 {
4171 IStream *stream;
4172 HANDLE start;
4173 HANDLE stop;
4174 };
4175
4176 static DWORD CALLBACK implicit_mta_marshal_proc(void *param)
4177 {
4178 struct implicit_mta_marshal_data *data = param;
4179 HRESULT hr;
4180
4181 hr = CoMarshalInterface(data->stream, &IID_IClassFactory,
4182 (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
4183 ok_ole_success(hr, CoMarshalInterface);
4184
4185 SetEvent(data->start);
4186
4187 ok(!WaitForSingleObject(data->stop, 1000), "wait failed\n");
4188 return 0;
4189 }
4190
4191 static void test_implicit_mta(void)
4192 {
4193 struct implicit_mta_marshal_data data;
4194 HANDLE host_thread, thread;
4195 IClassFactory *cf;
4196 IUnknown *proxy;
4197 IStream *stream;
4198 HRESULT hr;
4199 DWORD tid;
4200
4201 cLocks = 0;
4202 external_connections = 0;
4203
4204 CoInitializeEx(NULL, COINIT_MULTITHREADED);
4205
4206 /* Firstly: we can unmarshal and use an object while in the implicit MTA. */
4207 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4208 ok_ole_success(hr, CreateStreamOnHGlobal);
4209 tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
4210
4211 ok_more_than_one_lock();
4212 ok_non_zero_external_conn();
4213
4214 thread = CreateThread(NULL, 0, implicit_mta_unmarshal_proc, stream, 0, NULL);
4215 ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4216 CloseHandle(thread);
4217
4218 IStream_Release(stream);
4219 end_host_object(tid, host_thread);
4220
4221 /* Secondly: we can unmarshal an object into the real MTA and then use it
4222 * from the implicit MTA. */
4223 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4224 ok_ole_success(hr, CreateStreamOnHGlobal);
4225 tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
4226
4227 ok_more_than_one_lock();
4228 ok_non_zero_external_conn();
4229
4230 IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
4231 hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
4232 ok_ole_success(hr, CoUnmarshalInterface);
4233
4234 thread = CreateThread(NULL, 0, implicit_mta_use_proc, cf, 0, NULL);
4235 ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4236 CloseHandle(thread);
4237
4238 IClassFactory_Release(cf);
4239 IStream_Release(stream);
4240
4241 ok_no_locks();
4242 ok_non_zero_external_conn();
4243 ok_last_release_closes(TRUE);
4244
4245 end_host_object(tid, host_thread);
4246
4247 /* Thirdly: we can marshal an object from the implicit MTA and then
4248 * unmarshal it into the real one. */
4249 data.start = CreateEventA(NULL, FALSE, FALSE, NULL);
4250 data.stop = CreateEventA(NULL, FALSE, FALSE, NULL);
4251
4252 hr = CreateStreamOnHGlobal(NULL, TRUE, &data.stream);
4253 ok_ole_success(hr, CreateStreamOnHGlobal);
4254
4255 thread = CreateThread(NULL, 0, implicit_mta_marshal_proc, &data, 0, NULL);
4256 ok(!WaitForSingleObject(data.start, 1000), "wait failed\n");
4257
4258 IStream_Seek(data.stream, ullZero, STREAM_SEEK_SET, NULL);
4259 hr = CoUnmarshalInterface(data.stream, &IID_IClassFactory, (void **)&cf);
4260 ok_ole_success(hr, CoUnmarshalInterface);
4261
4262 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
4263 ok_ole_success(hr, IClassFactory_CreateInstance);
4264
4265 IUnknown_Release(proxy);
4266
4267 SetEvent(data.stop);
4268 ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
4269 CloseHandle(thread);
4270
4271 IStream_Release(data.stream);
4272
4273 CoUninitialize();
4274 }
4275
4276 static const char *debugstr_iid(REFIID riid)
4277 {
4278 static char name[256];
4279 HKEY hkeyInterface;
4280 WCHAR bufferW[39];
4281 char buffer[39];
4282 LONG name_size = sizeof(name);
4283 StringFromGUID2(riid, bufferW, ARRAY_SIZE(bufferW));
4284 WideCharToMultiByte(CP_ACP, 0, bufferW, ARRAY_SIZE(bufferW), buffer, sizeof(buffer), NULL, NULL);
4285 if (RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_QUERY_VALUE, &hkeyInterface) != ERROR_SUCCESS)
4286 {
4287 memcpy(name, buffer, sizeof(buffer));
4288 goto done;
4289 }
4290 if (RegQueryValueA(hkeyInterface, buffer, name, &name_size) != ERROR_SUCCESS)
4291 {
4292 memcpy(name, buffer, sizeof(buffer));
4293 goto done;
4294 }
4295 RegCloseKey(hkeyInterface);
4296 done:
4297 return name;
4298 }
4299
4300 static HRESULT WINAPI TestChannelHook_QueryInterface(IChannelHook *iface, REFIID riid, void **ppv)
4301 {
4302 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IChannelHook))
4303 {
4304 *ppv = iface;
4305 IChannelHook_AddRef(iface);
4306 return S_OK;
4307 }
4308
4309 *ppv = NULL;
4310 return E_NOINTERFACE;
4311 }
4312
4313 static ULONG WINAPI TestChannelHook_AddRef(IChannelHook *iface)
4314 {
4315 return 2;
4316 }
4317
4318 static ULONG WINAPI TestChannelHook_Release(IChannelHook *iface)
4319 {
4320 return 1;
4321 }
4322
4323 static BOOL new_hook_struct;
4324 static int method, server_tid;
4325 static GUID causality;
4326
4327 struct new_hook_info
4328 {
4329 IID iid;
4330 GUID causality;
4331 DWORD server_pid;
4332 DWORD server_tid;
4333 WORD method;
4334 };
4335
4336 static void WINAPI TestChannelHook_ClientGetSize(
4337 IChannelHook *iface,
4338 REFGUID uExtent,
4339 REFIID riid,
4340 ULONG *pDataSize )
4341 {
4342 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4343 trace("TestChannelHook_ClientGetSize\n");
4344 trace("\t%s\n", debugstr_iid(riid));
4345 if (info->cbSize != sizeof(*info))
4346 new_hook_struct = TRUE;
4347
4348 if (!new_hook_struct)
4349 {
4350 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4351 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4352 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4353 ok(!info->pObject, "pObject should be NULL\n");
4354 if (method == 3)
4355 causality = info->uCausality;
4356 else
4357 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4358 }
4359 else
4360 {
4361 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4362 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4363 GetCurrentProcessId());
4364 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4365 server_tid);
4366 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4367 if (method == 3)
4368 causality = new_info->causality;
4369 else
4370 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4371 }
4372
4373 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4374
4375 *pDataSize = 1;
4376 }
4377
4378 static void WINAPI TestChannelHook_ClientFillBuffer(
4379 IChannelHook *iface,
4380 REFGUID uExtent,
4381 REFIID riid,
4382 ULONG *pDataSize,
4383 void *pDataBuffer )
4384 {
4385 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4386 trace("TestChannelHook_ClientFillBuffer\n");
4387
4388 if (!new_hook_struct)
4389 {
4390 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4391 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4392 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4393 ok(!info->pObject, "pObject should be NULL\n");
4394 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4395 }
4396 else
4397 {
4398 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4399 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4400 GetCurrentProcessId());
4401 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4402 server_tid);
4403 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4404 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4405 }
4406
4407 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4408
4409 *(unsigned char *)pDataBuffer = 0xcc;
4410 *pDataSize = 1;
4411 }
4412
4413 static void WINAPI TestChannelHook_ClientNotify(
4414 IChannelHook *iface,
4415 REFGUID uExtent,
4416 REFIID riid,
4417 ULONG cbDataSize,
4418 void *pDataBuffer,
4419 DWORD lDataRep,
4420 HRESULT hrFault )
4421 {
4422 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4423 trace("TestChannelHook_ClientNotify hrFault = 0x%08x\n", hrFault);
4424
4425 if (!new_hook_struct)
4426 {
4427 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4428 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4429 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4430 todo_wine {
4431 ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4432 }
4433 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4434 }
4435 else
4436 {
4437 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4438 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4439 GetCurrentProcessId());
4440 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4441 server_tid);
4442 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4443 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4444 }
4445
4446 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4447 }
4448
4449 static void WINAPI TestChannelHook_ServerNotify(
4450 IChannelHook *iface,
4451 REFGUID uExtent,
4452 REFIID riid,
4453 ULONG cbDataSize,
4454 void *pDataBuffer,
4455 DWORD lDataRep )
4456 {
4457 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4458 trace("TestChannelHook_ServerNotify\n");
4459
4460 if (!new_hook_struct)
4461 {
4462 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4463 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4464 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4465 ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4466 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4467 }
4468 else
4469 {
4470 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4471 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4472 GetCurrentProcessId());
4473 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4474 server_tid);
4475 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4476 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4477 }
4478
4479 ok(cbDataSize == 1, "cbDataSize should have been 1 instead of %d\n", cbDataSize);
4480 ok(*(unsigned char *)pDataBuffer == 0xcc, "pDataBuffer should have contained 0xcc instead of 0x%x\n", *(unsigned char *)pDataBuffer);
4481 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4482 }
4483
4484 static void WINAPI TestChannelHook_ServerGetSize(
4485 IChannelHook *iface,
4486 REFGUID uExtent,
4487 REFIID riid,
4488 HRESULT hrFault,
4489 ULONG *pDataSize )
4490 {
4491 SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4492 trace("TestChannelHook_ServerGetSize\n");
4493 trace("\t%s\n", debugstr_iid(riid));
4494 if (!new_hook_struct)
4495 {
4496 ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4497 ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4498 ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4499 ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4500 ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4501 }
4502 else
4503 {
4504 struct new_hook_info *new_info = (struct new_hook_info *)riid;
4505 ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4506 GetCurrentProcessId());
4507 ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4508 server_tid);
4509 ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4510 ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4511 }
4512
4513 ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4514 if (hrFault != S_OK)
4515 trace("\thrFault = 0x%08x\n", hrFault);
4516
4517 *pDataSize = 0;
4518 }
4519
4520 static void WINAPI TestChannelHook_ServerFillBuffer(
4521 IChannelHook *iface,
4522 REFGUID uExtent,
4523 REFIID riid,
4524 ULONG *pDataSize,
4525 void *pDataBuffer,
4526 HRESULT hrFault )
4527 {
4528 trace("TestChannelHook_ServerFillBuffer\n");
4529 ok(0, "TestChannelHook_ServerFillBuffer shouldn't be called\n");
4530 }
4531
4532 static const IChannelHookVtbl TestChannelHookVtbl =
4533 {
4534 TestChannelHook_QueryInterface,
4535 TestChannelHook_AddRef,
4536 TestChannelHook_Release,
4537 TestChannelHook_ClientGetSize,
4538 TestChannelHook_ClientFillBuffer,
4539 TestChannelHook_ClientNotify,
4540 TestChannelHook_ServerNotify,
4541 TestChannelHook_ServerGetSize,
4542 TestChannelHook_ServerFillBuffer,
4543 };
4544
4545 static IChannelHook TestChannelHook = { &TestChannelHookVtbl };
4546
4547 static void test_channel_hook(void)
4548 {
4549 IClassFactory *cf = NULL;
4550 DWORD tid;
4551 IUnknown *proxy = NULL;
4552 HANDLE thread;
4553 HRESULT hr;
4554
4555 struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
4556 MSHLFLAGS_NORMAL, &MessageFilter };
4557
4558 hr = CoRegisterChannelHook(&EXTENTID_WineTest, &TestChannelHook);
4559 ok_ole_success(hr, CoRegisterChannelHook);
4560
4561 hr = CoRegisterMessageFilter(&MessageFilter, NULL);
4562 ok_ole_success(hr, CoRegisterMessageFilter);
4563
4564 cLocks = 0;
4565
4566 hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
4567 ok_ole_success(hr, CreateStreamOnHGlobal);
4568 tid = start_host_object2(&object_data, &thread);
4569 server_tid = tid;
4570
4571 ok_more_than_one_lock();
4572
4573 IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
4574 hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
4575 ok_ole_success(hr, CoUnmarshalInterface);
4576 IStream_Release(object_data.stream);
4577
4578 ok_more_than_one_lock();
4579
4580 method = 3;
4581 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
4582 ok_ole_success(hr, IClassFactory_CreateInstance);
4583
4584 method = 5;
4585 IUnknown_Release(proxy);
4586
4587 IClassFactory_Release(cf);
4588
4589 ok_no_locks();
4590
4591 end_host_object(tid, thread);
4592
4593 hr = CoRegisterMessageFilter(NULL, NULL);
4594 ok_ole_success(hr, CoRegisterMessageFilter);
4595 }
4596
4597 START_TEST(marshal)
4598 {
4599 HMODULE hOle32 = GetModuleHandleA("ole32");
4600 int argc;
4601 char **argv;
4602
4603 if (!GetProcAddress(hOle32, "CoRegisterSurrogateEx")) {
4604 win_skip("skipping test on win9x\n");
4605 return;
4606 }
4607
4608 pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx");
4609 pDllGetClassObject = (void*)GetProcAddress(hOle32, "DllGetClassObject");
4610
4611 argc = winetest_get_mainargs( &argv );
4612 if (argc > 2 && (!strcmp(argv[2], "-Embedding")))
4613 {
4614 pCoInitializeEx(NULL, COINIT_MULTITHREADED);
4615 test_register_local_server();
4616 CoUninitialize();
4617
4618 return;
4619 }
4620
4621 register_test_window();
4622
4623 test_cocreateinstance_proxy();
4624 test_implicit_mta();
4625
4626 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4627
4628 /* FIXME: test CoCreateInstanceEx */
4629
4630 /* lifecycle management and marshaling tests */
4631 do
4632 {
4633 test_no_marshaler();
4634 test_normal_marshal_and_release();
4635 test_normal_marshal_and_unmarshal();
4636 test_marshal_and_unmarshal_invalid();
4637 test_same_apartment_unmarshal_failure();
4638 test_interthread_marshal_and_unmarshal();
4639 test_proxy_marshal_and_unmarshal();
4640 test_proxy_marshal_and_unmarshal2();
4641 test_proxy_marshal_and_unmarshal_weak();
4642 test_proxy_marshal_and_unmarshal_strong();
4643 test_marshal_stub_apartment_shutdown();
4644 test_marshal_proxy_apartment_shutdown();
4645 test_marshal_proxy_mta_apartment_shutdown();
4646 test_no_couninitialize_server();
4647 test_no_couninitialize_client();
4648 test_tableweak_marshal_and_unmarshal_twice();
4649 test_tableweak_marshal_releasedata1();
4650 test_tableweak_marshal_releasedata2();
4651 test_tableweak_and_normal_marshal_and_unmarshal();
4652 test_tableweak_and_normal_marshal_and_releasedata();
4653 test_two_tableweak_marshal_and_releasedata();
4654 test_tablestrong_marshal_and_unmarshal_twice();
4655 test_lock_object_external();
4656 test_disconnect_stub();
4657 test_normal_marshal_and_unmarshal_twice();
4658
4659 with_external_conn = !with_external_conn;
4660 } while (with_external_conn);
4661
4662 test_marshal_channel_buffer();
4663 test_StdMarshal_custom_marshaling();
4664 test_DfMarshal_custom_marshaling();
4665 test_CoGetStandardMarshal();
4666 test_hresult_marshaling();
4667 test_proxy_used_in_wrong_thread();
4668 test_message_filter();
4669 test_bad_marshal_stream();
4670 test_proxy_interfaces();
4671 test_stubbuffer(&IID_IClassFactory);
4672 test_proxybuffer(&IID_IClassFactory);
4673 test_message_reentrancy();
4674 test_call_from_message();
4675 test_WM_QUIT_handling();
4676 test_freethreadedmarshaler();
4677 test_inproc_handler();
4678 test_handler_marshaling();
4679 test_client_security();
4680
4681 test_local_server();
4682
4683 test_globalinterfacetable();
4684 test_manualresetevent();
4685 test_crash_couninitialize();
4686
4687 /* must be last test as channel hooks can't be unregistered */
4688 test_channel_hook();
4689
4690 CoUninitialize();
4691 }