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