Implement CryptImport/ExportPublicKeyInfo.
[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 START_TEST(marshal)
1670 {
1671     HMODULE hOle32 = GetModuleHandle("ole32");
1672     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
1673
1674     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1675
1676     /* FIXME: test CoCreateInstanceEx */
1677
1678     /* helper function tests */
1679     test_CoGetPSClsid();
1680
1681     /* lifecycle management and marshaling tests */
1682     test_no_marshaler();
1683     test_normal_marshal_and_release();
1684     test_normal_marshal_and_unmarshal();
1685     test_marshal_and_unmarshal_invalid();
1686     test_interthread_marshal_and_unmarshal();
1687     test_proxy_marshal_and_unmarshal();
1688     test_marshal_stub_apartment_shutdown();
1689     test_marshal_proxy_apartment_shutdown();
1690     test_marshal_proxy_mta_apartment_shutdown();
1691     test_no_couninitialize_server();
1692     test_no_couninitialize_client();
1693     test_tableweak_marshal_and_unmarshal_twice();
1694     test_tableweak_marshal_releasedata1();
1695     test_tableweak_marshal_releasedata2();
1696     test_tablestrong_marshal_and_unmarshal_twice();
1697     test_lock_object_external();
1698     test_disconnect_stub();
1699     test_normal_marshal_and_unmarshal_twice();
1700     test_hresult_marshaling();
1701     test_proxy_used_in_wrong_thread();
1702     test_message_filter();
1703     test_bad_marshal_stream();
1704     test_proxy_interfaces();
1705     test_stubbuffer(&IID_IClassFactory);
1706     test_proxybuffer(&IID_IClassFactory);
1707     test_message_reentrancy();
1708
1709 /*    test_out_of_process_com(); */
1710
1711     test_ROT();
1712     /* FIXME: test GIT */
1713
1714     CoUninitialize();
1715     return;
1716
1717 no_test:
1718     trace("You need DCOM95 installed to run this test\n");
1719     return;
1720 }