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