Fix some gcc 4.0 warnings.
[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 that stubs are released when the containing apartment is destroyed */
421 static void test_marshal_stub_apartment_shutdown(void)
422 {
423     HRESULT hr;
424     IStream *pStream = NULL;
425     IUnknown *pProxy = NULL;
426     DWORD tid;
427     HANDLE thread;
428
429     cLocks = 0;
430
431     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
432     ok_ole_success(hr, CreateStreamOnHGlobal);
433     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
434
435     ok_more_than_one_lock();
436     
437     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
438     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
439     ok_ole_success(hr, CoUnmarshalInterface);
440     IStream_Release(pStream);
441
442     ok_more_than_one_lock();
443
444     end_host_object(tid, thread);
445
446     ok_no_locks();
447
448     IUnknown_Release(pProxy);
449
450     ok_no_locks();
451 }
452
453 /* tests that proxies are released when the containing apartment is destroyed */
454 static void test_marshal_proxy_apartment_shutdown(void)
455 {
456     HRESULT hr;
457     IStream *pStream = NULL;
458     IUnknown *pProxy = NULL;
459     DWORD tid;
460     HANDLE thread;
461
462     cLocks = 0;
463
464     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
465     ok_ole_success(hr, CreateStreamOnHGlobal);
466     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
467
468     ok_more_than_one_lock();
469     
470     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
471     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
472     ok_ole_success(hr, CoUnmarshalInterface);
473     IStream_Release(pStream);
474
475     ok_more_than_one_lock();
476
477     CoUninitialize();
478
479     ok_no_locks();
480
481     IUnknown_Release(pProxy);
482
483     ok_no_locks();
484
485     end_host_object(tid, thread);
486
487     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
488 }
489
490 /* tests that proxies are released when the containing mta apartment is destroyed */
491 static void test_marshal_proxy_mta_apartment_shutdown(void)
492 {
493     HRESULT hr;
494     IStream *pStream = NULL;
495     IUnknown *pProxy = NULL;
496     DWORD tid;
497     HANDLE thread;
498
499     CoUninitialize();
500     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
501
502     cLocks = 0;
503
504     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
505     ok_ole_success(hr, CreateStreamOnHGlobal);
506     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
507
508     ok_more_than_one_lock();
509
510     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
511     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
512     ok_ole_success(hr, CoUnmarshalInterface);
513     IStream_Release(pStream);
514
515     ok_more_than_one_lock();
516
517     CoUninitialize();
518
519     ok_no_locks();
520
521     IUnknown_Release(pProxy);
522
523     ok_no_locks();
524
525     end_host_object(tid, thread);
526
527     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
528 }
529
530 struct ncu_params
531 {
532     LPSTREAM stream;
533     HANDLE marshal_event;
534     HANDLE unmarshal_event;
535 };
536
537 /* helper for test_no_couninitialize_server */
538 static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p)
539 {
540     struct ncu_params *ncu_params = (struct ncu_params *)p;
541     HRESULT hr;
542
543     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
544
545     hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
546     ok_ole_success(hr, CoMarshalInterface);
547
548     SetEvent(ncu_params->marshal_event);
549
550     WaitForSingleObject(ncu_params->unmarshal_event, INFINITE);
551
552     /* die without calling CoUninitialize */
553
554     return 0;
555 }
556
557 /* tests apartment that an apartment with a stub is released without deadlock
558  * if the owning thread exits */
559 static void test_no_couninitialize_server()
560 {
561     HRESULT hr;
562     IStream *pStream = NULL;
563     IUnknown *pProxy = NULL;
564     DWORD tid;
565     HANDLE thread;
566     struct ncu_params ncu_params;
567
568     cLocks = 0;
569
570     ncu_params.marshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
571     ncu_params.unmarshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
572
573     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
574     ok_ole_success(hr, CreateStreamOnHGlobal);
575     ncu_params.stream = pStream;
576
577     thread = CreateThread(NULL, 0, no_couninitialize_server_proc, &ncu_params, 0, &tid);
578
579     WaitForSingleObject(ncu_params.marshal_event, INFINITE);
580     ok_more_than_one_lock();
581
582     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
583     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
584     ok_ole_success(hr, CoUnmarshalInterface);
585     IStream_Release(pStream);
586
587     ok_more_than_one_lock();
588
589     SetEvent(ncu_params.unmarshal_event);
590     WaitForSingleObject(thread, INFINITE);
591
592     ok_no_locks();
593
594     CloseHandle(thread);
595     CloseHandle(ncu_params.marshal_event);
596     CloseHandle(ncu_params.unmarshal_event);
597
598     IUnknown_Release(pProxy);
599
600     ok_no_locks();
601 }
602
603 /* STA -> STA call during DLL_THREAD_DETACH */
604 static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p)
605 {
606     struct ncu_params *ncu_params = (struct ncu_params *)p;
607     HRESULT hr;
608     IUnknown *pProxy = NULL;
609
610     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
611
612     hr = CoUnmarshalInterface(ncu_params->stream, &IID_IClassFactory, (void **)&pProxy);
613     ok_ole_success(hr, CoUnmarshalInterface);
614
615     ok_more_than_one_lock();
616
617     /* die without calling CoUninitialize */
618
619     return 0;
620 }
621
622 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
623 static void test_no_couninitialize_client()
624 {
625     HRESULT hr;
626     IStream *pStream = NULL;
627     DWORD tid;
628     DWORD host_tid;
629     HANDLE thread;
630     HANDLE host_thread;
631     struct ncu_params ncu_params;
632
633     cLocks = 0;
634
635     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
636     ok_ole_success(hr, CreateStreamOnHGlobal);
637     ncu_params.stream = pStream;
638
639     /* NOTE: assumes start_host_object uses an STA to host the object, as MTAs
640      * always deadlock when called from within DllMain */
641     host_tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
642     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
643
644     ok_more_than_one_lock();
645
646     thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
647
648     WaitForSingleObject(thread, INFINITE);
649     CloseHandle(thread);
650
651     ok_no_locks();
652
653     end_host_object(host_tid, host_thread);
654 }
655
656 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
657 static void test_tableweak_marshal_and_unmarshal_twice(void)
658 {
659     HRESULT hr;
660     IStream *pStream = NULL;
661     IUnknown *pProxy1 = NULL;
662     IUnknown *pProxy2 = NULL;
663     DWORD tid;
664     HANDLE thread;
665
666     cLocks = 0;
667
668     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
669     ok_ole_success(hr, CreateStreamOnHGlobal);
670     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
671
672     ok_more_than_one_lock();
673
674     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
675     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
676     ok_ole_success(hr, CoUnmarshalInterface);
677
678     ok_more_than_one_lock();
679
680     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
681     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
682     ok_ole_success(hr, CoUnmarshalInterface);
683
684     ok_more_than_one_lock();
685
686     IUnknown_Release(pProxy1);
687     IUnknown_Release(pProxy2);
688
689     /* this line is shows the difference between weak and strong table marshaling:
690      *  weak has cLocks == 0
691      *  strong has cLocks > 0 */
692     ok_no_locks();
693
694     end_host_object(tid, thread);
695 }
696
697 /* tests releasing after unmarshaling one object */
698 static void test_tableweak_marshal_releasedata1(void)
699 {
700     HRESULT hr;
701     IStream *pStream = NULL;
702     IUnknown *pProxy1 = NULL;
703     IUnknown *pProxy2 = NULL;
704     DWORD tid;
705     HANDLE thread;
706
707     cLocks = 0;
708
709     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
710     ok_ole_success(hr, CreateStreamOnHGlobal);
711     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
712
713     ok_more_than_one_lock();
714
715     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
716     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
717     ok_ole_success(hr, CoUnmarshalInterface);
718
719     ok_more_than_one_lock();
720
721     /* release the remaining reference on the object by calling
722      * CoReleaseMarshalData in the hosting thread */
723     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
724     release_host_object(tid);
725
726     ok_more_than_one_lock();
727
728     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
729     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
730     ok_ole_success(hr, CoUnmarshalInterface);
731     IStream_Release(pStream);
732
733     ok_more_than_one_lock();
734
735     IUnknown_Release(pProxy1);
736     if (pProxy2)
737         IUnknown_Release(pProxy2);
738
739     /* this line is shows the difference between weak and strong table marshaling:
740      *  weak has cLocks == 0
741      *  strong has cLocks > 0 */
742     ok_no_locks();
743
744     end_host_object(tid, thread);
745 }
746
747 /* tests releasing after unmarshaling one object */
748 static void test_tableweak_marshal_releasedata2(void)
749 {
750     HRESULT hr;
751     IStream *pStream = NULL;
752     IUnknown *pProxy = NULL;
753     DWORD tid;
754     HANDLE thread;
755
756     cLocks = 0;
757
758     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
759     ok_ole_success(hr, CreateStreamOnHGlobal);
760     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
761
762     ok_more_than_one_lock();
763
764     /* release the remaining reference on the object by calling
765      * CoReleaseMarshalData in the hosting thread */
766     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
767     release_host_object(tid);
768
769     ok_no_locks();
770
771     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
772     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
773     todo_wine
774     {
775     ok(hr == CO_E_OBJNOTREG,
776        "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08lx instead\n",
777        hr);
778     }
779     IStream_Release(pStream);
780
781     ok_no_locks();
782
783     end_host_object(tid, thread);
784 }
785
786 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
787 static void test_tablestrong_marshal_and_unmarshal_twice(void)
788 {
789     HRESULT hr;
790     IStream *pStream = NULL;
791     IUnknown *pProxy1 = NULL;
792     IUnknown *pProxy2 = NULL;
793     DWORD tid;
794     HANDLE thread;
795
796     cLocks = 0;
797
798     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
799     ok_ole_success(hr, CreateStreamOnHGlobal);
800     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
801
802     ok_more_than_one_lock();
803
804     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
805     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
806     ok_ole_success(hr, CoUnmarshalInterface);
807
808     ok_more_than_one_lock();
809
810     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
811     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
812     ok_ole_success(hr, CoUnmarshalInterface);
813
814     ok_more_than_one_lock();
815
816     if (pProxy1) IUnknown_Release(pProxy1);
817     if (pProxy2) IUnknown_Release(pProxy2);
818
819     /* this line is shows the difference between weak and strong table marshaling:
820      *  weak has cLocks == 0
821      *  strong has cLocks > 0 */
822     ok_more_than_one_lock();
823
824     /* release the remaining reference on the object by calling
825      * CoReleaseMarshalData in the hosting thread */
826     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
827     release_host_object(tid);
828     IStream_Release(pStream);
829
830     ok_no_locks();
831
832     end_host_object(tid, thread);
833 }
834
835 /* tests CoLockObjectExternal */
836 static void test_lock_object_external(void)
837 {
838     HRESULT hr;
839     IStream *pStream = NULL;
840
841     cLocks = 0;
842
843     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
844     ok_ole_success(hr, CreateStreamOnHGlobal);
845     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
846     ok_ole_success(hr, CoMarshalInterface);
847
848     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
849
850     ok_more_than_one_lock();
851     
852     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
853     hr = CoReleaseMarshalData(pStream);
854     ok_ole_success(hr, CoReleaseMarshalData);
855     IStream_Release(pStream);
856
857     ok_more_than_one_lock();
858
859     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
860
861     ok_no_locks();
862 }
863
864 /* tests disconnecting stubs */
865 static void test_disconnect_stub(void)
866 {
867     HRESULT hr;
868     IStream *pStream = NULL;
869
870     cLocks = 0;
871
872     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
873     ok_ole_success(hr, CreateStreamOnHGlobal);
874     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
875     ok_ole_success(hr, CoMarshalInterface);
876
877     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
878
879     ok_more_than_one_lock();
880     
881     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
882     hr = CoReleaseMarshalData(pStream);
883     ok_ole_success(hr, CoReleaseMarshalData);
884     IStream_Release(pStream);
885
886     ok_more_than_one_lock();
887
888     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
889
890     ok_no_locks();
891 }
892
893 /* tests failure case of a same-thread marshal and unmarshal twice */
894 static void test_normal_marshal_and_unmarshal_twice(void)
895 {
896     HRESULT hr;
897     IStream *pStream = NULL;
898     IUnknown *pProxy1 = NULL;
899     IUnknown *pProxy2 = NULL;
900
901     cLocks = 0;
902
903     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
904     ok_ole_success(hr, CreateStreamOnHGlobal);
905     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
906     ok_ole_success(hr, CoMarshalInterface);
907
908     ok_more_than_one_lock();
909     
910     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
911     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
912     ok_ole_success(hr, CoUnmarshalInterface);
913
914     ok_more_than_one_lock();
915
916     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
917     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
918     ok(hr == CO_E_OBJNOTCONNECTED,
919         "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08lx\n", hr);
920
921     IStream_Release(pStream);
922
923     ok_more_than_one_lock();
924
925     IUnknown_Release(pProxy1);
926
927     ok_no_locks();
928 }
929
930 /* tests success case of marshaling and unmarshaling an HRESULT */
931 static void test_hresult_marshaling(void)
932 {
933     HRESULT hr;
934     HRESULT hr_marshaled = 0;
935     IStream *pStream = NULL;
936     static const HRESULT E_DEADBEEF = 0xdeadbeef;
937
938     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
939     ok_ole_success(hr, CreateStreamOnHGlobal);
940
941     hr = CoMarshalHresult(pStream, E_DEADBEEF);
942     ok_ole_success(hr, CoMarshalHresult);
943
944     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
945     hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
946     ok_ole_success(hr, IStream_Read);
947
948     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
949
950     hr_marshaled = 0;
951     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
952     hr = CoUnmarshalHresult(pStream, &hr_marshaled);
953     ok_ole_success(hr, CoUnmarshalHresult);
954
955     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
956
957     IStream_Release(pStream);
958 }
959
960
961 /* helper for test_proxy_used_in_wrong_thread */
962 static DWORD CALLBACK bad_thread_proc(LPVOID p)
963 {
964     IClassFactory * cf = (IClassFactory *)p;
965     HRESULT hr;
966     IUnknown * proxy = NULL;
967
968     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
969     
970     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
971     if (proxy) IUnknown_Release(proxy);
972     todo_wine {
973     ok(hr == RPC_E_WRONG_THREAD,
974         "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n",
975         hr);
976     }
977
978     CoUninitialize();
979
980     return 0;
981 }
982
983 /* tests failure case of a using a proxy in the wrong apartment */
984 static void test_proxy_used_in_wrong_thread(void)
985 {
986     HRESULT hr;
987     IStream *pStream = NULL;
988     IUnknown *pProxy = NULL;
989     DWORD tid, tid2;
990     HANDLE thread;
991     HANDLE host_thread;
992
993     cLocks = 0;
994
995     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
996     ok_ole_success(hr, CreateStreamOnHGlobal);
997     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
998
999     ok_more_than_one_lock();
1000     
1001     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1002     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1003     ok_ole_success(hr, CoUnmarshalInterface);
1004     IStream_Release(pStream);
1005
1006     ok_more_than_one_lock();
1007
1008     /* create a thread that we can misbehave in */
1009     thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
1010
1011     WaitForSingleObject(thread, INFINITE);
1012     CloseHandle(thread);
1013
1014     IUnknown_Release(pProxy);
1015
1016     ok_no_locks();
1017
1018     end_host_object(tid, host_thread);
1019 }
1020
1021 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
1022 {
1023     if (ppvObj == NULL) return E_POINTER;
1024
1025     if (IsEqualGUID(riid, &IID_IUnknown) ||
1026         IsEqualGUID(riid, &IID_IClassFactory))
1027     {
1028         *ppvObj = (LPVOID)iface;
1029         IClassFactory_AddRef(iface);
1030         return S_OK;
1031     }
1032
1033     return E_NOINTERFACE;
1034 }
1035
1036 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
1037 {
1038     return 2; /* non-heap object */
1039 }
1040
1041 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
1042 {
1043     return 1; /* non-heap object */
1044 }
1045
1046 static DWORD WINAPI MessageFilter_HandleInComingCall(
1047   IMessageFilter *iface,
1048   DWORD dwCallType,
1049   HTASK threadIDCaller,
1050   DWORD dwTickCount,
1051   LPINTERFACEINFO lpInterfaceInfo)
1052 {
1053     static int callcount = 0;
1054     DWORD ret;
1055     trace("HandleInComingCall\n");
1056     switch (callcount)
1057     {
1058     case 0:
1059         ret = SERVERCALL_REJECTED;
1060         break;
1061     case 1:
1062         ret = SERVERCALL_RETRYLATER;
1063         break;
1064     default:
1065         ret = SERVERCALL_ISHANDLED;
1066         break;
1067     }
1068     callcount++;
1069     return ret;
1070 }
1071
1072 static DWORD WINAPI MessageFilter_RetryRejectedCall(
1073   IMessageFilter *iface,
1074   HTASK threadIDCallee,
1075   DWORD dwTickCount,
1076   DWORD dwRejectType)
1077 {
1078     trace("RetryRejectedCall\n");
1079     return 0;
1080 }
1081
1082 static DWORD WINAPI MessageFilter_MessagePending(
1083   IMessageFilter *iface,
1084   HTASK threadIDCallee,
1085   DWORD dwTickCount,
1086   DWORD dwPendingType)
1087 {
1088     trace("MessagePending\n");
1089     return PENDINGMSG_WAITNOPROCESS;
1090 }
1091
1092 static const IMessageFilterVtbl MessageFilter_Vtbl =
1093 {
1094     MessageFilter_QueryInterface,
1095     MessageFilter_AddRef,
1096     MessageFilter_Release,
1097     MessageFilter_HandleInComingCall,
1098     MessageFilter_RetryRejectedCall,
1099     MessageFilter_MessagePending
1100 };
1101
1102 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
1103
1104 static void test_message_filter(void)
1105 {
1106     HRESULT hr;
1107     IStream *pStream = NULL;
1108     IClassFactory *cf = NULL;
1109     DWORD tid;
1110     IUnknown *proxy = NULL;
1111     IMessageFilter *prev_filter = NULL;
1112     HANDLE thread;
1113
1114     cLocks = 0;
1115
1116     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1117     ok_ole_success(hr, CreateStreamOnHGlobal);
1118     tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
1119
1120     ok_more_than_one_lock();
1121
1122     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1123     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
1124     ok_ole_success(hr, CoUnmarshalInterface);
1125     IStream_Release(pStream);
1126
1127     ok_more_than_one_lock();
1128
1129     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1130     todo_wine { ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08lx instead\n", hr); }
1131     if (proxy) IUnknown_Release(proxy);
1132     proxy = NULL;
1133
1134     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
1135     ok_ole_success(hr, CoRegisterMessageFilter);
1136     if (prev_filter) IMessageFilter_Release(prev_filter);
1137
1138     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1139     ok_ole_success(hr, IClassFactory_CreateInstance);
1140
1141     IUnknown_Release(proxy);
1142
1143     IClassFactory_Release(cf);
1144
1145     ok_no_locks();
1146
1147     end_host_object(tid, thread);
1148 }
1149
1150 /* test failure case of trying to unmarshal from bad stream */
1151 static void test_bad_marshal_stream(void)
1152 {
1153     HRESULT hr;
1154     IStream *pStream = NULL;
1155
1156     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1157     ok_ole_success(hr, CreateStreamOnHGlobal);
1158     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1159     ok_ole_success(hr, CoMarshalInterface);
1160
1161     ok_more_than_one_lock();
1162
1163     /* try to read beyond end of stream */
1164     hr = CoReleaseMarshalData(pStream);
1165     ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08lx instead\n", hr);
1166
1167     /* now release for real */
1168     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1169     hr = CoReleaseMarshalData(pStream);
1170     ok_ole_success(hr, CoReleaseMarshalData);
1171
1172     IStream_Release(pStream);
1173 }
1174
1175 /* tests that proxies implement certain interfaces */
1176 static void test_proxy_interfaces(void)
1177 {
1178     HRESULT hr;
1179     IStream *pStream = NULL;
1180     IUnknown *pProxy = NULL;
1181     IUnknown *pOtherUnknown = NULL;
1182     DWORD tid;
1183     HANDLE thread;
1184
1185     cLocks = 0;
1186
1187     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1188     ok_ole_success(hr, CreateStreamOnHGlobal);
1189     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1190
1191     ok_more_than_one_lock();
1192         
1193     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1194     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1195     ok_ole_success(hr, CoUnmarshalInterface);
1196     IStream_Release(pStream);
1197
1198     ok_more_than_one_lock();
1199
1200     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
1201     ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
1202     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1203
1204     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
1205     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity); }
1206     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1207
1208     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
1209     ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
1210     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1211
1212     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
1213     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal); }
1214     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1215
1216     /* IMarshal2 is also supported on NT-based systems, but is pretty much
1217      * useless as it has no more methods over IMarshal that it inherits from. */
1218
1219     IUnknown_Release(pProxy);
1220
1221     ok_no_locks();
1222
1223     end_host_object(tid, thread);
1224 }
1225
1226 static void test_stubbuffer(REFIID riid)
1227 {
1228     HRESULT hr;
1229     IPSFactoryBuffer *psfb;
1230     IRpcStubBuffer *stub;
1231     ULONG refs;
1232     CLSID clsid;
1233
1234     cLocks = 0;
1235
1236     hr = CoGetPSClsid(riid, &clsid);
1237     ok_ole_success(hr, CoGetPSClsid);
1238
1239     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1240     ok_ole_success(hr, CoGetClassObject);
1241
1242     hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
1243     ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
1244
1245     refs = IPSFactoryBuffer_Release(psfb);
1246 #if 0 /* not reliable on native. maybe it leaks references */
1247     ok(refs == 0, "Ref-count leak of %ld on IPSFactoryBuffer\n", refs);
1248 #endif
1249
1250     ok_more_than_one_lock();
1251
1252     IRpcStubBuffer_Disconnect(stub);
1253
1254     ok_no_locks();
1255
1256     refs = IRpcStubBuffer_Release(stub);
1257     ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
1258 }
1259
1260 static HWND hwnd_app;
1261
1262 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
1263     LPCLASSFACTORY iface,
1264     LPUNKNOWN pUnkOuter,
1265     REFIID riid,
1266     LPVOID *ppvObj)
1267 {
1268     DWORD res;
1269     BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
1270     ok(ret, "Timed out sending a message to originating window during RPC call\n");
1271     return S_FALSE;
1272 }
1273
1274 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
1275 {
1276     Test_IClassFactory_QueryInterface,
1277     Test_IClassFactory_AddRef,
1278     Test_IClassFactory_Release,
1279     TestRE_IClassFactory_CreateInstance,
1280     Test_IClassFactory_LockServer
1281 };
1282
1283 IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
1284
1285 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1286 {
1287     switch (msg)
1288     {
1289     case WM_USER:
1290     {
1291         HRESULT hr;
1292         IStream *pStream = NULL;
1293         IClassFactory *proxy = NULL;
1294         IUnknown *object;
1295         DWORD tid;
1296         HANDLE thread;
1297
1298         cLocks = 0;
1299
1300         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1301         ok_ole_success(hr, CreateStreamOnHGlobal);
1302         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1303
1304         ok_more_than_one_lock();
1305
1306         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1307         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1308         ok_ole_success(hr, CoReleaseMarshalData);
1309         IStream_Release(pStream);
1310
1311         ok_more_than_one_lock();
1312
1313         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1314
1315         IClassFactory_Release(proxy);
1316
1317         ok_no_locks();
1318
1319         end_host_object(tid, thread);
1320
1321         PostMessage(hwnd, WM_QUIT, 0, 0);
1322
1323         return 0;
1324     }
1325     default:
1326         return DefWindowProc(hwnd, msg, wparam, lparam);
1327     }
1328 }
1329
1330 static void test_message_reentrancy(void)
1331 {
1332     WNDCLASS wndclass;
1333     MSG msg;
1334
1335     memset(&wndclass, 0, sizeof(wndclass));
1336     wndclass.lpfnWndProc = window_proc;
1337     wndclass.lpszClassName = "WineCOMTest";
1338     RegisterClass(&wndclass);
1339
1340     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1341     ok(hwnd_app != NULL, "Window creation failed\n");
1342
1343     PostMessage(hwnd_app, WM_USER, 0, 0);
1344
1345     while (GetMessage(&msg, NULL, 0, 0))
1346     {
1347         TranslateMessage(&msg);
1348         DispatchMessage(&msg);
1349     }
1350 }
1351
1352 /* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
1353 #if 0
1354
1355 static HANDLE heventShutdown;
1356
1357 static void LockModuleOOP()
1358 {
1359     InterlockedIncrement(&cLocks); /* for test purposes only */
1360     CoAddRefServerProcess();
1361 }
1362
1363 static void UnlockModuleOOP()
1364 {
1365     InterlockedDecrement(&cLocks); /* for test purposes only */
1366     if (!CoReleaseServerProcess())
1367         SetEvent(heventShutdown);
1368 }
1369
1370 static HWND hwnd_app;
1371
1372 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
1373     LPCLASSFACTORY iface,
1374     LPUNKNOWN pUnkOuter,
1375     REFIID riid,
1376     LPVOID *ppvObj)
1377 {
1378     DWORD res;
1379     BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 500, &res);
1380     todo_wine { ok(ret, "Timed out sending a message to originating window during RPC call\n"); }
1381     return S_FALSE;
1382 }
1383
1384 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
1385 {
1386     Test_IClassFactory_QueryInterface,
1387     Test_IClassFactory_AddRef,
1388     Test_IClassFactory_Release,
1389     TestRE_IClassFactory_CreateInstance,
1390     Test_IClassFactory_LockServer
1391 };
1392
1393 IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
1394
1395 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1396 {
1397     switch (msg)
1398     {
1399     case WM_USER:
1400     {
1401         HRESULT hr;
1402         IStream *pStream = NULL;
1403         IClassFactory *proxy = NULL;
1404         IUnknown *object;
1405         DWORD tid;
1406         HANDLE thread;
1407
1408         cLocks = 0;
1409
1410         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1411         ok_ole_success(hr, CreateStreamOnHGlobal);
1412         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1413
1414         ok_more_than_one_lock();
1415
1416         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1417         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1418         ok_ole_success(hr, CoReleaseMarshalData);
1419         IStream_Release(pStream);
1420
1421         ok_more_than_one_lock();
1422
1423         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1424
1425         IClassFactory_Release(proxy);
1426
1427         ok_no_locks();
1428
1429         end_host_object(tid, thread);
1430
1431         PostMessage(hwnd, WM_QUIT, 0, 0);
1432
1433         return 0;
1434     }
1435     default:
1436         return DefWindowProc(hwnd, msg, wparam, lparam);
1437     }
1438 }
1439
1440 static void test_message_reentrancy()
1441 {
1442     WNDCLASS wndclass;
1443     MSG msg;
1444
1445     memset(&wndclass, 0, sizeof(wndclass));
1446     wndclass.lpfnWndProc = window_proc;
1447     wndclass.lpszClassName = "WineCOMTest";
1448     RegisterClass(&wndclass);
1449
1450     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1451     ok(hwnd_app != NULL, "Window creation failed\n");
1452
1453     PostMessage(hwnd_app, WM_USER, 0, 0);
1454
1455     while (GetMessage(&msg, NULL, 0, 0))
1456     {
1457         TranslateMessage(&msg);
1458         DispatchMessage(&msg);
1459     }
1460 }
1461
1462 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
1463     LPCLASSFACTORY iface,
1464     REFIID riid,
1465     LPVOID *ppvObj)
1466 {
1467     if (ppvObj == NULL) return E_POINTER;
1468
1469     if (IsEqualGUID(riid, &IID_IUnknown) ||
1470         IsEqualGUID(riid, &IID_IClassFactory))
1471     {
1472         *ppvObj = (LPVOID)iface;
1473         IClassFactory_AddRef(iface);
1474         return S_OK;
1475     }
1476
1477     return E_NOINTERFACE;
1478 }
1479
1480 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
1481 {
1482     return 2; /* non-heap-based object */
1483 }
1484
1485 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
1486 {
1487     return 1; /* non-heap-based object */
1488 }
1489
1490 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
1491     LPCLASSFACTORY iface,
1492     LPUNKNOWN pUnkOuter,
1493     REFIID riid,
1494     LPVOID *ppvObj)
1495 {
1496     return CLASS_E_CLASSNOTAVAILABLE;
1497 }
1498
1499 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
1500     LPCLASSFACTORY iface,
1501     BOOL fLock)
1502 {
1503     if (fLock)
1504         LockModuleOOP();
1505     else
1506         UnlockModuleOOP();
1507     return S_OK;
1508 }
1509
1510 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
1511 {
1512     TestOOP_IClassFactory_QueryInterface,
1513     TestOOP_IClassFactory_AddRef,
1514     TestOOP_IClassFactory_Release,
1515     TestOOP_IClassFactory_CreateInstance,
1516     TestOOP_IClassFactory_LockServer
1517 };
1518
1519 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
1520
1521 /* tests functions commonly used by out of process COM servers */
1522 static void test_out_of_process_com()
1523 {
1524     static const CLSID CLSID_WineOOPTest = {
1525         0x5201163f,
1526         0x8164,
1527         0x4fd0,
1528         {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
1529     }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
1530     DWORD cookie;
1531     HRESULT hr;
1532     IClassFactory * cf;
1533     DWORD ret;
1534
1535     heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
1536
1537     cLocks = 0;
1538
1539     /* Start the object suspended */
1540     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
1541         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
1542     ok_ole_success(hr, CoRegisterClassObject);
1543
1544     /* ... and CoGetClassObject does not find it and fails when it looks for the
1545      * class in the registry */
1546     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1547         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1548     todo_wine {
1549     ok(hr == REGDB_E_CLASSNOTREG,
1550         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08lx\n", hr);
1551     }
1552
1553     /* Resume the object suspended above ... */
1554     hr = CoResumeClassObjects();
1555     ok_ole_success(hr, CoResumeClassObjects);
1556
1557     /* ... and now it should succeed */
1558     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1559         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1560     ok_ole_success(hr, CoGetClassObject);
1561
1562     /* Now check the locking is working */
1563     /* NOTE: we are accessing the class directly, not through a proxy */
1564
1565     ok_no_locks();
1566
1567     hr = IClassFactory_LockServer(cf, TRUE);
1568     trace("IClassFactory_LockServer returned 0x%08lx\n", hr);
1569
1570     ok_more_than_one_lock();
1571     
1572     IClassFactory_LockServer(cf, FALSE);
1573
1574     ok_no_locks();
1575
1576     IClassFactory_Release(cf);
1577
1578     /* wait for shutdown signal */
1579     ret = WaitForSingleObject(heventShutdown, 5000);
1580     todo_wine { ok(ret != WAIT_TIMEOUT, "Server didn't shut down or machine is under very heavy load\n"); }
1581
1582     /* try to connect again after SCM has suspended registered class objects */
1583     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
1584         &IID_IClassFactory, (LPVOID*)&cf);
1585     todo_wine {
1586     ok(hr == CO_E_SERVER_STOPPING,
1587         "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08lx\n", hr);
1588     }
1589
1590     hr = CoRevokeClassObject(cookie);
1591     ok_ole_success(hr, CoRevokeClassObject);
1592
1593     CloseHandle(heventShutdown);
1594 }
1595 #endif
1596
1597 static void test_ROT(void)
1598 {
1599     static const WCHAR wszFileName[] = {'B','E','2','0','E','2','F','5','-',
1600         '1','9','0','3','-','4','A','A','E','-','B','1','A','F','-',
1601         '2','0','4','6','E','5','8','6','C','9','2','5',0};
1602     HRESULT hr;
1603     IMoniker *pMoniker = NULL;
1604     IRunningObjectTable *pROT = NULL;
1605     DWORD dwCookie;
1606
1607     cLocks = 0;
1608
1609     hr = CreateFileMoniker(wszFileName, &pMoniker);
1610     ok_ole_success(hr, CreateClassMoniker);
1611     hr = GetRunningObjectTable(0, &pROT);
1612     ok_ole_success(hr, GetRunningObjectTable);
1613     hr = IRunningObjectTable_Register(pROT, 0, (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
1614     ok_ole_success(hr, IRunningObjectTable_Register);
1615
1616     ok_more_than_one_lock();
1617
1618     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
1619     ok_ole_success(hr, IRunningObjectTable_Revoke);
1620
1621     ok_no_locks();
1622 }
1623
1624 START_TEST(marshal)
1625 {
1626     HMODULE hOle32 = GetModuleHandle("ole32");
1627     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
1628
1629     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1630
1631     /* FIXME: test CoCreateInstanceEx */
1632
1633     /* helper function tests */
1634     test_CoGetPSClsid();
1635
1636     /* lifecycle management and marshaling tests */
1637     test_no_marshaler();
1638     test_normal_marshal_and_release();
1639     test_normal_marshal_and_unmarshal();
1640     test_marshal_and_unmarshal_invalid();
1641     test_interthread_marshal_and_unmarshal();
1642     test_marshal_stub_apartment_shutdown();
1643     test_marshal_proxy_apartment_shutdown();
1644     test_marshal_proxy_mta_apartment_shutdown();
1645     test_no_couninitialize_server();
1646     test_no_couninitialize_client();
1647     test_tableweak_marshal_and_unmarshal_twice();
1648     test_tableweak_marshal_releasedata1();
1649     test_tableweak_marshal_releasedata2();
1650     test_tablestrong_marshal_and_unmarshal_twice();
1651     test_lock_object_external();
1652     test_disconnect_stub();
1653     test_normal_marshal_and_unmarshal_twice();
1654     test_hresult_marshaling();
1655     test_proxy_used_in_wrong_thread();
1656     test_message_filter();
1657     test_bad_marshal_stream();
1658     test_proxy_interfaces();
1659     test_stubbuffer(&IID_IClassFactory);
1660     test_message_reentrancy();
1661
1662 /*    test_out_of_process_com(); */
1663
1664     test_ROT();
1665     /* FIXME: test GIT */
1666
1667     CoUninitialize();
1668     return;
1669
1670 no_test:
1671     trace("You need DCOM95 installed to run this test\n");
1672     return;
1673 }