crypt32: Test decoding a big CRL.
[wine] / dlls / ole32 / tests / 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
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
29 #include "shlguid.h"
30
31 #include "wine/test.h"
32
33 /* functions that are not present on all versions of Windows */
34 HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
35
36 /* helper macros to make tests a bit leaner */
37 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %ld\n", cLocks)
38 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %ld\n", cLocks)
39 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", hr)
40
41 static const IID IID_IWineTest =
42 {
43     0x5201163f,
44     0x8164,
45     0x4fd0,
46     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
47 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
48
49 static void test_cocreateinstance_proxy(void)
50 {
51     IUnknown *pProxy;
52     IMultiQI *pMQI;
53     HRESULT hr;
54
55     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
56
57     hr = CoCreateInstance(&CLSID_ShellDesktop, NULL, CLSCTX_INPROC, &IID_IUnknown, (void **)&pProxy);
58     ok_ole_success(hr, CoCreateInstance);
59     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (void **)&pMQI);
60     todo_wine
61     ok(hr == S_OK, "created object is not a proxy, so was created in the wrong apartment\n");
62     if (hr == S_OK)
63         IMultiQI_Release(pMQI);
64     IUnknown_Release(pProxy);
65
66     CoUninitialize();
67 }
68
69 static const LARGE_INTEGER ullZero;
70 static LONG cLocks;
71
72 static void LockModule(void)
73 {
74     InterlockedIncrement(&cLocks);
75 }
76
77 static void UnlockModule(void)
78 {
79     InterlockedDecrement(&cLocks);
80 }
81
82
83 static HRESULT WINAPI Test_IUnknown_QueryInterface(
84     LPUNKNOWN iface,
85     REFIID riid,
86     LPVOID *ppvObj)
87 {
88     if (ppvObj == NULL) return E_POINTER;
89
90     if (IsEqualGUID(riid, &IID_IUnknown))
91     {
92         *ppvObj = (LPVOID)iface;
93         IUnknown_AddRef(iface);
94         return S_OK;
95     }
96
97     *ppvObj = NULL;
98     return E_NOINTERFACE;
99 }
100
101 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
102 {
103     LockModule();
104     return 2; /* non-heap-based object */
105 }
106
107 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
108 {
109     UnlockModule();
110     return 1; /* non-heap-based object */
111 }
112
113 static const IUnknownVtbl TestUnknown_Vtbl =
114 {
115     Test_IUnknown_QueryInterface,
116     Test_IUnknown_AddRef,
117     Test_IUnknown_Release,
118 };
119
120 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
121
122
123 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
124     LPCLASSFACTORY iface,
125     REFIID riid,
126     LPVOID *ppvObj)
127 {
128     if (ppvObj == NULL) return E_POINTER;
129
130     if (IsEqualGUID(riid, &IID_IUnknown) ||
131         IsEqualGUID(riid, &IID_IClassFactory))
132     {
133         *ppvObj = (LPVOID)iface;
134         IClassFactory_AddRef(iface);
135         return S_OK;
136     }
137
138     *ppvObj = NULL;
139     return E_NOINTERFACE;
140 }
141
142 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
143 {
144     LockModule();
145     return 2; /* non-heap-based object */
146 }
147
148 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
149 {
150     UnlockModule();
151     return 1; /* non-heap-based object */
152 }
153
154 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
155     LPCLASSFACTORY iface,
156     LPUNKNOWN pUnkOuter,
157     REFIID riid,
158     LPVOID *ppvObj)
159 {
160     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
161     return IUnknown_QueryInterface((IUnknown*)&Test_Unknown, riid, ppvObj);
162 }
163
164 static HRESULT WINAPI Test_IClassFactory_LockServer(
165     LPCLASSFACTORY iface,
166     BOOL fLock)
167 {
168     return S_OK;
169 }
170
171 static const IClassFactoryVtbl TestClassFactory_Vtbl =
172 {
173     Test_IClassFactory_QueryInterface,
174     Test_IClassFactory_AddRef,
175     Test_IClassFactory_Release,
176     Test_IClassFactory_CreateInstance,
177     Test_IClassFactory_LockServer
178 };
179
180 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
181
182 #define RELEASEMARSHALDATA WM_USER
183
184 struct host_object_data
185 {
186     IStream *stream;
187     IID iid;
188     IUnknown *object;
189     MSHLFLAGS marshal_flags;
190     HANDLE marshal_event;
191     IMessageFilter *filter;
192 };
193
194 static DWORD CALLBACK host_object_proc(LPVOID p)
195 {
196     struct host_object_data *data = (struct host_object_data *)p;
197     HRESULT hr;
198     MSG msg;
199
200     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
201
202     if (data->filter)
203     {
204         IMessageFilter * prev_filter = NULL;
205         hr = CoRegisterMessageFilter(data->filter, &prev_filter);
206         if (prev_filter) IMessageFilter_Release(prev_filter);
207         ok_ole_success(hr, CoRegisterMessageFilter);
208     }
209
210     hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
211     ok_ole_success(hr, CoMarshalInterface);
212
213     /* force the message queue to be created before signaling parent thread */
214     PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
215
216     SetEvent(data->marshal_event);
217
218     while (GetMessage(&msg, NULL, 0, 0))
219     {
220         if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
221         {
222             trace("releasing marshal data\n");
223             CoReleaseMarshalData(data->stream);
224             SetEvent((HANDLE)msg.lParam);
225         }
226         else
227             DispatchMessage(&msg);
228     }
229
230     HeapFree(GetProcessHeap(), 0, data);
231
232     CoUninitialize();
233
234     return hr;
235 }
236
237 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
238 {
239     DWORD tid = 0;
240     HANDLE marshal_event = CreateEvent(NULL, FALSE, FALSE, NULL);
241     struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
242
243     data->stream = stream;
244     data->iid = *riid;
245     data->object = object;
246     data->marshal_flags = marshal_flags;
247     data->marshal_event = marshal_event;
248     data->filter = filter;
249
250     *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
251
252     /* wait for marshaling to complete before returning */
253     WaitForSingleObject(marshal_event, INFINITE);
254     CloseHandle(marshal_event);
255
256     return tid;
257 }
258
259 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
260 {
261     return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
262 }
263
264 /* asks thread to release the marshal data because it has to be done by the
265  * same thread that marshaled the interface in the first place. */
266 static void release_host_object(DWORD tid)
267 {
268     HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
269     PostThreadMessage(tid, RELEASEMARSHALDATA, 0, (LPARAM)event);
270     WaitForSingleObject(event, INFINITE);
271     CloseHandle(event);
272 }
273
274 static void end_host_object(DWORD tid, HANDLE thread)
275 {
276     BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0);
277     ok(ret, "PostThreadMessage failed with error %ld\n", GetLastError());
278     /* be careful of races - don't return until hosting thread has terminated */
279     WaitForSingleObject(thread, INFINITE);
280     CloseHandle(thread);
281 }
282
283 /* tests failure case of interface not having a marshaler specified in the
284  * registry */
285 static void test_no_marshaler(void)
286 {
287     IStream *pStream;
288     HRESULT hr;
289
290     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
291     ok_ole_success(hr, CreateStreamOnHGlobal);
292     hr = CoMarshalInterface(pStream, &IID_IWineTest, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
293     ok(hr == E_NOINTERFACE, "CoMarshalInterface should have returned E_NOINTERFACE instead of 0x%08lx\n", hr);
294
295     IStream_Release(pStream);
296 }
297
298 /* tests normal marshal and then release without unmarshaling */
299 static void test_normal_marshal_and_release(void)
300 {
301     HRESULT hr;
302     IStream *pStream = NULL;
303
304     cLocks = 0;
305
306     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
307     ok_ole_success(hr, CreateStreamOnHGlobal);
308     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
309     ok_ole_success(hr, CoMarshalInterface);
310
311     ok_more_than_one_lock();
312
313     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
314     hr = CoReleaseMarshalData(pStream);
315     ok_ole_success(hr, CoReleaseMarshalData);
316     IStream_Release(pStream);
317
318     ok_no_locks();
319 }
320
321 /* tests success case of a same-thread marshal and unmarshal */
322 static void test_normal_marshal_and_unmarshal(void)
323 {
324     HRESULT hr;
325     IStream *pStream = NULL;
326     IUnknown *pProxy = NULL;
327
328     cLocks = 0;
329
330     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
331     ok_ole_success(hr, CreateStreamOnHGlobal);
332     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
333     ok_ole_success(hr, CoMarshalInterface);
334
335     ok_more_than_one_lock();
336     
337     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
338     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
339     ok_ole_success(hr, CoUnmarshalInterface);
340     IStream_Release(pStream);
341
342     ok_more_than_one_lock();
343
344     IUnknown_Release(pProxy);
345
346     ok_no_locks();
347 }
348
349 /* tests failure case of unmarshaling a freed object */
350 static void test_marshal_and_unmarshal_invalid(void)
351 {
352     HRESULT hr;
353     IStream *pStream = NULL;
354     IClassFactory *pProxy = NULL;
355     DWORD tid;
356     void * dummy;
357     HANDLE thread;
358
359     cLocks = 0;
360
361     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
362     ok_ole_success(hr, CreateStreamOnHGlobal);
363     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
364
365     ok_more_than_one_lock();
366         
367     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
368     hr = CoReleaseMarshalData(pStream);
369     ok_ole_success(hr, CoReleaseMarshalData);
370
371     ok_no_locks();
372
373     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
374     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
375     todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
376
377     ok_no_locks();
378
379     if (pProxy)
380     {
381         hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, &dummy);
382         ok(hr == RPC_E_DISCONNECTED, "Remote call should have returned RPC_E_DISCONNECTED, instead of 0x%08lx\n", hr);
383
384         IClassFactory_Release(pProxy);
385     }
386
387     IStream_Release(pStream);
388
389     end_host_object(tid, thread);
390 }
391
392 /* tests success case of an interthread marshal */
393 static void test_interthread_marshal_and_unmarshal(void)
394 {
395     HRESULT hr;
396     IStream *pStream = NULL;
397     IUnknown *pProxy = NULL;
398     DWORD tid;
399     HANDLE thread;
400
401     cLocks = 0;
402
403     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
404     ok_ole_success(hr, CreateStreamOnHGlobal);
405     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
406
407     ok_more_than_one_lock();
408     
409     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
410     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
411     ok_ole_success(hr, CoUnmarshalInterface);
412     IStream_Release(pStream);
413
414     ok_more_than_one_lock();
415
416     IUnknown_Release(pProxy);
417
418     ok_no_locks();
419
420     end_host_object(tid, thread);
421 }
422
423 /* the number of external references that Wine's proxy manager normally gives
424  * out, so we can test the border case of running out of references */
425 #define NORMALEXTREFS 5
426
427 /* tests success case of an interthread marshal and then marshaling the proxy */
428 static void test_proxy_marshal_and_unmarshal(void)
429 {
430     HRESULT hr;
431     IStream *pStream = NULL;
432     IUnknown *pProxy = NULL;
433     IUnknown *pProxy2 = NULL;
434     DWORD tid;
435     HANDLE thread;
436     int i;
437
438     cLocks = 0;
439
440     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
441     ok_ole_success(hr, CreateStreamOnHGlobal);
442     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
443
444     ok_more_than_one_lock();
445     
446     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
447     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
448     ok_ole_success(hr, CoUnmarshalInterface);
449
450     ok_more_than_one_lock();
451
452     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
453     /* marshal the proxy */
454     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
455     ok_ole_success(hr, CoMarshalInterface);
456
457     ok_more_than_one_lock();
458
459     /* marshal 5 more times to exhaust the normal external references of 5 */
460     for (i = 0; i < NORMALEXTREFS; i++)
461     {
462         hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
463         ok_ole_success(hr, CoMarshalInterface);
464     }
465
466     ok_more_than_one_lock();
467
468     /* release the original proxy to test that we successfully keep the
469      * original object alive */
470     IUnknown_Release(pProxy);
471
472     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
473     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
474     ok_ole_success(hr, CoUnmarshalInterface);
475
476     ok_more_than_one_lock();
477
478     /* now the proxies should be as follows:
479      *  pProxy2 -> &Test_ClassFactory
480      * they should NOT be as follows:
481      *  pProxy -> &Test_ClassFactory
482      *  pProxy2 -> pProxy
483      * the above can only really be tested by looking in +ole traces
484      */
485
486     IUnknown_Release(pProxy2);
487
488     /* unmarshal all of the proxies to check that the object stub still exists */
489     for (i = 0; i < NORMALEXTREFS; i++)
490     {
491         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
492         ok_ole_success(hr, CoUnmarshalInterface);
493
494         IUnknown_Release(pProxy2);
495     }
496
497     ok_no_locks();
498
499     IStream_Release(pStream);
500
501     end_host_object(tid, thread);
502 }
503
504 /* tests success case of an interthread marshal and then marshaling the proxy
505  * using an iid that hasn't previously been unmarshaled */
506 static void test_proxy_marshal_and_unmarshal2(void)
507 {
508     HRESULT hr;
509     IStream *pStream = NULL;
510     IUnknown *pProxy = NULL;
511     IUnknown *pProxy2 = NULL;
512     DWORD tid;
513     HANDLE thread;
514
515     cLocks = 0;
516
517     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
518     ok_ole_success(hr, CreateStreamOnHGlobal);
519     tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
520
521     ok_more_than_one_lock();
522
523     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
524     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
525     ok_ole_success(hr, CoUnmarshalInterface);
526
527     ok_more_than_one_lock();
528
529     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
530     /* marshal the proxy */
531     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
532     ok_ole_success(hr, CoMarshalInterface);
533
534     ok_more_than_one_lock();
535
536     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
537     /* unmarshal the second proxy to the object */
538     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
539     ok_ole_success(hr, CoUnmarshalInterface);
540     IStream_Release(pStream);
541
542     /* now the proxies should be as follows:
543      *  pProxy -> &Test_ClassFactory
544      *  pProxy2 -> &Test_ClassFactory
545      * they should NOT be as follows:
546      *  pProxy -> &Test_ClassFactory
547      *  pProxy2 -> pProxy
548      * the above can only really be tested by looking in +ole traces
549      */
550
551     ok_more_than_one_lock();
552
553     IUnknown_Release(pProxy);
554
555     ok_more_than_one_lock();
556
557     IUnknown_Release(pProxy2);
558
559     ok_no_locks();
560
561     end_host_object(tid, thread);
562 }
563
564 /* tests that stubs are released when the containing apartment is destroyed */
565 static void test_marshal_stub_apartment_shutdown(void)
566 {
567     HRESULT hr;
568     IStream *pStream = NULL;
569     IUnknown *pProxy = NULL;
570     DWORD tid;
571     HANDLE thread;
572
573     cLocks = 0;
574
575     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
576     ok_ole_success(hr, CreateStreamOnHGlobal);
577     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
578
579     ok_more_than_one_lock();
580     
581     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
582     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
583     ok_ole_success(hr, CoUnmarshalInterface);
584     IStream_Release(pStream);
585
586     ok_more_than_one_lock();
587
588     end_host_object(tid, thread);
589
590     ok_no_locks();
591
592     IUnknown_Release(pProxy);
593
594     ok_no_locks();
595 }
596
597 /* tests that proxies are released when the containing apartment is destroyed */
598 static void test_marshal_proxy_apartment_shutdown(void)
599 {
600     HRESULT hr;
601     IStream *pStream = NULL;
602     IUnknown *pProxy = NULL;
603     DWORD tid;
604     HANDLE thread;
605
606     cLocks = 0;
607
608     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
609     ok_ole_success(hr, CreateStreamOnHGlobal);
610     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
611
612     ok_more_than_one_lock();
613     
614     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
615     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
616     ok_ole_success(hr, CoUnmarshalInterface);
617     IStream_Release(pStream);
618
619     ok_more_than_one_lock();
620
621     CoUninitialize();
622
623     ok_no_locks();
624
625     IUnknown_Release(pProxy);
626
627     ok_no_locks();
628
629     end_host_object(tid, thread);
630
631     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
632 }
633
634 /* tests that proxies are released when the containing mta apartment is destroyed */
635 static void test_marshal_proxy_mta_apartment_shutdown(void)
636 {
637     HRESULT hr;
638     IStream *pStream = NULL;
639     IUnknown *pProxy = NULL;
640     DWORD tid;
641     HANDLE thread;
642
643     CoUninitialize();
644     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
645
646     cLocks = 0;
647
648     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
649     ok_ole_success(hr, CreateStreamOnHGlobal);
650     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
651
652     ok_more_than_one_lock();
653
654     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
655     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
656     ok_ole_success(hr, CoUnmarshalInterface);
657     IStream_Release(pStream);
658
659     ok_more_than_one_lock();
660
661     CoUninitialize();
662
663     ok_no_locks();
664
665     IUnknown_Release(pProxy);
666
667     ok_no_locks();
668
669     end_host_object(tid, thread);
670
671     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
672 }
673
674 struct ncu_params
675 {
676     LPSTREAM stream;
677     HANDLE marshal_event;
678     HANDLE unmarshal_event;
679 };
680
681 /* helper for test_no_couninitialize_server */
682 static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p)
683 {
684     struct ncu_params *ncu_params = (struct ncu_params *)p;
685     HRESULT hr;
686
687     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
688
689     hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
690     ok_ole_success(hr, CoMarshalInterface);
691
692     SetEvent(ncu_params->marshal_event);
693
694     WaitForSingleObject(ncu_params->unmarshal_event, INFINITE);
695
696     /* die without calling CoUninitialize */
697
698     return 0;
699 }
700
701 /* tests apartment that an apartment with a stub is released without deadlock
702  * if the owning thread exits */
703 static void test_no_couninitialize_server(void)
704 {
705     HRESULT hr;
706     IStream *pStream = NULL;
707     IUnknown *pProxy = NULL;
708     DWORD tid;
709     HANDLE thread;
710     struct ncu_params ncu_params;
711
712     cLocks = 0;
713
714     ncu_params.marshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
715     ncu_params.unmarshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
716
717     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
718     ok_ole_success(hr, CreateStreamOnHGlobal);
719     ncu_params.stream = pStream;
720
721     thread = CreateThread(NULL, 0, no_couninitialize_server_proc, &ncu_params, 0, &tid);
722
723     WaitForSingleObject(ncu_params.marshal_event, INFINITE);
724     ok_more_than_one_lock();
725
726     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
727     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
728     ok_ole_success(hr, CoUnmarshalInterface);
729     IStream_Release(pStream);
730
731     ok_more_than_one_lock();
732
733     SetEvent(ncu_params.unmarshal_event);
734     WaitForSingleObject(thread, INFINITE);
735
736     ok_no_locks();
737
738     CloseHandle(thread);
739     CloseHandle(ncu_params.marshal_event);
740     CloseHandle(ncu_params.unmarshal_event);
741
742     IUnknown_Release(pProxy);
743
744     ok_no_locks();
745 }
746
747 /* STA -> STA call during DLL_THREAD_DETACH */
748 static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p)
749 {
750     struct ncu_params *ncu_params = (struct ncu_params *)p;
751     HRESULT hr;
752     IUnknown *pProxy = NULL;
753
754     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
755
756     hr = CoUnmarshalInterface(ncu_params->stream, &IID_IClassFactory, (void **)&pProxy);
757     ok_ole_success(hr, CoUnmarshalInterface);
758
759     ok_more_than_one_lock();
760
761     /* die without calling CoUninitialize */
762
763     return 0;
764 }
765
766 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
767 static void test_no_couninitialize_client(void)
768 {
769     HRESULT hr;
770     IStream *pStream = NULL;
771     DWORD tid;
772     DWORD host_tid;
773     HANDLE thread;
774     HANDLE host_thread;
775     struct ncu_params ncu_params;
776
777     cLocks = 0;
778
779     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
780     ok_ole_success(hr, CreateStreamOnHGlobal);
781     ncu_params.stream = pStream;
782
783     /* NOTE: assumes start_host_object uses an STA to host the object, as MTAs
784      * always deadlock when called from within DllMain */
785     host_tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
786     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
787
788     ok_more_than_one_lock();
789
790     thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
791
792     WaitForSingleObject(thread, INFINITE);
793     CloseHandle(thread);
794
795     ok_no_locks();
796
797     end_host_object(host_tid, host_thread);
798 }
799
800 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
801 static void test_tableweak_marshal_and_unmarshal_twice(void)
802 {
803     HRESULT hr;
804     IStream *pStream = NULL;
805     IUnknown *pProxy1 = NULL;
806     IUnknown *pProxy2 = NULL;
807     DWORD tid;
808     HANDLE thread;
809
810     cLocks = 0;
811
812     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
813     ok_ole_success(hr, CreateStreamOnHGlobal);
814     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
815
816     ok_more_than_one_lock();
817
818     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
819     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
820     ok_ole_success(hr, CoUnmarshalInterface);
821
822     ok_more_than_one_lock();
823
824     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
825     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
826     ok_ole_success(hr, CoUnmarshalInterface);
827
828     ok_more_than_one_lock();
829
830     IUnknown_Release(pProxy1);
831     IUnknown_Release(pProxy2);
832
833     /* this line is shows the difference between weak and strong table marshaling:
834      *  weak has cLocks == 0
835      *  strong has cLocks > 0 */
836     ok_no_locks();
837
838     end_host_object(tid, thread);
839 }
840
841 /* tests releasing after unmarshaling one object */
842 static void test_tableweak_marshal_releasedata1(void)
843 {
844     HRESULT hr;
845     IStream *pStream = NULL;
846     IUnknown *pProxy1 = NULL;
847     IUnknown *pProxy2 = NULL;
848     DWORD tid;
849     HANDLE thread;
850
851     cLocks = 0;
852
853     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
854     ok_ole_success(hr, CreateStreamOnHGlobal);
855     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
856
857     ok_more_than_one_lock();
858
859     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
860     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
861     ok_ole_success(hr, CoUnmarshalInterface);
862
863     ok_more_than_one_lock();
864
865     /* release the remaining reference on the object by calling
866      * CoReleaseMarshalData in the hosting thread */
867     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
868     release_host_object(tid);
869
870     ok_more_than_one_lock();
871
872     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
873     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
874     ok_ole_success(hr, CoUnmarshalInterface);
875     IStream_Release(pStream);
876
877     ok_more_than_one_lock();
878
879     IUnknown_Release(pProxy1);
880     if (pProxy2)
881         IUnknown_Release(pProxy2);
882
883     /* this line is shows the difference between weak and strong table marshaling:
884      *  weak has cLocks == 0
885      *  strong has cLocks > 0 */
886     ok_no_locks();
887
888     end_host_object(tid, thread);
889 }
890
891 /* tests releasing after unmarshaling one object */
892 static void test_tableweak_marshal_releasedata2(void)
893 {
894     HRESULT hr;
895     IStream *pStream = NULL;
896     IUnknown *pProxy = NULL;
897     DWORD tid;
898     HANDLE thread;
899
900     cLocks = 0;
901
902     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
903     ok_ole_success(hr, CreateStreamOnHGlobal);
904     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
905
906     ok_more_than_one_lock();
907
908     /* release the remaining reference on the object by calling
909      * CoReleaseMarshalData in the hosting thread */
910     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
911     release_host_object(tid);
912
913     ok_no_locks();
914
915     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
916     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
917     todo_wine
918     {
919     ok(hr == CO_E_OBJNOTREG,
920        "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08lx instead\n",
921        hr);
922     }
923     IStream_Release(pStream);
924
925     ok_no_locks();
926
927     end_host_object(tid, thread);
928 }
929
930 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
931 static void test_tablestrong_marshal_and_unmarshal_twice(void)
932 {
933     HRESULT hr;
934     IStream *pStream = NULL;
935     IUnknown *pProxy1 = NULL;
936     IUnknown *pProxy2 = NULL;
937     DWORD tid;
938     HANDLE thread;
939
940     cLocks = 0;
941
942     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
943     ok_ole_success(hr, CreateStreamOnHGlobal);
944     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
945
946     ok_more_than_one_lock();
947
948     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
949     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
950     ok_ole_success(hr, CoUnmarshalInterface);
951
952     ok_more_than_one_lock();
953
954     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
955     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
956     ok_ole_success(hr, CoUnmarshalInterface);
957
958     ok_more_than_one_lock();
959
960     if (pProxy1) IUnknown_Release(pProxy1);
961     if (pProxy2) IUnknown_Release(pProxy2);
962
963     /* this line is shows the difference between weak and strong table marshaling:
964      *  weak has cLocks == 0
965      *  strong has cLocks > 0 */
966     ok_more_than_one_lock();
967
968     /* release the remaining reference on the object by calling
969      * CoReleaseMarshalData in the hosting thread */
970     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
971     release_host_object(tid);
972     IStream_Release(pStream);
973
974     ok_no_locks();
975
976     end_host_object(tid, thread);
977 }
978
979 /* tests CoLockObjectExternal */
980 static void test_lock_object_external(void)
981 {
982     HRESULT hr;
983     IStream *pStream = NULL;
984
985     cLocks = 0;
986
987     /* test the stub manager creation aspect of CoLockObjectExternal when the
988      * object hasn't been marshaled yet */
989     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
990
991     ok_more_than_one_lock();
992
993     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
994
995     ok_no_locks();
996
997     /* test our empty stub manager being handled correctly in
998      * CoMarshalInterface */
999     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1000
1001     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1002     ok_ole_success(hr, CreateStreamOnHGlobal);
1003     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1004     ok_ole_success(hr, CoMarshalInterface);
1005
1006     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1007
1008     ok_more_than_one_lock();
1009
1010     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1011     hr = CoReleaseMarshalData(pStream);
1012     ok_ole_success(hr, CoReleaseMarshalData);
1013     IStream_Release(pStream);
1014
1015     ok_more_than_one_lock();
1016
1017     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
1018
1019     ok_more_than_one_lock();
1020
1021     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
1022
1023     ok_no_locks();
1024 }
1025
1026 /* tests disconnecting stubs */
1027 static void test_disconnect_stub(void)
1028 {
1029     HRESULT hr;
1030     IStream *pStream = NULL;
1031
1032     cLocks = 0;
1033
1034     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1035     ok_ole_success(hr, CreateStreamOnHGlobal);
1036     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1037     ok_ole_success(hr, CoMarshalInterface);
1038
1039     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1040
1041     ok_more_than_one_lock();
1042     
1043     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1044     hr = CoReleaseMarshalData(pStream);
1045     ok_ole_success(hr, CoReleaseMarshalData);
1046     IStream_Release(pStream);
1047
1048     ok_more_than_one_lock();
1049
1050     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
1051
1052     ok_no_locks();
1053 }
1054
1055 /* tests failure case of a same-thread marshal and unmarshal twice */
1056 static void test_normal_marshal_and_unmarshal_twice(void)
1057 {
1058     HRESULT hr;
1059     IStream *pStream = NULL;
1060     IUnknown *pProxy1 = NULL;
1061     IUnknown *pProxy2 = NULL;
1062
1063     cLocks = 0;
1064
1065     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1066     ok_ole_success(hr, CreateStreamOnHGlobal);
1067     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1068     ok_ole_success(hr, CoMarshalInterface);
1069
1070     ok_more_than_one_lock();
1071     
1072     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1073     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1074     ok_ole_success(hr, CoUnmarshalInterface);
1075
1076     ok_more_than_one_lock();
1077
1078     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1079     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1080     ok(hr == CO_E_OBJNOTCONNECTED,
1081         "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08lx\n", hr);
1082
1083     IStream_Release(pStream);
1084
1085     ok_more_than_one_lock();
1086
1087     IUnknown_Release(pProxy1);
1088
1089     ok_no_locks();
1090 }
1091
1092 /* tests success case of marshaling and unmarshaling an HRESULT */
1093 static void test_hresult_marshaling(void)
1094 {
1095     HRESULT hr;
1096     HRESULT hr_marshaled = 0;
1097     IStream *pStream = NULL;
1098     static const HRESULT E_DEADBEEF = 0xdeadbeef;
1099
1100     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1101     ok_ole_success(hr, CreateStreamOnHGlobal);
1102
1103     hr = CoMarshalHresult(pStream, E_DEADBEEF);
1104     ok_ole_success(hr, CoMarshalHresult);
1105
1106     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1107     hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
1108     ok_ole_success(hr, IStream_Read);
1109
1110     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
1111
1112     hr_marshaled = 0;
1113     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1114     hr = CoUnmarshalHresult(pStream, &hr_marshaled);
1115     ok_ole_success(hr, CoUnmarshalHresult);
1116
1117     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
1118
1119     IStream_Release(pStream);
1120 }
1121
1122
1123 /* helper for test_proxy_used_in_wrong_thread */
1124 static DWORD CALLBACK bad_thread_proc(LPVOID p)
1125 {
1126     IClassFactory * cf = (IClassFactory *)p;
1127     HRESULT hr;
1128     IUnknown * proxy = NULL;
1129
1130     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1131
1132     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1133     if (proxy) IUnknown_Release(proxy);
1134     ok(hr == RPC_E_WRONG_THREAD,
1135         "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n",
1136         hr);
1137
1138     CoUninitialize();
1139
1140     return 0;
1141 }
1142
1143 /* tests failure case of a using a proxy in the wrong apartment */
1144 static void test_proxy_used_in_wrong_thread(void)
1145 {
1146     HRESULT hr;
1147     IStream *pStream = NULL;
1148     IUnknown *pProxy = NULL;
1149     DWORD tid, tid2;
1150     HANDLE thread;
1151     HANDLE host_thread;
1152
1153     cLocks = 0;
1154
1155     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1156     ok_ole_success(hr, CreateStreamOnHGlobal);
1157     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
1158
1159     ok_more_than_one_lock();
1160     
1161     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1162     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1163     ok_ole_success(hr, CoUnmarshalInterface);
1164     IStream_Release(pStream);
1165
1166     ok_more_than_one_lock();
1167
1168     /* create a thread that we can misbehave in */
1169     thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
1170
1171     WaitForSingleObject(thread, INFINITE);
1172     CloseHandle(thread);
1173
1174     IUnknown_Release(pProxy);
1175
1176     ok_no_locks();
1177
1178     end_host_object(tid, host_thread);
1179 }
1180
1181 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
1182 {
1183     if (ppvObj == NULL) return E_POINTER;
1184
1185     if (IsEqualGUID(riid, &IID_IUnknown) ||
1186         IsEqualGUID(riid, &IID_IClassFactory))
1187     {
1188         *ppvObj = (LPVOID)iface;
1189         IClassFactory_AddRef(iface);
1190         return S_OK;
1191     }
1192
1193     return E_NOINTERFACE;
1194 }
1195
1196 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
1197 {
1198     return 2; /* non-heap object */
1199 }
1200
1201 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
1202 {
1203     return 1; /* non-heap object */
1204 }
1205
1206 static DWORD WINAPI MessageFilter_HandleInComingCall(
1207   IMessageFilter *iface,
1208   DWORD dwCallType,
1209   HTASK threadIDCaller,
1210   DWORD dwTickCount,
1211   LPINTERFACEINFO lpInterfaceInfo)
1212 {
1213     static int callcount = 0;
1214     DWORD ret;
1215     trace("HandleInComingCall\n");
1216     switch (callcount)
1217     {
1218     case 0:
1219         ret = SERVERCALL_REJECTED;
1220         break;
1221     case 1:
1222         ret = SERVERCALL_RETRYLATER;
1223         break;
1224     default:
1225         ret = SERVERCALL_ISHANDLED;
1226         break;
1227     }
1228     callcount++;
1229     return ret;
1230 }
1231
1232 static DWORD WINAPI MessageFilter_RetryRejectedCall(
1233   IMessageFilter *iface,
1234   HTASK threadIDCallee,
1235   DWORD dwTickCount,
1236   DWORD dwRejectType)
1237 {
1238     trace("RetryRejectedCall\n");
1239     return 0;
1240 }
1241
1242 static DWORD WINAPI MessageFilter_MessagePending(
1243   IMessageFilter *iface,
1244   HTASK threadIDCallee,
1245   DWORD dwTickCount,
1246   DWORD dwPendingType)
1247 {
1248     trace("MessagePending\n");
1249     return PENDINGMSG_WAITNOPROCESS;
1250 }
1251
1252 static const IMessageFilterVtbl MessageFilter_Vtbl =
1253 {
1254     MessageFilter_QueryInterface,
1255     MessageFilter_AddRef,
1256     MessageFilter_Release,
1257     MessageFilter_HandleInComingCall,
1258     MessageFilter_RetryRejectedCall,
1259     MessageFilter_MessagePending
1260 };
1261
1262 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
1263
1264 static void test_message_filter(void)
1265 {
1266     HRESULT hr;
1267     IStream *pStream = NULL;
1268     IClassFactory *cf = NULL;
1269     DWORD tid;
1270     IUnknown *proxy = NULL;
1271     IMessageFilter *prev_filter = NULL;
1272     HANDLE thread;
1273
1274     cLocks = 0;
1275
1276     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1277     ok_ole_success(hr, CreateStreamOnHGlobal);
1278     tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
1279
1280     ok_more_than_one_lock();
1281
1282     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1283     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
1284     ok_ole_success(hr, CoUnmarshalInterface);
1285     IStream_Release(pStream);
1286
1287     ok_more_than_one_lock();
1288
1289     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1290     todo_wine { ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08lx instead\n", hr); }
1291     if (proxy) IUnknown_Release(proxy);
1292     proxy = NULL;
1293
1294     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
1295     ok_ole_success(hr, CoRegisterMessageFilter);
1296     if (prev_filter) IMessageFilter_Release(prev_filter);
1297
1298     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1299     ok_ole_success(hr, IClassFactory_CreateInstance);
1300
1301     IUnknown_Release(proxy);
1302
1303     IClassFactory_Release(cf);
1304
1305     ok_no_locks();
1306
1307     end_host_object(tid, thread);
1308 }
1309
1310 /* test failure case of trying to unmarshal from bad stream */
1311 static void test_bad_marshal_stream(void)
1312 {
1313     HRESULT hr;
1314     IStream *pStream = NULL;
1315
1316     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1317     ok_ole_success(hr, CreateStreamOnHGlobal);
1318     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1319     ok_ole_success(hr, CoMarshalInterface);
1320
1321     ok_more_than_one_lock();
1322
1323     /* try to read beyond end of stream */
1324     hr = CoReleaseMarshalData(pStream);
1325     ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08lx instead\n", hr);
1326
1327     /* now release for real */
1328     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1329     hr = CoReleaseMarshalData(pStream);
1330     ok_ole_success(hr, CoReleaseMarshalData);
1331
1332     IStream_Release(pStream);
1333 }
1334
1335 /* tests that proxies implement certain interfaces */
1336 static void test_proxy_interfaces(void)
1337 {
1338     HRESULT hr;
1339     IStream *pStream = NULL;
1340     IUnknown *pProxy = NULL;
1341     IUnknown *pOtherUnknown = NULL;
1342     DWORD tid;
1343     HANDLE thread;
1344
1345     cLocks = 0;
1346
1347     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1348     ok_ole_success(hr, CreateStreamOnHGlobal);
1349     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1350
1351     ok_more_than_one_lock();
1352         
1353     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1354     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1355     ok_ole_success(hr, CoUnmarshalInterface);
1356     IStream_Release(pStream);
1357
1358     ok_more_than_one_lock();
1359
1360     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
1361     ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
1362     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1363
1364     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
1365     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity); }
1366     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1367
1368     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
1369     ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
1370     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1371
1372     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
1373     ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal);
1374     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1375
1376     /* IMarshal2 is also supported on NT-based systems, but is pretty much
1377      * useless as it has no more methods over IMarshal that it inherits from. */
1378
1379     IUnknown_Release(pProxy);
1380
1381     ok_no_locks();
1382
1383     end_host_object(tid, thread);
1384 }
1385
1386 typedef struct
1387 {
1388     const IUnknownVtbl *lpVtbl;
1389     ULONG refs;
1390 } HeapUnknown;
1391
1392 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1393 {
1394     if (IsEqualIID(riid, &IID_IUnknown))
1395     {
1396         IUnknown_AddRef(iface);
1397         *ppv = (LPVOID)iface;
1398         return S_OK;
1399     }
1400     *ppv = NULL;
1401     return E_NOINTERFACE;
1402 }
1403
1404 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
1405 {
1406     HeapUnknown *This = (HeapUnknown *)iface;
1407     trace("HeapUnknown_AddRef(%p)\n", iface);
1408     return InterlockedIncrement((LONG*)&This->refs);
1409 }
1410
1411 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
1412 {
1413     HeapUnknown *This = (HeapUnknown *)iface;
1414     ULONG refs = InterlockedDecrement((LONG*)&This->refs);
1415     trace("HeapUnknown_Release(%p)\n", iface);
1416     if (!refs) HeapFree(GetProcessHeap(), 0, This);
1417     return refs;
1418 }
1419
1420 static const IUnknownVtbl HeapUnknown_Vtbl =
1421 {
1422     HeapUnknown_QueryInterface,
1423     HeapUnknown_AddRef,
1424     HeapUnknown_Release
1425 };
1426
1427 static void test_proxybuffer(REFIID riid)
1428 {
1429     HRESULT hr;
1430     IPSFactoryBuffer *psfb;
1431     IRpcProxyBuffer *proxy;
1432     LPVOID lpvtbl;
1433     ULONG refs;
1434     CLSID clsid;
1435     HeapUnknown *pUnkOuter = (HeapUnknown *)HeapAlloc(GetProcessHeap(), 0, sizeof(*pUnkOuter));
1436
1437     pUnkOuter->lpVtbl = &HeapUnknown_Vtbl;
1438     pUnkOuter->refs = 1;
1439
1440     hr = CoGetPSClsid(riid, &clsid);
1441     ok_ole_success(hr, CoGetPSClsid);
1442
1443     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1444     ok_ole_success(hr, CoGetClassObject);
1445
1446     hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown*)pUnkOuter, riid, &proxy, &lpvtbl);
1447     ok_ole_success(hr, IPSFactoryBuffer_CreateProxy);
1448     ok(lpvtbl != NULL, "IPSFactoryBuffer_CreateProxy succeeded, but returned a NULL vtable!\n");
1449
1450     /* release our reference to the outer unknown object - the PS factory
1451      * buffer will have AddRef's it in the CreateProxy call */
1452     refs = IUnknown_Release((IUnknown *)pUnkOuter);
1453     ok(refs == 1, "Ref count of outer unknown should have been 1 instead of %ld\n", refs);
1454
1455     refs = IPSFactoryBuffer_Release(psfb);
1456 #if 0 /* not reliable on native. maybe it leaks references! */
1457     ok(refs == 0, "Ref-count leak of %ld on IPSFactoryBuffer\n", refs);
1458 #endif
1459
1460     refs = IUnknown_Release((IUnknown *)lpvtbl);
1461     ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
1462
1463     refs = IRpcProxyBuffer_Release(proxy);
1464     ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
1465 }
1466
1467 static void test_stubbuffer(REFIID riid)
1468 {
1469     HRESULT hr;
1470     IPSFactoryBuffer *psfb;
1471     IRpcStubBuffer *stub;
1472     ULONG refs;
1473     CLSID clsid;
1474
1475     cLocks = 0;
1476
1477     hr = CoGetPSClsid(riid, &clsid);
1478     ok_ole_success(hr, CoGetPSClsid);
1479
1480     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1481     ok_ole_success(hr, CoGetClassObject);
1482
1483     hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
1484     ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
1485
1486     refs = IPSFactoryBuffer_Release(psfb);
1487 #if 0 /* not reliable on native. maybe it leaks references */
1488     ok(refs == 0, "Ref-count leak of %ld on IPSFactoryBuffer\n", refs);
1489 #endif
1490
1491     ok_more_than_one_lock();
1492
1493     IRpcStubBuffer_Disconnect(stub);
1494
1495     ok_no_locks();
1496
1497     refs = IRpcStubBuffer_Release(stub);
1498     ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
1499 }
1500
1501 static HWND hwnd_app;
1502
1503 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
1504     LPCLASSFACTORY iface,
1505     LPUNKNOWN pUnkOuter,
1506     REFIID riid,
1507     LPVOID *ppvObj)
1508 {
1509     DWORD_PTR res;
1510     if (IsEqualIID(riid, &IID_IWineTest))
1511     {
1512         BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
1513         ok(ret, "Timed out sending a message to originating window during RPC call\n");
1514     }
1515     return S_FALSE;
1516 }
1517
1518 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
1519 {
1520     Test_IClassFactory_QueryInterface,
1521     Test_IClassFactory_AddRef,
1522     Test_IClassFactory_Release,
1523     TestRE_IClassFactory_CreateInstance,
1524     Test_IClassFactory_LockServer
1525 };
1526
1527 IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
1528
1529 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1530 {
1531     switch (msg)
1532     {
1533     case WM_USER:
1534     {
1535         HRESULT hr;
1536         IStream *pStream = NULL;
1537         IClassFactory *proxy = NULL;
1538         IUnknown *object;
1539         DWORD tid;
1540         HANDLE thread;
1541
1542         cLocks = 0;
1543
1544         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1545         ok_ole_success(hr, CreateStreamOnHGlobal);
1546         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1547
1548         ok_more_than_one_lock();
1549
1550         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1551         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1552         ok_ole_success(hr, CoReleaseMarshalData);
1553         IStream_Release(pStream);
1554
1555         ok_more_than_one_lock();
1556
1557         /* note the use of the magic IID_IWineTest value to tell remote thread
1558          * to try to send a message back to us */
1559         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IWineTest, (void **)&object);
1560
1561         IClassFactory_Release(proxy);
1562
1563         ok_no_locks();
1564
1565         end_host_object(tid, thread);
1566
1567         PostMessage(hwnd, WM_QUIT, 0, 0);
1568
1569         return 0;
1570     }
1571     case WM_USER+1:
1572     {
1573         HRESULT hr;
1574         IStream *pStream = NULL;
1575         IClassFactory *proxy = NULL;
1576         IUnknown *object;
1577         DWORD tid;
1578         HANDLE thread;
1579
1580         cLocks = 0;
1581
1582         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1583         ok_ole_success(hr, CreateStreamOnHGlobal);
1584         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1585
1586         ok_more_than_one_lock();
1587
1588         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1589         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1590         ok_ole_success(hr, CoReleaseMarshalData);
1591         IStream_Release(pStream);
1592
1593         ok_more_than_one_lock();
1594
1595         /* post quit message before a doing a COM call to show that a pending
1596         * WM_QUIT message doesn't stop the call from succeeding */
1597         PostMessage(hwnd, WM_QUIT, 0, 0);
1598         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1599
1600         IClassFactory_Release(proxy);
1601
1602         ok_no_locks();
1603
1604         end_host_object(tid, thread);
1605
1606         return 0;
1607     }
1608     default:
1609         return DefWindowProc(hwnd, msg, wparam, lparam);
1610     }
1611 }
1612
1613 static void test_message_reentrancy(void)
1614 {
1615     WNDCLASS wndclass;
1616     MSG msg;
1617
1618     memset(&wndclass, 0, sizeof(wndclass));
1619     wndclass.lpfnWndProc = window_proc;
1620     wndclass.lpszClassName = "WineCOMTest";
1621     RegisterClass(&wndclass);
1622
1623     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1624     ok(hwnd_app != NULL, "Window creation failed\n");
1625
1626     /* start message re-entrancy test */
1627     PostMessage(hwnd_app, WM_USER, 0, 0);
1628
1629     while (GetMessage(&msg, NULL, 0, 0))
1630     {
1631         TranslateMessage(&msg);
1632         DispatchMessage(&msg);
1633     }
1634 }
1635
1636 static void test_WM_QUIT_handling(void)
1637 {
1638     MSG msg;
1639
1640     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1641     ok(hwnd_app != NULL, "Window creation failed\n");
1642
1643     /* start WM_QUIT handling test */
1644     PostMessage(hwnd_app, WM_USER+1, 0, 0);
1645
1646     while (GetMessage(&msg, NULL, 0, 0))
1647     {
1648         TranslateMessage(&msg);
1649         DispatchMessage(&msg);
1650     }
1651 }
1652
1653 static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void *ptr, DWORD mshlflags)
1654 {
1655     HGLOBAL hglobal;
1656     DWORD size;
1657     char *marshal_data;
1658     HRESULT hr;
1659
1660     hr = GetHGlobalFromStream(pStream, &hglobal);
1661     ok_ole_success(hr, GetHGlobalFromStream);
1662
1663     size = GlobalSize(hglobal);
1664
1665     marshal_data = (char *)GlobalLock(hglobal);
1666
1667     if (mshctx == MSHCTX_INPROC)
1668     {
1669         DWORD expected_size = sizeof(DWORD) + sizeof(void *) + sizeof(DWORD) + sizeof(GUID);
1670         ok(size == expected_size, "size should have been %ld instead of %ld\n", expected_size, size);
1671
1672         ok(*(DWORD *)marshal_data == mshlflags, "expected 0x%lx, but got 0x%lx for mshctx\n", mshlflags, *(DWORD *)marshal_data);
1673         marshal_data += sizeof(DWORD);
1674         ok(*(void **)marshal_data == ptr, "expected %p, but got %p for mshctx\n", ptr, *(void **)marshal_data);
1675         marshal_data += sizeof(void *);
1676         ok(*(DWORD *)marshal_data == 0, "expected 0x0, but got 0x%lx\n", *(DWORD *)marshal_data);
1677         marshal_data += sizeof(DWORD);
1678         trace("got guid data: {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
1679             ((GUID *)marshal_data)->Data1, ((GUID *)marshal_data)->Data2, ((GUID *)marshal_data)->Data3,
1680             ((GUID *)marshal_data)->Data4[0], ((GUID *)marshal_data)->Data4[1], ((GUID *)marshal_data)->Data4[2], ((GUID *)marshal_data)->Data4[3],
1681             ((GUID *)marshal_data)->Data4[4], ((GUID *)marshal_data)->Data4[5], ((GUID *)marshal_data)->Data4[6], ((GUID *)marshal_data)->Data4[7]);
1682     }
1683     else
1684     {
1685         ok(size > sizeof(DWORD), "size should have been > sizeof(DWORD), not %ld\n", size);
1686         ok(*(DWORD *)marshal_data == 0x574f454d /* MEOW */,
1687             "marshal data should be filled by standard marshal and start with MEOW signature\n");
1688     }
1689
1690     GlobalUnlock(hglobal);
1691 }
1692
1693 static void test_freethreadedmarshaler(void)
1694 {
1695     HRESULT hr;
1696     IUnknown *pFTUnknown;
1697     IMarshal *pFTMarshal;
1698     IStream *pStream;
1699     IUnknown *pProxy;
1700     static const LARGE_INTEGER llZero;
1701
1702     cLocks = 0;
1703     hr = CoCreateFreeThreadedMarshaler(NULL, &pFTUnknown);
1704     ok_ole_success(hr, CoCreateFreeThreadedMarshaler);
1705     hr = IUnknown_QueryInterface(pFTUnknown, &IID_IMarshal, (void **)&pFTMarshal);
1706     ok_ole_success(hr, IUnknown_QueryInterface);
1707     IUnknown_Release(pFTUnknown);
1708
1709     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1710     ok_ole_success(hr, CreateStreamOnHGlobal);
1711
1712     /* inproc normal marshaling */
1713
1714     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
1715         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1716     ok_ole_success(hr, IMarshal_MarshalInterface);
1717
1718     ok_more_than_one_lock();
1719
1720     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_NORMAL);
1721
1722     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1723     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
1724     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1725
1726     IUnknown_Release(pProxy);
1727
1728     ok_no_locks();
1729
1730 /* native doesn't allow us to unmarshal or release the stream data,
1731  * presumably because it wants us to call CoMarshalInterface instead */
1732 #if 0
1733     /* local normal marshaling */
1734
1735     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1736     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
1737     ok_ole_success(hr, IMarshal_MarshalInterface);
1738
1739     ok_more_than_one_lock();
1740
1741     test_freethreadedmarshaldata(pStream, MSHCTX_LOCAL, &Test_ClassFactory, MSHLFLAGS_NORMAL);
1742
1743     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1744     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
1745     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1746
1747     ok_no_locks();
1748 #endif
1749
1750     /* inproc table-strong marshaling */
1751
1752     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1753     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
1754         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
1755         MSHLFLAGS_TABLESTRONG);
1756     ok_ole_success(hr, IMarshal_MarshalInterface);
1757
1758     ok_more_than_one_lock();
1759
1760     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLESTRONG);
1761
1762     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1763     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
1764     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1765
1766     IUnknown_Release(pProxy);
1767
1768     ok_more_than_one_lock();
1769
1770     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1771     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
1772     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1773
1774     ok_no_locks();
1775
1776     /* inproc table-weak marshaling */
1777
1778     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1779     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
1780         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
1781         MSHLFLAGS_TABLEWEAK);
1782     ok_ole_success(hr, IMarshal_MarshalInterface);
1783
1784     ok_no_locks();
1785
1786     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLEWEAK);
1787
1788     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1789     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
1790     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1791
1792     ok_more_than_one_lock();
1793
1794     IUnknown_Release(pProxy);
1795
1796     ok_no_locks();
1797
1798     /* inproc normal marshaling (for extraordinary cases) */
1799
1800     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1801     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
1802         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1803     ok_ole_success(hr, IMarshal_MarshalInterface);
1804
1805     ok_more_than_one_lock();
1806
1807     /* this call shows that DisconnectObject does nothing */
1808     hr = IMarshal_DisconnectObject(pFTMarshal, 0);
1809     ok_ole_success(hr, IMarshal_DisconnectObject);
1810
1811     ok_more_than_one_lock();
1812
1813     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1814     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
1815     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1816
1817     ok_no_locks();
1818
1819     /* doesn't enforce marshaling rules here and allows us to unmarshal the
1820      * interface, even though it was freed above */
1821     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1822     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
1823     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1824
1825     ok_no_locks();
1826
1827     IStream_Release(pStream);
1828     IMarshal_Release(pFTMarshal);
1829 }
1830
1831 static HANDLE heventShutdown;
1832
1833 static void LockModuleOOP(void)
1834 {
1835     InterlockedIncrement(&cLocks); /* for test purposes only */
1836     CoAddRefServerProcess();
1837 }
1838
1839 static void UnlockModuleOOP(void)
1840 {
1841     InterlockedDecrement(&cLocks); /* for test purposes only */
1842     if (!CoReleaseServerProcess())
1843         SetEvent(heventShutdown);
1844 }
1845
1846 static HWND hwnd_app;
1847
1848 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
1849     LPCLASSFACTORY iface,
1850     REFIID riid,
1851     LPVOID *ppvObj)
1852 {
1853     if (ppvObj == NULL) return E_POINTER;
1854
1855     if (IsEqualGUID(riid, &IID_IUnknown) ||
1856         IsEqualGUID(riid, &IID_IClassFactory))
1857     {
1858         *ppvObj = (LPVOID)iface;
1859         IClassFactory_AddRef(iface);
1860         return S_OK;
1861     }
1862
1863     return E_NOINTERFACE;
1864 }
1865
1866 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
1867 {
1868     return 2; /* non-heap-based object */
1869 }
1870
1871 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
1872 {
1873     return 1; /* non-heap-based object */
1874 }
1875
1876 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
1877     LPCLASSFACTORY iface,
1878     LPUNKNOWN pUnkOuter,
1879     REFIID riid,
1880     LPVOID *ppvObj)
1881 {
1882     return CLASS_E_CLASSNOTAVAILABLE;
1883 }
1884
1885 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
1886     LPCLASSFACTORY iface,
1887     BOOL fLock)
1888 {
1889     if (fLock)
1890         LockModuleOOP();
1891     else
1892         UnlockModuleOOP();
1893     return S_OK;
1894 }
1895
1896 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
1897 {
1898     TestOOP_IClassFactory_QueryInterface,
1899     TestOOP_IClassFactory_AddRef,
1900     TestOOP_IClassFactory_Release,
1901     TestOOP_IClassFactory_CreateInstance,
1902     TestOOP_IClassFactory_LockServer
1903 };
1904
1905 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
1906
1907 /* tests functions commonly used by out of process COM servers */
1908 static void test_out_of_process_com(void)
1909 {
1910     static const CLSID CLSID_WineOOPTest = {
1911         0x5201163f,
1912         0x8164,
1913         0x4fd0,
1914         {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
1915     }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
1916     DWORD cookie;
1917     HRESULT hr;
1918     IClassFactory * cf;
1919     DWORD ret;
1920
1921     heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
1922
1923     cLocks = 0;
1924
1925     /* Start the object suspended */
1926     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
1927         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
1928     ok_ole_success(hr, CoRegisterClassObject);
1929
1930     /* ... and CoGetClassObject does not find it and fails when it looks for the
1931      * class in the registry */
1932     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1933         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1934     todo_wine {
1935     ok(hr == REGDB_E_CLASSNOTREG,
1936         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08lx\n", hr);
1937     }
1938
1939     /* Resume the object suspended above ... */
1940     hr = CoResumeClassObjects();
1941     ok_ole_success(hr, CoResumeClassObjects);
1942
1943     /* ... and now it should succeed */
1944     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1945         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1946     ok_ole_success(hr, CoGetClassObject);
1947
1948     /* Now check the locking is working */
1949     /* NOTE: we are accessing the class directly, not through a proxy */
1950
1951     ok_no_locks();
1952
1953     hr = IClassFactory_LockServer(cf, TRUE);
1954     trace("IClassFactory_LockServer returned 0x%08lx\n", hr);
1955
1956     ok_more_than_one_lock();
1957     
1958     IClassFactory_LockServer(cf, FALSE);
1959
1960     ok_no_locks();
1961
1962     IClassFactory_Release(cf);
1963
1964     /* wait for shutdown signal */
1965     ret = WaitForSingleObject(heventShutdown, 5000);
1966     todo_wine { ok(ret != WAIT_TIMEOUT, "Server didn't shut down or machine is under very heavy load\n"); }
1967
1968     /* try to connect again after SCM has suspended registered class objects */
1969     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
1970         &IID_IClassFactory, (LPVOID*)&cf);
1971     todo_wine {
1972     ok(hr == CO_E_SERVER_STOPPING,
1973         "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08lx\n", hr);
1974     }
1975
1976     hr = CoRevokeClassObject(cookie);
1977     ok_ole_success(hr, CoRevokeClassObject);
1978
1979     CloseHandle(heventShutdown);
1980 }
1981
1982 static void test_ROT(void)
1983 {
1984     static const WCHAR wszFileName[] = {'B','E','2','0','E','2','F','5','-',
1985         '1','9','0','3','-','4','A','A','E','-','B','1','A','F','-',
1986         '2','0','4','6','E','5','8','6','C','9','2','5',0};
1987     HRESULT hr;
1988     IMoniker *pMoniker = NULL;
1989     IRunningObjectTable *pROT = NULL;
1990     DWORD dwCookie;
1991
1992     cLocks = 0;
1993
1994     hr = CreateFileMoniker(wszFileName, &pMoniker);
1995     ok_ole_success(hr, CreateClassMoniker);
1996     hr = GetRunningObjectTable(0, &pROT);
1997     ok_ole_success(hr, GetRunningObjectTable);
1998     hr = IRunningObjectTable_Register(pROT, 0, (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
1999     ok_ole_success(hr, IRunningObjectTable_Register);
2000
2001     ok_more_than_one_lock();
2002
2003     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
2004     ok_ole_success(hr, IRunningObjectTable_Revoke);
2005
2006     ok_no_locks();
2007 }
2008
2009 struct git_params
2010 {
2011         DWORD cookie;
2012         IGlobalInterfaceTable *git;
2013 };
2014
2015 static DWORD CALLBACK get_global_interface_proc(LPVOID pv)
2016 {
2017         HRESULT hr;
2018         struct git_params *params = (struct git_params *)pv;
2019         IClassFactory *cf;
2020
2021         hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
2022         ok(hr == CO_E_NOTINITIALIZED,
2023                 "IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED instead of 0x%08lx\n",
2024                 hr);
2025
2026         CoInitialize(NULL);
2027         hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
2028         ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
2029         CoUninitialize();
2030
2031         return hr;
2032 }
2033
2034 static void test_globalinterfacetable(void)
2035 {
2036         HRESULT hr;
2037         IGlobalInterfaceTable *git;
2038         DWORD cookie;
2039         HANDLE thread;
2040         DWORD tid;
2041         struct git_params params;
2042         DWORD ret;
2043
2044         hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)&git);
2045         ok_ole_success(hr, CoCreateInstance);
2046
2047         hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&Test_ClassFactory, &IID_IClassFactory, &cookie);
2048         ok_ole_success(hr, IGlobalInterfaceTable_RegisterInterfaceInGlobal);
2049
2050         params.cookie = cookie;
2051         params.git = git;
2052         /* note: params is on stack so we MUST wait for get_global_interface_proc
2053          * to exit before we can return */
2054         thread = CreateThread(NULL, 0, get_global_interface_proc, &params, 0, &tid);
2055
2056         ret = MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT);
2057         while (ret == WAIT_OBJECT_0 + 1)
2058         {
2059                 MSG msg;
2060                 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
2061                         DispatchMessage(&msg);
2062                 ret = MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT);
2063         }
2064
2065         CloseHandle(thread);
2066 }
2067
2068 static const char cf_marshaled[] =
2069 {
2070     0x9, 0x0, 0x0, 0x0,
2071     0x0, 0x0, 0x0, 0x0,
2072     0x9, 0x0, 0x0, 0x0,
2073     'M', 0x0, 'y', 0x0,
2074     'F', 0x0, 'o', 0x0,
2075     'r', 0x0, 'm', 0x0,
2076     'a', 0x0, 't', 0x0,
2077     0x0, 0x0
2078 };
2079
2080 static void test_marshal_CLIPFORMAT(void)
2081 {
2082     unsigned char *buffer;
2083     unsigned long size;
2084     unsigned long flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
2085     wireCLIPFORMAT wirecf;
2086     CLIPFORMAT cf = RegisterClipboardFormatA("MyFormat");
2087     CLIPFORMAT cf2;
2088
2089     size = CLIPFORMAT_UserSize(&flags, 0, &cf);
2090     ok(size == sizeof(*wirecf) + sizeof(cf_marshaled), "Wrong size %ld\n", size);
2091
2092     buffer = HeapAlloc(GetProcessHeap(), 0, size);
2093     CLIPFORMAT_UserMarshal(&flags, buffer, &cf);
2094     wirecf = (wireCLIPFORMAT)buffer;
2095     ok(wirecf->fContext == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08lx\n", wirecf->fContext);
2096     ok(wirecf->u.dwValue == cf, "Marshaled value should be 0x%04x instead of 0x%04lx\n", cf, wirecf->u.dwValue);
2097     ok(!memcmp(wirecf+1, cf_marshaled, sizeof(cf_marshaled)), "Marshaled data differs\n");
2098
2099     CLIPFORMAT_UserUnmarshal(&flags, buffer, &cf2);
2100     ok(cf == cf2, "Didn't unmarshal properly\n");
2101     HeapFree(GetProcessHeap(), 0, buffer);
2102
2103     CLIPFORMAT_UserFree(&flags, &cf2);
2104 }
2105
2106 static void test_marshal_HWND(void)
2107 {
2108     unsigned char *buffer;
2109     unsigned long size;
2110     unsigned long flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION);
2111     HWND hwnd = GetDesktopWindow();
2112     HWND hwnd2;
2113     wireHWND wirehwnd;
2114
2115     size = HWND_UserSize(&flags, 0, &hwnd);
2116     ok(size == sizeof(*wirehwnd), "Wrong size %ld\n", size);
2117
2118     buffer = HeapAlloc(GetProcessHeap(), 0, size);
2119     HWND_UserMarshal(&flags, buffer, &hwnd);
2120     wirehwnd = (wireHWND)buffer;
2121     ok(wirehwnd->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08lx\n", wirehwnd->fContext);
2122     ok(wirehwnd->u.hInproc == (LONG_PTR)hwnd, "Marshaled value should be %p instead of %p\n", hwnd, (HANDLE)wirehwnd->u.hRemote);
2123
2124     HWND_UserUnmarshal(&flags, buffer, &hwnd2);
2125     ok(hwnd == hwnd2, "Didn't unmarshal properly\n");
2126     HeapFree(GetProcessHeap(), 0, buffer);
2127
2128     HWND_UserFree(&flags, &hwnd2);
2129 }
2130
2131 static void test_marshal_HGLOBAL(void)
2132 {
2133     unsigned char *buffer;
2134     unsigned long size;
2135     unsigned long flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION);
2136     HGLOBAL hglobal;
2137     HGLOBAL hglobal2;
2138     unsigned char *wirehglobal;
2139     int i;
2140
2141     hglobal = NULL;
2142     flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION);
2143     size = HGLOBAL_UserSize(&flags, 0, &hglobal);
2144     /* native is poorly programmed and allocates 4 bytes more than it needs to
2145      * here - Wine doesn't have to emulate that */
2146     ok((size == 8) || (size == 12), "Size should be 12, instead of %ld\n", size);
2147     buffer = HeapAlloc(GetProcessHeap(), 0, size);
2148     HGLOBAL_UserMarshal(&flags, buffer, &hglobal);
2149     wirehglobal = buffer;
2150     ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08lx\n", *(ULONG *)wirehglobal);
2151     wirehglobal += sizeof(ULONG);
2152     ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+4 should be HGLOBAL\n");
2153     HGLOBAL_UserUnmarshal(&flags, buffer, &hglobal2);
2154     ok(hglobal2 == hglobal, "Didn't unmarshal properly\n");
2155     HeapFree(GetProcessHeap(), 0, buffer);
2156     HGLOBAL_UserFree(&flags, &hglobal2);
2157
2158     hglobal = GlobalAlloc(0, 4);
2159     buffer = GlobalLock(hglobal);
2160     for (i = 0; i < 4; i++)
2161         buffer[i] = i;
2162     GlobalUnlock(hglobal);
2163     flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION);
2164     size = HGLOBAL_UserSize(&flags, 0, &hglobal);
2165     /* native is poorly programmed and allocates 4 bytes more than it needs to
2166      * here - Wine doesn't have to emulate that */
2167     ok((size == 24) || (size == 28), "Size should be 24 or 28, instead of %ld\n", size);
2168     buffer = HeapAlloc(GetProcessHeap(), 0, size);
2169     HGLOBAL_UserMarshal(&flags, buffer, &hglobal);
2170     wirehglobal = buffer;
2171     ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08lx\n", *(ULONG *)wirehglobal);
2172     wirehglobal += sizeof(ULONG);
2173     ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+0x4 should be HGLOBAL\n");
2174     wirehglobal += sizeof(ULONG);
2175     ok(*(ULONG *)wirehglobal == 4, "buffer+0x8 should be size of HGLOBAL\n");
2176     wirehglobal += sizeof(ULONG);
2177     ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+0xc should be HGLOBAL\n");
2178     wirehglobal += sizeof(ULONG);
2179     ok(*(ULONG *)wirehglobal == 4, "buffer+0x10 should be size of HGLOBAL\n");
2180     wirehglobal += sizeof(ULONG);
2181     for (i = 0; i < 4; i++)
2182         ok(wirehglobal[i] == i, "buffer+0x%x should be %d\n", 0x10 + i, i);
2183     HGLOBAL_UserUnmarshal(&flags, buffer, &hglobal2);
2184     ok(hglobal2 != NULL, "Didn't unmarshal properly\n");
2185     HeapFree(GetProcessHeap(), 0, buffer);
2186     HGLOBAL_UserFree(&flags, &hglobal2);
2187     GlobalFree(hglobal);
2188 }
2189
2190 static HENHMETAFILE create_emf(void)
2191 {
2192     RECT rect = {0, 0, 100, 100};
2193     HDC hdc = CreateEnhMetaFile(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0");
2194     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, NULL, "Test String", strlen("Test String"), NULL);
2195     return CloseEnhMetaFile(hdc);
2196 }
2197
2198 static void test_marshal_HENHMETAFILE(void)
2199 {
2200     unsigned char *buffer;
2201     unsigned long size;
2202     unsigned long flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
2203     HENHMETAFILE hemf;
2204     HENHMETAFILE hemf2 = NULL;
2205     unsigned char *wirehemf;
2206
2207     hemf = create_emf();
2208
2209     size = HENHMETAFILE_UserSize(&flags, 0, &hemf);
2210     ok(size > 20, "size should be at least 20 bytes, not %ld\n", size);
2211     buffer = HeapAlloc(GetProcessHeap(), 0, size);
2212     HENHMETAFILE_UserMarshal(&flags, buffer, &hemf);
2213     wirehemf = buffer;
2214     ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08lx\n", *(DWORD *)wirehemf);
2215     wirehemf += sizeof(DWORD);
2216     ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08lx\n", *(DWORD *)wirehemf);
2217     wirehemf += sizeof(DWORD);
2218     ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08lx\n", *(DWORD *)wirehemf);
2219     wirehemf += sizeof(DWORD);
2220     ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08lx\n", *(DWORD *)wirehemf);
2221     wirehemf += sizeof(DWORD);
2222     ok(*(DWORD *)wirehemf == EMR_HEADER, "wirestgm + 0x10 should be EMR_HEADER instead of %ld\n", *(DWORD *)wirehemf);
2223     wirehemf += sizeof(DWORD);
2224     /* ... rest of data not tested - refer to tests for GetEnhMetaFileBits
2225      * at this point */
2226
2227     HENHMETAFILE_UserUnmarshal(&flags, buffer, &hemf2);
2228     ok(hemf2 != NULL, "HENHMETAFILE didn't unmarshal\n");
2229     HeapFree(GetProcessHeap(), 0, buffer);
2230     HENHMETAFILE_UserFree(&flags, &hemf2);
2231     DeleteEnhMetaFile(hemf);
2232
2233     /* test NULL emf */
2234     hemf = NULL;
2235
2236     size = HENHMETAFILE_UserSize(&flags, 0, &hemf);
2237     ok(size == 8, "size should be 8 bytes, not %ld\n", size);
2238     buffer = (unsigned char *)HeapAlloc(GetProcessHeap(), 0, size);
2239     HENHMETAFILE_UserMarshal(&flags, buffer, &hemf);
2240     wirehemf = buffer;
2241     ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08lx\n", *(DWORD *)wirehemf);
2242     wirehemf += sizeof(DWORD);
2243     ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08lx\n", *(DWORD *)wirehemf);
2244     wirehemf += sizeof(DWORD);
2245
2246     HENHMETAFILE_UserUnmarshal(&flags, buffer, &hemf2);
2247     ok(hemf2 == NULL, "NULL HENHMETAFILE didn't unmarshal\n");
2248     HeapFree(GetProcessHeap(), 0, buffer);
2249     HENHMETAFILE_UserFree(&flags, &hemf2);
2250 }
2251
2252 START_TEST(marshal)
2253 {
2254     WNDCLASS wndclass;
2255     HMODULE hOle32 = GetModuleHandle("ole32");
2256     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
2257
2258     /* register a window class used in several tests */
2259     memset(&wndclass, 0, sizeof(wndclass));
2260     wndclass.lpfnWndProc = window_proc;
2261     wndclass.lpszClassName = "WineCOMTest";
2262     RegisterClass(&wndclass);
2263
2264     test_cocreateinstance_proxy();
2265
2266     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2267
2268     /* FIXME: test CoCreateInstanceEx */
2269
2270     /* lifecycle management and marshaling tests */
2271     test_no_marshaler();
2272     test_normal_marshal_and_release();
2273     test_normal_marshal_and_unmarshal();
2274     test_marshal_and_unmarshal_invalid();
2275     test_interthread_marshal_and_unmarshal();
2276     test_proxy_marshal_and_unmarshal();
2277     test_proxy_marshal_and_unmarshal2();
2278     test_marshal_stub_apartment_shutdown();
2279     test_marshal_proxy_apartment_shutdown();
2280     test_marshal_proxy_mta_apartment_shutdown();
2281     test_no_couninitialize_server();
2282     test_no_couninitialize_client();
2283     test_tableweak_marshal_and_unmarshal_twice();
2284     test_tableweak_marshal_releasedata1();
2285     test_tableweak_marshal_releasedata2();
2286     test_tablestrong_marshal_and_unmarshal_twice();
2287     test_lock_object_external();
2288     test_disconnect_stub();
2289     test_normal_marshal_and_unmarshal_twice();
2290     test_hresult_marshaling();
2291     test_proxy_used_in_wrong_thread();
2292     test_message_filter();
2293     test_bad_marshal_stream();
2294     test_proxy_interfaces();
2295     test_stubbuffer(&IID_IClassFactory);
2296     test_proxybuffer(&IID_IClassFactory);
2297     test_message_reentrancy();
2298     test_WM_QUIT_handling();
2299     test_freethreadedmarshaler();
2300
2301     /* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
2302     if (0) test_out_of_process_com();
2303
2304     test_ROT();
2305     test_globalinterfacetable();
2306
2307     test_marshal_CLIPFORMAT();
2308     test_marshal_HWND();
2309     test_marshal_HGLOBAL();
2310     test_marshal_HENHMETAFILE();
2311
2312     CoUninitialize();
2313     return;
2314
2315 no_test:
2316     trace("You need DCOM95 installed to run this test\n");
2317     return;
2318 }