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