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