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