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