SendMessageTimeout takes a DWORD_PTR not a DWORD.
[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 static void test_stubbuffer(REFIID riid)
1286 {
1287     HRESULT hr;
1288     IPSFactoryBuffer *psfb;
1289     IRpcStubBuffer *stub;
1290     ULONG refs;
1291     CLSID clsid;
1292
1293     cLocks = 0;
1294
1295     hr = CoGetPSClsid(riid, &clsid);
1296     ok_ole_success(hr, CoGetPSClsid);
1297
1298     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1299     ok_ole_success(hr, CoGetClassObject);
1300
1301     hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
1302     ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
1303
1304     refs = IPSFactoryBuffer_Release(psfb);
1305 #if 0 /* not reliable on native. maybe it leaks references */
1306     ok(refs == 0, "Ref-count leak of %ld on IPSFactoryBuffer\n", refs);
1307 #endif
1308
1309     ok_more_than_one_lock();
1310
1311     IRpcStubBuffer_Disconnect(stub);
1312
1313     ok_no_locks();
1314
1315     refs = IRpcStubBuffer_Release(stub);
1316     ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
1317 }
1318
1319 static HWND hwnd_app;
1320
1321 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
1322     LPCLASSFACTORY iface,
1323     LPUNKNOWN pUnkOuter,
1324     REFIID riid,
1325     LPVOID *ppvObj)
1326 {
1327     DWORD_PTR res;
1328     BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
1329     ok(ret, "Timed out sending a message to originating window during RPC call\n");
1330     return S_FALSE;
1331 }
1332
1333 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
1334 {
1335     Test_IClassFactory_QueryInterface,
1336     Test_IClassFactory_AddRef,
1337     Test_IClassFactory_Release,
1338     TestRE_IClassFactory_CreateInstance,
1339     Test_IClassFactory_LockServer
1340 };
1341
1342 IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
1343
1344 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1345 {
1346     switch (msg)
1347     {
1348     case WM_USER:
1349     {
1350         HRESULT hr;
1351         IStream *pStream = NULL;
1352         IClassFactory *proxy = NULL;
1353         IUnknown *object;
1354         DWORD tid;
1355         HANDLE thread;
1356
1357         cLocks = 0;
1358
1359         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1360         ok_ole_success(hr, CreateStreamOnHGlobal);
1361         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1362
1363         ok_more_than_one_lock();
1364
1365         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1366         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1367         ok_ole_success(hr, CoReleaseMarshalData);
1368         IStream_Release(pStream);
1369
1370         ok_more_than_one_lock();
1371
1372         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1373
1374         IClassFactory_Release(proxy);
1375
1376         ok_no_locks();
1377
1378         end_host_object(tid, thread);
1379
1380         PostMessage(hwnd, WM_QUIT, 0, 0);
1381
1382         return 0;
1383     }
1384     default:
1385         return DefWindowProc(hwnd, msg, wparam, lparam);
1386     }
1387 }
1388
1389 static void test_message_reentrancy(void)
1390 {
1391     WNDCLASS wndclass;
1392     MSG msg;
1393
1394     memset(&wndclass, 0, sizeof(wndclass));
1395     wndclass.lpfnWndProc = window_proc;
1396     wndclass.lpszClassName = "WineCOMTest";
1397     RegisterClass(&wndclass);
1398
1399     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1400     ok(hwnd_app != NULL, "Window creation failed\n");
1401
1402     PostMessage(hwnd_app, WM_USER, 0, 0);
1403
1404     while (GetMessage(&msg, NULL, 0, 0))
1405     {
1406         TranslateMessage(&msg);
1407         DispatchMessage(&msg);
1408     }
1409 }
1410
1411 /* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
1412 #if 0
1413
1414 static HANDLE heventShutdown;
1415
1416 static void LockModuleOOP()
1417 {
1418     InterlockedIncrement(&cLocks); /* for test purposes only */
1419     CoAddRefServerProcess();
1420 }
1421
1422 static void UnlockModuleOOP()
1423 {
1424     InterlockedDecrement(&cLocks); /* for test purposes only */
1425     if (!CoReleaseServerProcess())
1426         SetEvent(heventShutdown);
1427 }
1428
1429 static HWND hwnd_app;
1430
1431 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
1432     LPCLASSFACTORY iface,
1433     LPUNKNOWN pUnkOuter,
1434     REFIID riid,
1435     LPVOID *ppvObj)
1436 {
1437     DWORD res;
1438     BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 500, &res);
1439     todo_wine { ok(ret, "Timed out sending a message to originating window during RPC call\n"); }
1440     return S_FALSE;
1441 }
1442
1443 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
1444 {
1445     Test_IClassFactory_QueryInterface,
1446     Test_IClassFactory_AddRef,
1447     Test_IClassFactory_Release,
1448     TestRE_IClassFactory_CreateInstance,
1449     Test_IClassFactory_LockServer
1450 };
1451
1452 IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
1453
1454 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1455 {
1456     switch (msg)
1457     {
1458     case WM_USER:
1459     {
1460         HRESULT hr;
1461         IStream *pStream = NULL;
1462         IClassFactory *proxy = NULL;
1463         IUnknown *object;
1464         DWORD tid;
1465         HANDLE thread;
1466
1467         cLocks = 0;
1468
1469         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1470         ok_ole_success(hr, CreateStreamOnHGlobal);
1471         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1472
1473         ok_more_than_one_lock();
1474
1475         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1476         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1477         ok_ole_success(hr, CoReleaseMarshalData);
1478         IStream_Release(pStream);
1479
1480         ok_more_than_one_lock();
1481
1482         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1483
1484         IClassFactory_Release(proxy);
1485
1486         ok_no_locks();
1487
1488         end_host_object(tid, thread);
1489
1490         PostMessage(hwnd, WM_QUIT, 0, 0);
1491
1492         return 0;
1493     }
1494     default:
1495         return DefWindowProc(hwnd, msg, wparam, lparam);
1496     }
1497 }
1498
1499 static void test_message_reentrancy()
1500 {
1501     WNDCLASS wndclass;
1502     MSG msg;
1503
1504     memset(&wndclass, 0, sizeof(wndclass));
1505     wndclass.lpfnWndProc = window_proc;
1506     wndclass.lpszClassName = "WineCOMTest";
1507     RegisterClass(&wndclass);
1508
1509     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1510     ok(hwnd_app != NULL, "Window creation failed\n");
1511
1512     PostMessage(hwnd_app, WM_USER, 0, 0);
1513
1514     while (GetMessage(&msg, NULL, 0, 0))
1515     {
1516         TranslateMessage(&msg);
1517         DispatchMessage(&msg);
1518     }
1519 }
1520
1521 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
1522     LPCLASSFACTORY iface,
1523     REFIID riid,
1524     LPVOID *ppvObj)
1525 {
1526     if (ppvObj == NULL) return E_POINTER;
1527
1528     if (IsEqualGUID(riid, &IID_IUnknown) ||
1529         IsEqualGUID(riid, &IID_IClassFactory))
1530     {
1531         *ppvObj = (LPVOID)iface;
1532         IClassFactory_AddRef(iface);
1533         return S_OK;
1534     }
1535
1536     return E_NOINTERFACE;
1537 }
1538
1539 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
1540 {
1541     return 2; /* non-heap-based object */
1542 }
1543
1544 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
1545 {
1546     return 1; /* non-heap-based object */
1547 }
1548
1549 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
1550     LPCLASSFACTORY iface,
1551     LPUNKNOWN pUnkOuter,
1552     REFIID riid,
1553     LPVOID *ppvObj)
1554 {
1555     return CLASS_E_CLASSNOTAVAILABLE;
1556 }
1557
1558 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
1559     LPCLASSFACTORY iface,
1560     BOOL fLock)
1561 {
1562     if (fLock)
1563         LockModuleOOP();
1564     else
1565         UnlockModuleOOP();
1566     return S_OK;
1567 }
1568
1569 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
1570 {
1571     TestOOP_IClassFactory_QueryInterface,
1572     TestOOP_IClassFactory_AddRef,
1573     TestOOP_IClassFactory_Release,
1574     TestOOP_IClassFactory_CreateInstance,
1575     TestOOP_IClassFactory_LockServer
1576 };
1577
1578 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
1579
1580 /* tests functions commonly used by out of process COM servers */
1581 static void test_out_of_process_com()
1582 {
1583     static const CLSID CLSID_WineOOPTest = {
1584         0x5201163f,
1585         0x8164,
1586         0x4fd0,
1587         {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
1588     }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
1589     DWORD cookie;
1590     HRESULT hr;
1591     IClassFactory * cf;
1592     DWORD ret;
1593
1594     heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
1595
1596     cLocks = 0;
1597
1598     /* Start the object suspended */
1599     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
1600         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
1601     ok_ole_success(hr, CoRegisterClassObject);
1602
1603     /* ... and CoGetClassObject does not find it and fails when it looks for the
1604      * class in the registry */
1605     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1606         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1607     todo_wine {
1608     ok(hr == REGDB_E_CLASSNOTREG,
1609         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08lx\n", hr);
1610     }
1611
1612     /* Resume the object suspended above ... */
1613     hr = CoResumeClassObjects();
1614     ok_ole_success(hr, CoResumeClassObjects);
1615
1616     /* ... and now it should succeed */
1617     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1618         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1619     ok_ole_success(hr, CoGetClassObject);
1620
1621     /* Now check the locking is working */
1622     /* NOTE: we are accessing the class directly, not through a proxy */
1623
1624     ok_no_locks();
1625
1626     hr = IClassFactory_LockServer(cf, TRUE);
1627     trace("IClassFactory_LockServer returned 0x%08lx\n", hr);
1628
1629     ok_more_than_one_lock();
1630     
1631     IClassFactory_LockServer(cf, FALSE);
1632
1633     ok_no_locks();
1634
1635     IClassFactory_Release(cf);
1636
1637     /* wait for shutdown signal */
1638     ret = WaitForSingleObject(heventShutdown, 5000);
1639     todo_wine { ok(ret != WAIT_TIMEOUT, "Server didn't shut down or machine is under very heavy load\n"); }
1640
1641     /* try to connect again after SCM has suspended registered class objects */
1642     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
1643         &IID_IClassFactory, (LPVOID*)&cf);
1644     todo_wine {
1645     ok(hr == CO_E_SERVER_STOPPING,
1646         "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08lx\n", hr);
1647     }
1648
1649     hr = CoRevokeClassObject(cookie);
1650     ok_ole_success(hr, CoRevokeClassObject);
1651
1652     CloseHandle(heventShutdown);
1653 }
1654 #endif
1655
1656 static void test_ROT(void)
1657 {
1658     static const WCHAR wszFileName[] = {'B','E','2','0','E','2','F','5','-',
1659         '1','9','0','3','-','4','A','A','E','-','B','1','A','F','-',
1660         '2','0','4','6','E','5','8','6','C','9','2','5',0};
1661     HRESULT hr;
1662     IMoniker *pMoniker = NULL;
1663     IRunningObjectTable *pROT = NULL;
1664     DWORD dwCookie;
1665
1666     cLocks = 0;
1667
1668     hr = CreateFileMoniker(wszFileName, &pMoniker);
1669     ok_ole_success(hr, CreateClassMoniker);
1670     hr = GetRunningObjectTable(0, &pROT);
1671     ok_ole_success(hr, GetRunningObjectTable);
1672     hr = IRunningObjectTable_Register(pROT, 0, (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
1673     ok_ole_success(hr, IRunningObjectTable_Register);
1674
1675     ok_more_than_one_lock();
1676
1677     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
1678     ok_ole_success(hr, IRunningObjectTable_Revoke);
1679
1680     ok_no_locks();
1681 }
1682
1683 START_TEST(marshal)
1684 {
1685     HMODULE hOle32 = GetModuleHandle("ole32");
1686     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
1687
1688     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1689
1690     /* FIXME: test CoCreateInstanceEx */
1691
1692     /* helper function tests */
1693     test_CoGetPSClsid();
1694
1695     /* lifecycle management and marshaling tests */
1696     test_no_marshaler();
1697     test_normal_marshal_and_release();
1698     test_normal_marshal_and_unmarshal();
1699     test_marshal_and_unmarshal_invalid();
1700     test_interthread_marshal_and_unmarshal();
1701     test_proxy_marshal_and_unmarshal();
1702     test_marshal_stub_apartment_shutdown();
1703     test_marshal_proxy_apartment_shutdown();
1704     test_marshal_proxy_mta_apartment_shutdown();
1705     test_no_couninitialize_server();
1706     test_no_couninitialize_client();
1707     test_tableweak_marshal_and_unmarshal_twice();
1708     test_tableweak_marshal_releasedata1();
1709     test_tableweak_marshal_releasedata2();
1710     test_tablestrong_marshal_and_unmarshal_twice();
1711     test_lock_object_external();
1712     test_disconnect_stub();
1713     test_normal_marshal_and_unmarshal_twice();
1714     test_hresult_marshaling();
1715     test_proxy_used_in_wrong_thread();
1716     test_message_filter();
1717     test_bad_marshal_stream();
1718     test_proxy_interfaces();
1719     test_stubbuffer(&IID_IClassFactory);
1720     test_message_reentrancy();
1721
1722 /*    test_out_of_process_com(); */
1723
1724     test_ROT();
1725     /* FIXME: test GIT */
1726
1727     CoUninitialize();
1728     return;
1729
1730 no_test:
1731     trace("You need DCOM95 installed to run this test\n");
1732     return;
1733 }