ole: Verify that the proxy is being used in the correct thread.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 that stubs are released when the containing apartment is destroyed */
476 static void test_marshal_stub_apartment_shutdown(void)
477 {
478     HRESULT hr;
479     IStream *pStream = NULL;
480     IUnknown *pProxy = NULL;
481     DWORD tid;
482     HANDLE thread;
483
484     cLocks = 0;
485
486     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
487     ok_ole_success(hr, CreateStreamOnHGlobal);
488     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
489
490     ok_more_than_one_lock();
491     
492     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
493     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
494     ok_ole_success(hr, CoUnmarshalInterface);
495     IStream_Release(pStream);
496
497     ok_more_than_one_lock();
498
499     end_host_object(tid, thread);
500
501     ok_no_locks();
502
503     IUnknown_Release(pProxy);
504
505     ok_no_locks();
506 }
507
508 /* tests that proxies are released when the containing apartment is destroyed */
509 static void test_marshal_proxy_apartment_shutdown(void)
510 {
511     HRESULT hr;
512     IStream *pStream = NULL;
513     IUnknown *pProxy = NULL;
514     DWORD tid;
515     HANDLE thread;
516
517     cLocks = 0;
518
519     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
520     ok_ole_success(hr, CreateStreamOnHGlobal);
521     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
522
523     ok_more_than_one_lock();
524     
525     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
526     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
527     ok_ole_success(hr, CoUnmarshalInterface);
528     IStream_Release(pStream);
529
530     ok_more_than_one_lock();
531
532     CoUninitialize();
533
534     ok_no_locks();
535
536     IUnknown_Release(pProxy);
537
538     ok_no_locks();
539
540     end_host_object(tid, thread);
541
542     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
543 }
544
545 /* tests that proxies are released when the containing mta apartment is destroyed */
546 static void test_marshal_proxy_mta_apartment_shutdown(void)
547 {
548     HRESULT hr;
549     IStream *pStream = NULL;
550     IUnknown *pProxy = NULL;
551     DWORD tid;
552     HANDLE thread;
553
554     CoUninitialize();
555     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
556
557     cLocks = 0;
558
559     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
560     ok_ole_success(hr, CreateStreamOnHGlobal);
561     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
562
563     ok_more_than_one_lock();
564
565     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
566     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
567     ok_ole_success(hr, CoUnmarshalInterface);
568     IStream_Release(pStream);
569
570     ok_more_than_one_lock();
571
572     CoUninitialize();
573
574     ok_no_locks();
575
576     IUnknown_Release(pProxy);
577
578     ok_no_locks();
579
580     end_host_object(tid, thread);
581
582     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
583 }
584
585 struct ncu_params
586 {
587     LPSTREAM stream;
588     HANDLE marshal_event;
589     HANDLE unmarshal_event;
590 };
591
592 /* helper for test_no_couninitialize_server */
593 static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p)
594 {
595     struct ncu_params *ncu_params = (struct ncu_params *)p;
596     HRESULT hr;
597
598     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
599
600     hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
601     ok_ole_success(hr, CoMarshalInterface);
602
603     SetEvent(ncu_params->marshal_event);
604
605     WaitForSingleObject(ncu_params->unmarshal_event, INFINITE);
606
607     /* die without calling CoUninitialize */
608
609     return 0;
610 }
611
612 /* tests apartment that an apartment with a stub is released without deadlock
613  * if the owning thread exits */
614 static void test_no_couninitialize_server(void)
615 {
616     HRESULT hr;
617     IStream *pStream = NULL;
618     IUnknown *pProxy = NULL;
619     DWORD tid;
620     HANDLE thread;
621     struct ncu_params ncu_params;
622
623     cLocks = 0;
624
625     ncu_params.marshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
626     ncu_params.unmarshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
627
628     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
629     ok_ole_success(hr, CreateStreamOnHGlobal);
630     ncu_params.stream = pStream;
631
632     thread = CreateThread(NULL, 0, no_couninitialize_server_proc, &ncu_params, 0, &tid);
633
634     WaitForSingleObject(ncu_params.marshal_event, INFINITE);
635     ok_more_than_one_lock();
636
637     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
638     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
639     ok_ole_success(hr, CoUnmarshalInterface);
640     IStream_Release(pStream);
641
642     ok_more_than_one_lock();
643
644     SetEvent(ncu_params.unmarshal_event);
645     WaitForSingleObject(thread, INFINITE);
646
647     ok_no_locks();
648
649     CloseHandle(thread);
650     CloseHandle(ncu_params.marshal_event);
651     CloseHandle(ncu_params.unmarshal_event);
652
653     IUnknown_Release(pProxy);
654
655     ok_no_locks();
656 }
657
658 /* STA -> STA call during DLL_THREAD_DETACH */
659 static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p)
660 {
661     struct ncu_params *ncu_params = (struct ncu_params *)p;
662     HRESULT hr;
663     IUnknown *pProxy = NULL;
664
665     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
666
667     hr = CoUnmarshalInterface(ncu_params->stream, &IID_IClassFactory, (void **)&pProxy);
668     ok_ole_success(hr, CoUnmarshalInterface);
669
670     ok_more_than_one_lock();
671
672     /* die without calling CoUninitialize */
673
674     return 0;
675 }
676
677 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
678 static void test_no_couninitialize_client(void)
679 {
680     HRESULT hr;
681     IStream *pStream = NULL;
682     DWORD tid;
683     DWORD host_tid;
684     HANDLE thread;
685     HANDLE host_thread;
686     struct ncu_params ncu_params;
687
688     cLocks = 0;
689
690     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
691     ok_ole_success(hr, CreateStreamOnHGlobal);
692     ncu_params.stream = pStream;
693
694     /* NOTE: assumes start_host_object uses an STA to host the object, as MTAs
695      * always deadlock when called from within DllMain */
696     host_tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
697     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
698
699     ok_more_than_one_lock();
700
701     thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
702
703     WaitForSingleObject(thread, INFINITE);
704     CloseHandle(thread);
705
706     ok_no_locks();
707
708     end_host_object(host_tid, host_thread);
709 }
710
711 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
712 static void test_tableweak_marshal_and_unmarshal_twice(void)
713 {
714     HRESULT hr;
715     IStream *pStream = NULL;
716     IUnknown *pProxy1 = NULL;
717     IUnknown *pProxy2 = NULL;
718     DWORD tid;
719     HANDLE thread;
720
721     cLocks = 0;
722
723     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
724     ok_ole_success(hr, CreateStreamOnHGlobal);
725     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
726
727     ok_more_than_one_lock();
728
729     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
730     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
731     ok_ole_success(hr, CoUnmarshalInterface);
732
733     ok_more_than_one_lock();
734
735     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
736     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
737     ok_ole_success(hr, CoUnmarshalInterface);
738
739     ok_more_than_one_lock();
740
741     IUnknown_Release(pProxy1);
742     IUnknown_Release(pProxy2);
743
744     /* this line is shows the difference between weak and strong table marshaling:
745      *  weak has cLocks == 0
746      *  strong has cLocks > 0 */
747     ok_no_locks();
748
749     end_host_object(tid, thread);
750 }
751
752 /* tests releasing after unmarshaling one object */
753 static void test_tableweak_marshal_releasedata1(void)
754 {
755     HRESULT hr;
756     IStream *pStream = NULL;
757     IUnknown *pProxy1 = NULL;
758     IUnknown *pProxy2 = NULL;
759     DWORD tid;
760     HANDLE thread;
761
762     cLocks = 0;
763
764     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
765     ok_ole_success(hr, CreateStreamOnHGlobal);
766     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
767
768     ok_more_than_one_lock();
769
770     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
771     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
772     ok_ole_success(hr, CoUnmarshalInterface);
773
774     ok_more_than_one_lock();
775
776     /* release the remaining reference on the object by calling
777      * CoReleaseMarshalData in the hosting thread */
778     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
779     release_host_object(tid);
780
781     ok_more_than_one_lock();
782
783     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
784     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
785     ok_ole_success(hr, CoUnmarshalInterface);
786     IStream_Release(pStream);
787
788     ok_more_than_one_lock();
789
790     IUnknown_Release(pProxy1);
791     if (pProxy2)
792         IUnknown_Release(pProxy2);
793
794     /* this line is shows the difference between weak and strong table marshaling:
795      *  weak has cLocks == 0
796      *  strong has cLocks > 0 */
797     ok_no_locks();
798
799     end_host_object(tid, thread);
800 }
801
802 /* tests releasing after unmarshaling one object */
803 static void test_tableweak_marshal_releasedata2(void)
804 {
805     HRESULT hr;
806     IStream *pStream = NULL;
807     IUnknown *pProxy = NULL;
808     DWORD tid;
809     HANDLE thread;
810
811     cLocks = 0;
812
813     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
814     ok_ole_success(hr, CreateStreamOnHGlobal);
815     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
816
817     ok_more_than_one_lock();
818
819     /* release the remaining reference on the object by calling
820      * CoReleaseMarshalData in the hosting thread */
821     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
822     release_host_object(tid);
823
824     ok_no_locks();
825
826     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
827     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
828     todo_wine
829     {
830     ok(hr == CO_E_OBJNOTREG,
831        "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08lx instead\n",
832        hr);
833     }
834     IStream_Release(pStream);
835
836     ok_no_locks();
837
838     end_host_object(tid, thread);
839 }
840
841 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
842 static void test_tablestrong_marshal_and_unmarshal_twice(void)
843 {
844     HRESULT hr;
845     IStream *pStream = NULL;
846     IUnknown *pProxy1 = NULL;
847     IUnknown *pProxy2 = NULL;
848     DWORD tid;
849     HANDLE thread;
850
851     cLocks = 0;
852
853     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
854     ok_ole_success(hr, CreateStreamOnHGlobal);
855     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
856
857     ok_more_than_one_lock();
858
859     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
860     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
861     ok_ole_success(hr, CoUnmarshalInterface);
862
863     ok_more_than_one_lock();
864
865     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
866     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
867     ok_ole_success(hr, CoUnmarshalInterface);
868
869     ok_more_than_one_lock();
870
871     if (pProxy1) IUnknown_Release(pProxy1);
872     if (pProxy2) IUnknown_Release(pProxy2);
873
874     /* this line is shows the difference between weak and strong table marshaling:
875      *  weak has cLocks == 0
876      *  strong has cLocks > 0 */
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     IStream_Release(pStream);
884
885     ok_no_locks();
886
887     end_host_object(tid, thread);
888 }
889
890 /* tests CoLockObjectExternal */
891 static void test_lock_object_external(void)
892 {
893     HRESULT hr;
894     IStream *pStream = NULL;
895
896     cLocks = 0;
897
898     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
899     ok_ole_success(hr, CreateStreamOnHGlobal);
900     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
901     ok_ole_success(hr, CoMarshalInterface);
902
903     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
904
905     ok_more_than_one_lock();
906     
907     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
908     hr = CoReleaseMarshalData(pStream);
909     ok_ole_success(hr, CoReleaseMarshalData);
910     IStream_Release(pStream);
911
912     ok_more_than_one_lock();
913
914     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
915
916     ok_no_locks();
917 }
918
919 /* tests disconnecting stubs */
920 static void test_disconnect_stub(void)
921 {
922     HRESULT hr;
923     IStream *pStream = NULL;
924
925     cLocks = 0;
926
927     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
928     ok_ole_success(hr, CreateStreamOnHGlobal);
929     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
930     ok_ole_success(hr, CoMarshalInterface);
931
932     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
933
934     ok_more_than_one_lock();
935     
936     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
937     hr = CoReleaseMarshalData(pStream);
938     ok_ole_success(hr, CoReleaseMarshalData);
939     IStream_Release(pStream);
940
941     ok_more_than_one_lock();
942
943     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
944
945     ok_no_locks();
946 }
947
948 /* tests failure case of a same-thread marshal and unmarshal twice */
949 static void test_normal_marshal_and_unmarshal_twice(void)
950 {
951     HRESULT hr;
952     IStream *pStream = NULL;
953     IUnknown *pProxy1 = NULL;
954     IUnknown *pProxy2 = 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     ok_more_than_one_lock();
964     
965     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
966     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
967     ok_ole_success(hr, CoUnmarshalInterface);
968
969     ok_more_than_one_lock();
970
971     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
972     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
973     ok(hr == CO_E_OBJNOTCONNECTED,
974         "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08lx\n", hr);
975
976     IStream_Release(pStream);
977
978     ok_more_than_one_lock();
979
980     IUnknown_Release(pProxy1);
981
982     ok_no_locks();
983 }
984
985 /* tests success case of marshaling and unmarshaling an HRESULT */
986 static void test_hresult_marshaling(void)
987 {
988     HRESULT hr;
989     HRESULT hr_marshaled = 0;
990     IStream *pStream = NULL;
991     static const HRESULT E_DEADBEEF = 0xdeadbeef;
992
993     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
994     ok_ole_success(hr, CreateStreamOnHGlobal);
995
996     hr = CoMarshalHresult(pStream, E_DEADBEEF);
997     ok_ole_success(hr, CoMarshalHresult);
998
999     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1000     hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
1001     ok_ole_success(hr, IStream_Read);
1002
1003     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
1004
1005     hr_marshaled = 0;
1006     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1007     hr = CoUnmarshalHresult(pStream, &hr_marshaled);
1008     ok_ole_success(hr, CoUnmarshalHresult);
1009
1010     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
1011
1012     IStream_Release(pStream);
1013 }
1014
1015
1016 /* helper for test_proxy_used_in_wrong_thread */
1017 static DWORD CALLBACK bad_thread_proc(LPVOID p)
1018 {
1019     IClassFactory * cf = (IClassFactory *)p;
1020     HRESULT hr;
1021     IUnknown * proxy = NULL;
1022
1023     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1024
1025     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1026     if (proxy) IUnknown_Release(proxy);
1027     ok(hr == RPC_E_WRONG_THREAD,
1028         "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n",
1029         hr);
1030
1031     CoUninitialize();
1032
1033     return 0;
1034 }
1035
1036 /* tests failure case of a using a proxy in the wrong apartment */
1037 static void test_proxy_used_in_wrong_thread(void)
1038 {
1039     HRESULT hr;
1040     IStream *pStream = NULL;
1041     IUnknown *pProxy = NULL;
1042     DWORD tid, tid2;
1043     HANDLE thread;
1044     HANDLE host_thread;
1045
1046     cLocks = 0;
1047
1048     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1049     ok_ole_success(hr, CreateStreamOnHGlobal);
1050     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
1051
1052     ok_more_than_one_lock();
1053     
1054     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1055     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1056     ok_ole_success(hr, CoUnmarshalInterface);
1057     IStream_Release(pStream);
1058
1059     ok_more_than_one_lock();
1060
1061     /* create a thread that we can misbehave in */
1062     thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
1063
1064     WaitForSingleObject(thread, INFINITE);
1065     CloseHandle(thread);
1066
1067     IUnknown_Release(pProxy);
1068
1069     ok_no_locks();
1070
1071     end_host_object(tid, host_thread);
1072 }
1073
1074 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
1075 {
1076     if (ppvObj == NULL) return E_POINTER;
1077
1078     if (IsEqualGUID(riid, &IID_IUnknown) ||
1079         IsEqualGUID(riid, &IID_IClassFactory))
1080     {
1081         *ppvObj = (LPVOID)iface;
1082         IClassFactory_AddRef(iface);
1083         return S_OK;
1084     }
1085
1086     return E_NOINTERFACE;
1087 }
1088
1089 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
1090 {
1091     return 2; /* non-heap object */
1092 }
1093
1094 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
1095 {
1096     return 1; /* non-heap object */
1097 }
1098
1099 static DWORD WINAPI MessageFilter_HandleInComingCall(
1100   IMessageFilter *iface,
1101   DWORD dwCallType,
1102   HTASK threadIDCaller,
1103   DWORD dwTickCount,
1104   LPINTERFACEINFO lpInterfaceInfo)
1105 {
1106     static int callcount = 0;
1107     DWORD ret;
1108     trace("HandleInComingCall\n");
1109     switch (callcount)
1110     {
1111     case 0:
1112         ret = SERVERCALL_REJECTED;
1113         break;
1114     case 1:
1115         ret = SERVERCALL_RETRYLATER;
1116         break;
1117     default:
1118         ret = SERVERCALL_ISHANDLED;
1119         break;
1120     }
1121     callcount++;
1122     return ret;
1123 }
1124
1125 static DWORD WINAPI MessageFilter_RetryRejectedCall(
1126   IMessageFilter *iface,
1127   HTASK threadIDCallee,
1128   DWORD dwTickCount,
1129   DWORD dwRejectType)
1130 {
1131     trace("RetryRejectedCall\n");
1132     return 0;
1133 }
1134
1135 static DWORD WINAPI MessageFilter_MessagePending(
1136   IMessageFilter *iface,
1137   HTASK threadIDCallee,
1138   DWORD dwTickCount,
1139   DWORD dwPendingType)
1140 {
1141     trace("MessagePending\n");
1142     return PENDINGMSG_WAITNOPROCESS;
1143 }
1144
1145 static const IMessageFilterVtbl MessageFilter_Vtbl =
1146 {
1147     MessageFilter_QueryInterface,
1148     MessageFilter_AddRef,
1149     MessageFilter_Release,
1150     MessageFilter_HandleInComingCall,
1151     MessageFilter_RetryRejectedCall,
1152     MessageFilter_MessagePending
1153 };
1154
1155 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
1156
1157 static void test_message_filter(void)
1158 {
1159     HRESULT hr;
1160     IStream *pStream = NULL;
1161     IClassFactory *cf = NULL;
1162     DWORD tid;
1163     IUnknown *proxy = NULL;
1164     IMessageFilter *prev_filter = NULL;
1165     HANDLE thread;
1166
1167     cLocks = 0;
1168
1169     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1170     ok_ole_success(hr, CreateStreamOnHGlobal);
1171     tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
1172
1173     ok_more_than_one_lock();
1174
1175     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1176     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
1177     ok_ole_success(hr, CoUnmarshalInterface);
1178     IStream_Release(pStream);
1179
1180     ok_more_than_one_lock();
1181
1182     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1183     todo_wine { ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08lx instead\n", hr); }
1184     if (proxy) IUnknown_Release(proxy);
1185     proxy = NULL;
1186
1187     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
1188     ok_ole_success(hr, CoRegisterMessageFilter);
1189     if (prev_filter) IMessageFilter_Release(prev_filter);
1190
1191     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1192     ok_ole_success(hr, IClassFactory_CreateInstance);
1193
1194     IUnknown_Release(proxy);
1195
1196     IClassFactory_Release(cf);
1197
1198     ok_no_locks();
1199
1200     end_host_object(tid, thread);
1201 }
1202
1203 /* test failure case of trying to unmarshal from bad stream */
1204 static void test_bad_marshal_stream(void)
1205 {
1206     HRESULT hr;
1207     IStream *pStream = NULL;
1208
1209     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1210     ok_ole_success(hr, CreateStreamOnHGlobal);
1211     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1212     ok_ole_success(hr, CoMarshalInterface);
1213
1214     ok_more_than_one_lock();
1215
1216     /* try to read beyond end of stream */
1217     hr = CoReleaseMarshalData(pStream);
1218     ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08lx instead\n", hr);
1219
1220     /* now release for real */
1221     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1222     hr = CoReleaseMarshalData(pStream);
1223     ok_ole_success(hr, CoReleaseMarshalData);
1224
1225     IStream_Release(pStream);
1226 }
1227
1228 /* tests that proxies implement certain interfaces */
1229 static void test_proxy_interfaces(void)
1230 {
1231     HRESULT hr;
1232     IStream *pStream = NULL;
1233     IUnknown *pProxy = NULL;
1234     IUnknown *pOtherUnknown = NULL;
1235     DWORD tid;
1236     HANDLE thread;
1237
1238     cLocks = 0;
1239
1240     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1241     ok_ole_success(hr, CreateStreamOnHGlobal);
1242     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1243
1244     ok_more_than_one_lock();
1245         
1246     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1247     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1248     ok_ole_success(hr, CoUnmarshalInterface);
1249     IStream_Release(pStream);
1250
1251     ok_more_than_one_lock();
1252
1253     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
1254     ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
1255     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1256
1257     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
1258     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity); }
1259     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1260
1261     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
1262     ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
1263     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1264
1265     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
1266     ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal);
1267     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1268
1269     /* IMarshal2 is also supported on NT-based systems, but is pretty much
1270      * useless as it has no more methods over IMarshal that it inherits from. */
1271
1272     IUnknown_Release(pProxy);
1273
1274     ok_no_locks();
1275
1276     end_host_object(tid, thread);
1277 }
1278
1279 typedef struct
1280 {
1281     const IUnknownVtbl *lpVtbl;
1282     ULONG refs;
1283 } HeapUnknown;
1284
1285 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1286 {
1287     if (IsEqualIID(riid, &IID_IUnknown))
1288     {
1289         IUnknown_AddRef(iface);
1290         *ppv = (LPVOID)iface;
1291         return S_OK;
1292     }
1293     *ppv = NULL;
1294     return E_NOINTERFACE;
1295 }
1296
1297 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
1298 {
1299     HeapUnknown *This = (HeapUnknown *)iface;
1300     trace("HeapUnknown_AddRef(%p)\n", iface);
1301     return InterlockedIncrement((LONG*)&This->refs);
1302 }
1303
1304 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
1305 {
1306     HeapUnknown *This = (HeapUnknown *)iface;
1307     ULONG refs = InterlockedDecrement((LONG*)&This->refs);
1308     trace("HeapUnknown_Release(%p)\n", iface);
1309     if (!refs) HeapFree(GetProcessHeap(), 0, This);
1310     return refs;
1311 }
1312
1313 static const IUnknownVtbl HeapUnknown_Vtbl =
1314 {
1315     HeapUnknown_QueryInterface,
1316     HeapUnknown_AddRef,
1317     HeapUnknown_Release
1318 };
1319
1320 static void test_proxybuffer(REFIID riid)
1321 {
1322     HRESULT hr;
1323     IPSFactoryBuffer *psfb;
1324     IRpcProxyBuffer *proxy;
1325     LPVOID lpvtbl;
1326     ULONG refs;
1327     CLSID clsid;
1328     HeapUnknown *pUnkOuter = (HeapUnknown *)HeapAlloc(GetProcessHeap(), 0, sizeof(*pUnkOuter));
1329
1330     pUnkOuter->lpVtbl = &HeapUnknown_Vtbl;
1331     pUnkOuter->refs = 1;
1332
1333     hr = CoGetPSClsid(riid, &clsid);
1334     ok_ole_success(hr, CoGetPSClsid);
1335
1336     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1337     ok_ole_success(hr, CoGetClassObject);
1338
1339     hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown*)pUnkOuter, riid, &proxy, &lpvtbl);
1340     ok_ole_success(hr, IPSFactoryBuffer_CreateProxy);
1341     ok(lpvtbl != NULL, "IPSFactoryBuffer_CreateProxy succeeded, but returned a NULL vtable!\n");
1342
1343     refs = IPSFactoryBuffer_Release(psfb);
1344 #if 0 /* not reliable on native. maybe it leaks references! */
1345     ok(refs == 0, "Ref-count leak of %ld on IPSFactoryBuffer\n", refs);
1346 #endif
1347
1348     refs = IUnknown_Release((IUnknown *)lpvtbl);
1349     ok(refs == 1, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs-1);
1350
1351     refs = IRpcProxyBuffer_Release(proxy);
1352     ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
1353 }
1354
1355 static void test_stubbuffer(REFIID riid)
1356 {
1357     HRESULT hr;
1358     IPSFactoryBuffer *psfb;
1359     IRpcStubBuffer *stub;
1360     ULONG refs;
1361     CLSID clsid;
1362
1363     cLocks = 0;
1364
1365     hr = CoGetPSClsid(riid, &clsid);
1366     ok_ole_success(hr, CoGetPSClsid);
1367
1368     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1369     ok_ole_success(hr, CoGetClassObject);
1370
1371     hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
1372     ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
1373
1374     refs = IPSFactoryBuffer_Release(psfb);
1375 #if 0 /* not reliable on native. maybe it leaks references */
1376     ok(refs == 0, "Ref-count leak of %ld on IPSFactoryBuffer\n", refs);
1377 #endif
1378
1379     ok_more_than_one_lock();
1380
1381     IRpcStubBuffer_Disconnect(stub);
1382
1383     ok_no_locks();
1384
1385     refs = IRpcStubBuffer_Release(stub);
1386     ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
1387 }
1388
1389 static HWND hwnd_app;
1390
1391 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
1392     LPCLASSFACTORY iface,
1393     LPUNKNOWN pUnkOuter,
1394     REFIID riid,
1395     LPVOID *ppvObj)
1396 {
1397     DWORD_PTR res;
1398     if (IsEqualIID(riid, &IID_IWineTest))
1399     {
1400         BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
1401         ok(ret, "Timed out sending a message to originating window during RPC call\n");
1402     }
1403     return S_FALSE;
1404 }
1405
1406 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
1407 {
1408     Test_IClassFactory_QueryInterface,
1409     Test_IClassFactory_AddRef,
1410     Test_IClassFactory_Release,
1411     TestRE_IClassFactory_CreateInstance,
1412     Test_IClassFactory_LockServer
1413 };
1414
1415 IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
1416
1417 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1418 {
1419     switch (msg)
1420     {
1421     case WM_USER:
1422     {
1423         HRESULT hr;
1424         IStream *pStream = NULL;
1425         IClassFactory *proxy = NULL;
1426         IUnknown *object;
1427         DWORD tid;
1428         HANDLE thread;
1429
1430         cLocks = 0;
1431
1432         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1433         ok_ole_success(hr, CreateStreamOnHGlobal);
1434         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1435
1436         ok_more_than_one_lock();
1437
1438         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1439         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1440         ok_ole_success(hr, CoReleaseMarshalData);
1441         IStream_Release(pStream);
1442
1443         ok_more_than_one_lock();
1444
1445         /* note the use of the magic IID_IWineTest value to tell remote thread
1446          * to try to send a message back to us */
1447         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IWineTest, (void **)&object);
1448
1449         IClassFactory_Release(proxy);
1450
1451         ok_no_locks();
1452
1453         end_host_object(tid, thread);
1454
1455         PostMessage(hwnd, WM_QUIT, 0, 0);
1456
1457         return 0;
1458     }
1459     case WM_USER+1:
1460     {
1461         HRESULT hr;
1462         IStream *pStream = NULL;
1463         IClassFactory *proxy = NULL;
1464         IUnknown *object;
1465         DWORD tid;
1466         HANDLE thread;
1467
1468         cLocks = 0;
1469
1470         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1471         ok_ole_success(hr, CreateStreamOnHGlobal);
1472         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1473
1474         ok_more_than_one_lock();
1475
1476         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1477         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1478         ok_ole_success(hr, CoReleaseMarshalData);
1479         IStream_Release(pStream);
1480
1481         ok_more_than_one_lock();
1482
1483         /* post quit message before a doing a COM call to show that a pending
1484         * WM_QUIT message doesn't stop the call from succeeding */
1485         PostMessage(hwnd, WM_QUIT, 0, 0);
1486         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1487
1488         IClassFactory_Release(proxy);
1489
1490         ok_no_locks();
1491
1492         end_host_object(tid, thread);
1493
1494         return 0;
1495     }
1496     default:
1497         return DefWindowProc(hwnd, msg, wparam, lparam);
1498     }
1499 }
1500
1501 static void test_message_reentrancy(void)
1502 {
1503     WNDCLASS wndclass;
1504     MSG msg;
1505
1506     memset(&wndclass, 0, sizeof(wndclass));
1507     wndclass.lpfnWndProc = window_proc;
1508     wndclass.lpszClassName = "WineCOMTest";
1509     RegisterClass(&wndclass);
1510
1511     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1512     ok(hwnd_app != NULL, "Window creation failed\n");
1513
1514     /* start message re-entrancy test */
1515     PostMessage(hwnd_app, WM_USER, 0, 0);
1516
1517     while (GetMessage(&msg, NULL, 0, 0))
1518     {
1519         TranslateMessage(&msg);
1520         DispatchMessage(&msg);
1521     }
1522 }
1523
1524 static void test_WM_QUIT_handling(void)
1525 {
1526     MSG msg;
1527
1528     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1529     ok(hwnd_app != NULL, "Window creation failed\n");
1530
1531     /* start WM_QUIT handling test */
1532     PostMessage(hwnd_app, WM_USER+1, 0, 0);
1533
1534     while (GetMessage(&msg, NULL, 0, 0))
1535     {
1536         TranslateMessage(&msg);
1537         DispatchMessage(&msg);
1538     }
1539 }
1540
1541 /* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
1542 #if 0
1543
1544 static HANDLE heventShutdown;
1545
1546 static void LockModuleOOP()
1547 {
1548     InterlockedIncrement(&cLocks); /* for test purposes only */
1549     CoAddRefServerProcess();
1550 }
1551
1552 static void UnlockModuleOOP()
1553 {
1554     InterlockedDecrement(&cLocks); /* for test purposes only */
1555     if (!CoReleaseServerProcess())
1556         SetEvent(heventShutdown);
1557 }
1558
1559 static HWND hwnd_app;
1560
1561 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
1562     LPCLASSFACTORY iface,
1563     REFIID riid,
1564     LPVOID *ppvObj)
1565 {
1566     if (ppvObj == NULL) return E_POINTER;
1567
1568     if (IsEqualGUID(riid, &IID_IUnknown) ||
1569         IsEqualGUID(riid, &IID_IClassFactory))
1570     {
1571         *ppvObj = (LPVOID)iface;
1572         IClassFactory_AddRef(iface);
1573         return S_OK;
1574     }
1575
1576     return E_NOINTERFACE;
1577 }
1578
1579 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
1580 {
1581     return 2; /* non-heap-based object */
1582 }
1583
1584 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
1585 {
1586     return 1; /* non-heap-based object */
1587 }
1588
1589 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
1590     LPCLASSFACTORY iface,
1591     LPUNKNOWN pUnkOuter,
1592     REFIID riid,
1593     LPVOID *ppvObj)
1594 {
1595     return CLASS_E_CLASSNOTAVAILABLE;
1596 }
1597
1598 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
1599     LPCLASSFACTORY iface,
1600     BOOL fLock)
1601 {
1602     if (fLock)
1603         LockModuleOOP();
1604     else
1605         UnlockModuleOOP();
1606     return S_OK;
1607 }
1608
1609 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
1610 {
1611     TestOOP_IClassFactory_QueryInterface,
1612     TestOOP_IClassFactory_AddRef,
1613     TestOOP_IClassFactory_Release,
1614     TestOOP_IClassFactory_CreateInstance,
1615     TestOOP_IClassFactory_LockServer
1616 };
1617
1618 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
1619
1620 /* tests functions commonly used by out of process COM servers */
1621 static void test_out_of_process_com(void)
1622 {
1623     static const CLSID CLSID_WineOOPTest = {
1624         0x5201163f,
1625         0x8164,
1626         0x4fd0,
1627         {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
1628     }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
1629     DWORD cookie;
1630     HRESULT hr;
1631     IClassFactory * cf;
1632     DWORD ret;
1633
1634     heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
1635
1636     cLocks = 0;
1637
1638     /* Start the object suspended */
1639     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
1640         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
1641     ok_ole_success(hr, CoRegisterClassObject);
1642
1643     /* ... and CoGetClassObject does not find it and fails when it looks for the
1644      * class in the registry */
1645     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1646         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1647     todo_wine {
1648     ok(hr == REGDB_E_CLASSNOTREG,
1649         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08lx\n", hr);
1650     }
1651
1652     /* Resume the object suspended above ... */
1653     hr = CoResumeClassObjects();
1654     ok_ole_success(hr, CoResumeClassObjects);
1655
1656     /* ... and now it should succeed */
1657     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1658         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1659     ok_ole_success(hr, CoGetClassObject);
1660
1661     /* Now check the locking is working */
1662     /* NOTE: we are accessing the class directly, not through a proxy */
1663
1664     ok_no_locks();
1665
1666     hr = IClassFactory_LockServer(cf, TRUE);
1667     trace("IClassFactory_LockServer returned 0x%08lx\n", hr);
1668
1669     ok_more_than_one_lock();
1670     
1671     IClassFactory_LockServer(cf, FALSE);
1672
1673     ok_no_locks();
1674
1675     IClassFactory_Release(cf);
1676
1677     /* wait for shutdown signal */
1678     ret = WaitForSingleObject(heventShutdown, 5000);
1679     todo_wine { ok(ret != WAIT_TIMEOUT, "Server didn't shut down or machine is under very heavy load\n"); }
1680
1681     /* try to connect again after SCM has suspended registered class objects */
1682     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
1683         &IID_IClassFactory, (LPVOID*)&cf);
1684     todo_wine {
1685     ok(hr == CO_E_SERVER_STOPPING,
1686         "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08lx\n", hr);
1687     }
1688
1689     hr = CoRevokeClassObject(cookie);
1690     ok_ole_success(hr, CoRevokeClassObject);
1691
1692     CloseHandle(heventShutdown);
1693 }
1694 #endif
1695
1696 static void test_ROT(void)
1697 {
1698     static const WCHAR wszFileName[] = {'B','E','2','0','E','2','F','5','-',
1699         '1','9','0','3','-','4','A','A','E','-','B','1','A','F','-',
1700         '2','0','4','6','E','5','8','6','C','9','2','5',0};
1701     HRESULT hr;
1702     IMoniker *pMoniker = NULL;
1703     IRunningObjectTable *pROT = NULL;
1704     DWORD dwCookie;
1705
1706     cLocks = 0;
1707
1708     hr = CreateFileMoniker(wszFileName, &pMoniker);
1709     ok_ole_success(hr, CreateClassMoniker);
1710     hr = GetRunningObjectTable(0, &pROT);
1711     ok_ole_success(hr, GetRunningObjectTable);
1712     hr = IRunningObjectTable_Register(pROT, 0, (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
1713     ok_ole_success(hr, IRunningObjectTable_Register);
1714
1715     ok_more_than_one_lock();
1716
1717     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
1718     ok_ole_success(hr, IRunningObjectTable_Revoke);
1719
1720     ok_no_locks();
1721 }
1722
1723 static const char cf_marshaled[] =
1724 {
1725     0x9, 0x0, 0x0, 0x0,
1726     0x0, 0x0, 0x0, 0x0,
1727     0x9, 0x0, 0x0, 0x0,
1728     'M', 0x0, 'y', 0x0,
1729     'F', 0x0, 'o', 0x0,
1730     'r', 0x0, 'm', 0x0,
1731     'a', 0x0, 't', 0x0,
1732     0x0, 0x0
1733 };
1734
1735 static void test_marshal_CLIPFORMAT(void)
1736 {
1737     unsigned char *buffer;
1738     unsigned long size;
1739     unsigned long flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1740     wireCLIPFORMAT wirecf;
1741     CLIPFORMAT cf = RegisterClipboardFormatA("MyFormat");
1742     CLIPFORMAT cf2;
1743
1744     size = CLIPFORMAT_UserSize(&flags, 0, &cf);
1745     ok(size == sizeof(*wirecf) + sizeof(cf_marshaled), "Size should be %d, instead of %ld\n", sizeof(*wirecf) + sizeof(cf_marshaled), size);
1746
1747     buffer = HeapAlloc(GetProcessHeap(), 0, size);
1748     CLIPFORMAT_UserMarshal(&flags, buffer, &cf);
1749     wirecf = (wireCLIPFORMAT)buffer;
1750     ok(wirecf->fContext == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08lx\n", wirecf->fContext);
1751     ok(wirecf->u.dwValue == cf, "Marshaled value should be 0x%04x instead of 0x%04lx\n", cf, wirecf->u.dwValue);
1752     ok(!memcmp(wirecf+1, cf_marshaled, sizeof(cf_marshaled)), "Marshaled data differs\n");
1753
1754     CLIPFORMAT_UserUnmarshal(&flags, buffer, &cf2);
1755     ok(cf == cf2, "Didn't unmarshal properly\n");
1756     HeapFree(GetProcessHeap(), 0, buffer);
1757
1758     CLIPFORMAT_UserFree(&flags, &cf2);
1759 }
1760
1761 static void test_marshal_HWND(void)
1762 {
1763     unsigned char *buffer;
1764     unsigned long size;
1765     unsigned long flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION);
1766     HWND hwnd = GetDesktopWindow();
1767     HWND hwnd2;
1768     wireHWND wirehwnd;
1769
1770     size = HWND_UserSize(&flags, 0, &hwnd);
1771     ok(size == sizeof(*wirehwnd), "Size should be %d, instead of %ld\n", sizeof(*wirehwnd), size);
1772
1773     buffer = HeapAlloc(GetProcessHeap(), 0, size);
1774     HWND_UserMarshal(&flags, buffer, &hwnd);
1775     wirehwnd = (wireHWND)buffer;
1776     ok(wirehwnd->fContext == WDT_INPROC_CALL, "Context should be WDT_INPROC_CALL instead of 0x%08lx\n", wirehwnd->fContext);
1777     ok(wirehwnd->u.hInproc == (LONG_PTR)hwnd, "Marshaled value should be %p instead of %p\n", hwnd, (HANDLE)wirehwnd->u.hRemote);
1778
1779     HWND_UserUnmarshal(&flags, buffer, &hwnd2);
1780     ok(hwnd == hwnd2, "Didn't unmarshal properly\n");
1781     HeapFree(GetProcessHeap(), 0, buffer);
1782
1783     HWND_UserFree(&flags, &hwnd2);
1784 }
1785
1786 static void test_marshal_HGLOBAL(void)
1787 {
1788     unsigned char *buffer;
1789     unsigned long size;
1790     unsigned long flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION);
1791     HGLOBAL hglobal;
1792     HGLOBAL hglobal2;
1793     unsigned char *wirehglobal;
1794     int i;
1795
1796     hglobal = NULL;
1797     flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION);
1798     size = HGLOBAL_UserSize(&flags, 0, &hglobal);
1799     /* native is poorly programmed and allocates 4 bytes more than it needs to
1800      * here - Wine doesn't have to emulate that */
1801     ok((size == 8) || (size == 12), "Size should be 12, instead of %ld\n", size);
1802     buffer = HeapAlloc(GetProcessHeap(), 0, size);
1803     HGLOBAL_UserMarshal(&flags, buffer, &hglobal);
1804     wirehglobal = buffer;
1805     ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08lx\n", *(ULONG *)wirehglobal);
1806     wirehglobal += sizeof(ULONG);
1807     ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+4 should be HGLOBAL\n");
1808     HGLOBAL_UserUnmarshal(&flags, buffer, &hglobal2);
1809     ok(hglobal2 == hglobal, "Didn't unmarshal properly\n");
1810     HeapFree(GetProcessHeap(), 0, buffer);
1811     HGLOBAL_UserFree(&flags, &hglobal2);
1812
1813     hglobal = GlobalAlloc(0, 4);
1814     buffer = GlobalLock(hglobal);
1815     for (i = 0; i < 4; i++)
1816         buffer[i] = i;
1817     GlobalUnlock(hglobal);
1818     flags = MAKELONG(MSHCTX_LOCAL, NDR_LOCAL_DATA_REPRESENTATION);
1819     size = HGLOBAL_UserSize(&flags, 0, &hglobal);
1820     /* native is poorly programmed and allocates 4 bytes more than it needs to
1821      * here - Wine doesn't have to emulate that */
1822     ok((size == 24) || (size == 28), "Size should be 24 or 28, instead of %ld\n", size);
1823     buffer = HeapAlloc(GetProcessHeap(), 0, size);
1824     HGLOBAL_UserMarshal(&flags, buffer, &hglobal);
1825     wirehglobal = buffer;
1826     ok(*(ULONG *)wirehglobal == WDT_REMOTE_CALL, "Context should be WDT_REMOTE_CALL instead of 0x%08lx\n", *(ULONG *)wirehglobal);
1827     wirehglobal += sizeof(ULONG);
1828     ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+0x4 should be HGLOBAL\n");
1829     wirehglobal += sizeof(ULONG);
1830     ok(*(ULONG *)wirehglobal == 4, "buffer+0x8 should be size of HGLOBAL\n");
1831     wirehglobal += sizeof(ULONG);
1832     ok(*(ULONG *)wirehglobal == (ULONG)hglobal, "buffer+0xc should be HGLOBAL\n");
1833     wirehglobal += sizeof(ULONG);
1834     ok(*(ULONG *)wirehglobal == 4, "buffer+0x10 should be size of HGLOBAL\n");
1835     wirehglobal += sizeof(ULONG);
1836     for (i = 0; i < 4; i++)
1837         ok(wirehglobal[i] == i, "buffer+0x%x should be %d\n", 0x10 + i, i);
1838     HGLOBAL_UserUnmarshal(&flags, buffer, &hglobal2);
1839     ok(hglobal2 != NULL, "Didn't unmarshal properly\n");
1840     HeapFree(GetProcessHeap(), 0, buffer);
1841     HGLOBAL_UserFree(&flags, &hglobal2);
1842     GlobalFree(hglobal);
1843 }
1844
1845 static HENHMETAFILE create_emf(void)
1846 {
1847     RECT rect = {0, 0, 100, 100};
1848     HDC hdc = CreateEnhMetaFile(NULL, NULL, &rect, "HENHMETAFILE Marshaling Test\0Test\0\0");
1849     ExtTextOut(hdc, 0, 0, ETO_OPAQUE, NULL, "Test String", strlen("Test String"), NULL);
1850     return CloseEnhMetaFile(hdc);
1851 }
1852
1853 static void test_marshal_HENHMETAFILE(void)
1854 {
1855     unsigned char *buffer;
1856     unsigned long size;
1857     unsigned long flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1858     HENHMETAFILE hemf;
1859     HENHMETAFILE hemf2 = NULL;
1860     unsigned char *wirehemf;
1861
1862     hemf = create_emf();
1863
1864     size = HENHMETAFILE_UserSize(&flags, 0, &hemf);
1865     ok(size > 20, "size should be at least 20 bytes, not %ld\n", size);
1866     buffer = HeapAlloc(GetProcessHeap(), 0, size);
1867     HENHMETAFILE_UserMarshal(&flags, buffer, &hemf);
1868     wirehemf = buffer;
1869     ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08lx\n", *(DWORD *)wirehemf);
1870     wirehemf += sizeof(DWORD);
1871     ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08lx\n", *(DWORD *)wirehemf);
1872     wirehemf += sizeof(DWORD);
1873     ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0x8 should be size - 0x10 instead of 0x%08lx\n", *(DWORD *)wirehemf);
1874     wirehemf += sizeof(DWORD);
1875     ok(*(DWORD *)wirehemf == (size - 0x10), "wirestgm + 0xc should be size - 0x10 instead of 0x%08lx\n", *(DWORD *)wirehemf);
1876     wirehemf += sizeof(DWORD);
1877     ok(*(DWORD *)wirehemf == EMR_HEADER, "wirestgm + 0x10 should be EMR_HEADER instead of %ld\n", *(DWORD *)wirehemf);
1878     wirehemf += sizeof(DWORD);
1879     /* ... rest of data not tested - refer to tests for GetEnhMetaFileBits
1880      * at this point */
1881
1882     HENHMETAFILE_UserUnmarshal(&flags, buffer, &hemf2);
1883     ok(hemf2 != NULL, "HENHMETAFILE didn't unmarshal\n");
1884     HeapFree(GetProcessHeap(), 0, buffer);
1885     HENHMETAFILE_UserFree(&flags, &hemf2);
1886     DeleteEnhMetaFile(hemf);
1887
1888     /* test NULL emf */
1889     hemf = NULL;
1890
1891     size = HENHMETAFILE_UserSize(&flags, 0, &hemf);
1892     ok(size == 8, "size should be 8 bytes, not %ld\n", size);
1893     buffer = (unsigned char *)HeapAlloc(GetProcessHeap(), 0, size);
1894     HENHMETAFILE_UserMarshal(&flags, buffer, &hemf);
1895     wirehemf = buffer;
1896     ok(*(DWORD *)wirehemf == WDT_REMOTE_CALL, "wirestgm + 0x0 should be WDT_REMOTE_CALL instead of 0x%08lx\n", *(DWORD *)wirehemf);
1897     wirehemf += sizeof(DWORD);
1898     ok(*(DWORD *)wirehemf == (DWORD)(DWORD_PTR)hemf, "wirestgm + 0x4 should be hemf instead of 0x%08lx\n", *(DWORD *)wirehemf);
1899     wirehemf += sizeof(DWORD);
1900
1901     HENHMETAFILE_UserUnmarshal(&flags, buffer, &hemf2);
1902     ok(hemf2 == NULL, "NULL HENHMETAFILE didn't unmarshal\n");
1903     HeapFree(GetProcessHeap(), 0, buffer);
1904     HENHMETAFILE_UserFree(&flags, &hemf2);
1905 }
1906
1907 START_TEST(marshal)
1908 {
1909     WNDCLASS wndclass;
1910     HMODULE hOle32 = GetModuleHandle("ole32");
1911     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
1912
1913     /* register a window class used in several tests */
1914     memset(&wndclass, 0, sizeof(wndclass));
1915     wndclass.lpfnWndProc = window_proc;
1916     wndclass.lpszClassName = "WineCOMTest";
1917     RegisterClass(&wndclass);
1918
1919     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1920
1921     /* FIXME: test CoCreateInstanceEx */
1922
1923     /* helper function tests */
1924     test_CoGetPSClsid();
1925
1926     /* lifecycle management and marshaling tests */
1927     test_no_marshaler();
1928     test_normal_marshal_and_release();
1929     test_normal_marshal_and_unmarshal();
1930     test_marshal_and_unmarshal_invalid();
1931     test_interthread_marshal_and_unmarshal();
1932     test_proxy_marshal_and_unmarshal();
1933     test_marshal_stub_apartment_shutdown();
1934     test_marshal_proxy_apartment_shutdown();
1935     test_marshal_proxy_mta_apartment_shutdown();
1936     test_no_couninitialize_server();
1937     test_no_couninitialize_client();
1938     test_tableweak_marshal_and_unmarshal_twice();
1939     test_tableweak_marshal_releasedata1();
1940     test_tableweak_marshal_releasedata2();
1941     test_tablestrong_marshal_and_unmarshal_twice();
1942     test_lock_object_external();
1943     test_disconnect_stub();
1944     test_normal_marshal_and_unmarshal_twice();
1945     test_hresult_marshaling();
1946     test_proxy_used_in_wrong_thread();
1947     test_message_filter();
1948     test_bad_marshal_stream();
1949     test_proxy_interfaces();
1950     test_stubbuffer(&IID_IClassFactory);
1951     test_proxybuffer(&IID_IClassFactory);
1952     test_message_reentrancy();
1953     test_WM_QUIT_handling();
1954
1955 /*    test_out_of_process_com(); */
1956
1957     test_ROT();
1958     /* FIXME: test GIT */
1959
1960     test_marshal_CLIPFORMAT();
1961     test_marshal_HWND();
1962     test_marshal_HGLOBAL();
1963     test_marshal_HENHMETAFILE();
1964
1965     CoUninitialize();
1966     return;
1967
1968 no_test:
1969     trace("You need DCOM95 installed to run this test\n");
1970     return;
1971 }