- Split up apartment creation so that the long code paths that don't
[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()
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()
64 {
65     InterlockedIncrement(&cLocks);
66 }
67
68 static void UnlockModule()
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 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 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 = (struct host_object_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()
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()
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()
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 a unmarshaling an freed object */
347 static void test_marshal_and_unmarshal_invalid()
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()
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()
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()
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()
492 {
493     HRESULT hr;
494     IStream *pStream = NULL;
495     IUnknown *pProxy = NULL;
496     DWORD tid;
497     HANDLE thread;
498
499     CoUninitialize();
500     CoInitializeEx(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     CoInitializeEx(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_proxy_used_in_wrong_thread */
538 static DWORD CALLBACK no_couninitialize_proc(LPVOID p)
539 {
540         struct ncu_params *ncu_params = (struct ncu_params *)p;
541         HRESULT hr;
542
543         CoInitializeEx(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 is released if the owning thread exits */
558 static void test_no_couninitialize()
559 {
560     HRESULT hr;
561     IStream *pStream = NULL;
562     IUnknown *pProxy = NULL;
563     DWORD tid;
564     HANDLE thread;
565     struct ncu_params ncu_params;
566
567     cLocks = 0;
568
569     ncu_params.marshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
570     ncu_params.unmarshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
571
572     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
573     ok_ole_success(hr, CreateStreamOnHGlobal);
574     ncu_params.stream = pStream;
575
576     thread = CreateThread(NULL, 0, no_couninitialize_proc, &ncu_params, 0, &tid);
577
578     WaitForSingleObject(ncu_params.marshal_event, INFINITE);
579     ok_more_than_one_lock();
580         
581     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
582     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
583     ok_ole_success(hr, CoUnmarshalInterface);
584     IStream_Release(pStream);
585
586     ok_more_than_one_lock();
587
588     SetEvent(ncu_params.unmarshal_event);
589     WaitForSingleObject(thread, INFINITE);
590
591     ok_no_locks();
592
593     CloseHandle(thread);
594     CloseHandle(ncu_params.marshal_event);
595     CloseHandle(ncu_params.unmarshal_event);
596
597     IUnknown_Release(pProxy);
598
599     ok_no_locks();
600 }
601
602 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
603 static void test_tableweak_marshal_and_unmarshal_twice()
604 {
605     HRESULT hr;
606     IStream *pStream = NULL;
607     IUnknown *pProxy1 = NULL;
608     IUnknown *pProxy2 = NULL;
609     DWORD tid;
610     HANDLE thread;
611
612     cLocks = 0;
613
614     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
615     ok_ole_success(hr, CreateStreamOnHGlobal);
616     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
617
618     ok_more_than_one_lock();
619
620     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
621     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
622     ok_ole_success(hr, CoUnmarshalInterface);
623
624     ok_more_than_one_lock();
625
626     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
627     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
628     ok_ole_success(hr, CoUnmarshalInterface);
629
630     ok_more_than_one_lock();
631
632     IUnknown_Release(pProxy1);
633     IUnknown_Release(pProxy2);
634
635     /* this line is shows the difference between weak and strong table marshaling:
636      *  weak has cLocks == 0
637      *  strong has cLocks > 0 */
638     ok_no_locks();
639
640     end_host_object(tid, thread);
641 }
642
643 /* tests releasing after unmarshaling one object */
644 static void test_tableweak_marshal_releasedata1()
645 {
646     HRESULT hr;
647     IStream *pStream = NULL;
648     IUnknown *pProxy1 = NULL;
649     IUnknown *pProxy2 = NULL;
650     DWORD tid;
651     HANDLE thread;
652
653     cLocks = 0;
654
655     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
656     ok_ole_success(hr, CreateStreamOnHGlobal);
657     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
658
659     ok_more_than_one_lock();
660
661     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
662     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
663     ok_ole_success(hr, CoUnmarshalInterface);
664
665     ok_more_than_one_lock();
666
667     /* release the remaining reference on the object by calling
668      * CoReleaseMarshalData in the hosting thread */
669     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
670     release_host_object(tid);
671
672     todo_wine { ok_more_than_one_lock(); }
673
674     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
675     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
676     todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
677     IStream_Release(pStream);
678
679     todo_wine { ok_more_than_one_lock(); }
680
681     IUnknown_Release(pProxy1);
682     if (pProxy2)
683         IUnknown_Release(pProxy2);
684
685     /* this line is shows the difference between weak and strong table marshaling:
686      *  weak has cLocks == 0
687      *  strong has cLocks > 0 */
688     ok_no_locks();
689
690     end_host_object(tid, thread);
691 }
692
693 /* tests releasing after unmarshaling one object */
694 static void test_tableweak_marshal_releasedata2()
695 {
696     HRESULT hr;
697     IStream *pStream = NULL;
698     IUnknown *pProxy = NULL;
699     DWORD tid;
700     HANDLE thread;
701
702     cLocks = 0;
703
704     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
705     ok_ole_success(hr, CreateStreamOnHGlobal);
706     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
707
708     ok_more_than_one_lock();
709
710     /* release the remaining reference on the object by calling
711      * CoReleaseMarshalData in the hosting thread */
712     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
713     release_host_object(tid);
714
715     todo_wine
716     {
717
718     ok_no_locks();
719
720     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
721     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
722     ok(hr == CO_E_OBJNOTREG,
723        "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08lx instead\n",
724        hr);
725     IStream_Release(pStream);
726
727     ok_no_locks();
728     }
729
730     end_host_object(tid, thread);
731 }
732
733 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
734 static void test_tablestrong_marshal_and_unmarshal_twice()
735 {
736     HRESULT hr;
737     IStream *pStream = NULL;
738     IUnknown *pProxy1 = NULL;
739     IUnknown *pProxy2 = NULL;
740     DWORD tid;
741     HANDLE thread;
742
743     cLocks = 0;
744
745     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
746     ok_ole_success(hr, CreateStreamOnHGlobal);
747     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
748
749     ok_more_than_one_lock();
750
751     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
752     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
753     ok_ole_success(hr, CoUnmarshalInterface);
754
755     ok_more_than_one_lock();
756
757     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
758     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
759     ok_ole_success(hr, CoUnmarshalInterface);
760
761     ok_more_than_one_lock();
762
763     if (pProxy1) IUnknown_Release(pProxy1);
764     if (pProxy2) IUnknown_Release(pProxy2);
765
766     /* this line is shows the difference between weak and strong table marshaling:
767      *  weak has cLocks == 0
768      *  strong has cLocks > 0 */
769     ok_more_than_one_lock();
770
771     /* release the remaining reference on the object by calling
772      * CoReleaseMarshalData in the hosting thread */
773     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
774     release_host_object(tid);
775     IStream_Release(pStream);
776
777     ok_no_locks();
778
779     end_host_object(tid, thread);
780 }
781
782 /* tests CoLockObjectExternal */
783 static void test_lock_object_external()
784 {
785     HRESULT hr;
786     IStream *pStream = NULL;
787
788     cLocks = 0;
789
790     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
791     ok_ole_success(hr, CreateStreamOnHGlobal);
792     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
793     ok_ole_success(hr, CoMarshalInterface);
794
795     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
796
797     ok_more_than_one_lock();
798     
799     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
800     hr = CoReleaseMarshalData(pStream);
801     ok_ole_success(hr, CoReleaseMarshalData);
802     IStream_Release(pStream);
803
804     ok_more_than_one_lock();
805
806     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
807
808     ok_no_locks();
809 }
810
811 /* tests disconnecting stubs */
812 static void test_disconnect_stub()
813 {
814     HRESULT hr;
815     IStream *pStream = NULL;
816
817     cLocks = 0;
818
819     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
820     ok_ole_success(hr, CreateStreamOnHGlobal);
821     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
822     ok_ole_success(hr, CoMarshalInterface);
823
824     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
825
826     ok_more_than_one_lock();
827     
828     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
829     hr = CoReleaseMarshalData(pStream);
830     ok_ole_success(hr, CoReleaseMarshalData);
831     IStream_Release(pStream);
832
833     ok_more_than_one_lock();
834
835     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
836
837     todo_wine { ok_no_locks(); }
838 }
839
840 /* tests failure case of a same-thread marshal and unmarshal twice */
841 static void test_normal_marshal_and_unmarshal_twice()
842 {
843     HRESULT hr;
844     IStream *pStream = NULL;
845     IUnknown *pProxy1 = NULL;
846     IUnknown *pProxy2 = NULL;
847
848     cLocks = 0;
849
850     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
851     ok_ole_success(hr, CreateStreamOnHGlobal);
852     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
853     ok_ole_success(hr, CoMarshalInterface);
854
855     ok_more_than_one_lock();
856     
857     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
858     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
859     ok_ole_success(hr, CoUnmarshalInterface);
860
861     ok_more_than_one_lock();
862
863     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
864     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
865     ok(hr == CO_E_OBJNOTCONNECTED,
866         "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08lx\n", hr);
867
868     IStream_Release(pStream);
869
870     ok_more_than_one_lock();
871
872     IUnknown_Release(pProxy1);
873
874     ok_no_locks();
875 }
876
877 /* tests success case of marshaling and unmarshaling an HRESULT */
878 static void test_hresult_marshaling()
879 {
880     HRESULT hr;
881     HRESULT hr_marshaled = 0;
882     IStream *pStream = NULL;
883     static const HRESULT E_DEADBEEF = 0xdeadbeef;
884
885     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
886     ok_ole_success(hr, CreateStreamOnHGlobal);
887
888     hr = CoMarshalHresult(pStream, E_DEADBEEF);
889     ok_ole_success(hr, CoMarshalHresult);
890
891     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
892     hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
893     ok_ole_success(hr, IStream_Read);
894
895     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
896
897     hr_marshaled = 0;
898     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
899     hr = CoUnmarshalHresult(pStream, &hr_marshaled);
900     ok_ole_success(hr, CoUnmarshalHresult);
901
902     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
903
904     IStream_Release(pStream);
905 }
906
907
908 /* helper for test_proxy_used_in_wrong_thread */
909 static DWORD CALLBACK bad_thread_proc(LPVOID p)
910 {
911     IClassFactory * cf = (IClassFactory *)p;
912     HRESULT hr;
913     IUnknown * proxy = NULL;
914
915     CoInitializeEx(NULL, COINIT_MULTITHREADED);
916     
917     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
918     if (proxy) IUnknown_Release(proxy);
919     todo_wine {
920     ok(hr == RPC_E_WRONG_THREAD,
921         "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n",
922         hr);
923     }
924
925     CoUninitialize();
926
927     return 0;
928 }
929
930 /* tests failure case of a using a proxy in the wrong apartment */
931 static void test_proxy_used_in_wrong_thread()
932 {
933     HRESULT hr;
934     IStream *pStream = NULL;
935     IUnknown *pProxy = NULL;
936     DWORD tid, tid2;
937     HANDLE thread;
938     HANDLE host_thread;
939
940     cLocks = 0;
941
942     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
943     ok_ole_success(hr, CreateStreamOnHGlobal);
944     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
945
946     ok_more_than_one_lock();
947     
948     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
949     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
950     ok_ole_success(hr, CoUnmarshalInterface);
951     IStream_Release(pStream);
952
953     ok_more_than_one_lock();
954
955     /* create a thread that we can misbehave in */
956     thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
957
958     WaitForSingleObject(thread, INFINITE);
959     CloseHandle(thread);
960
961     IUnknown_Release(pProxy);
962
963     ok_no_locks();
964
965     end_host_object(tid, host_thread);
966 }
967
968 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
969 {
970     if (ppvObj == NULL) return E_POINTER;
971
972     if (IsEqualGUID(riid, &IID_IUnknown) ||
973         IsEqualGUID(riid, &IID_IClassFactory))
974     {
975         *ppvObj = (LPVOID)iface;
976         IClassFactory_AddRef(iface);
977         return S_OK;
978     }
979
980     return E_NOINTERFACE;
981 }
982
983 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
984 {
985     return 2; /* non-heap object */
986 }
987
988 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
989 {
990     return 1; /* non-heap object */
991 }
992
993 static DWORD WINAPI MessageFilter_HandleInComingCall(
994   IMessageFilter *iface,
995   DWORD dwCallType,
996   HTASK threadIDCaller,
997   DWORD dwTickCount,
998   LPINTERFACEINFO lpInterfaceInfo)
999 {
1000     static int callcount = 0;
1001     DWORD ret;
1002     trace("HandleInComingCall\n");
1003     switch (callcount)
1004     {
1005     case 0:
1006         ret = SERVERCALL_REJECTED;
1007         break;
1008     case 1:
1009         ret = SERVERCALL_RETRYLATER;
1010         break;
1011     default:
1012         ret = SERVERCALL_ISHANDLED;
1013         break;
1014     }
1015     callcount++;
1016     return ret;
1017 }
1018
1019 static DWORD WINAPI MessageFilter_RetryRejectedCall(
1020   IMessageFilter *iface,
1021   HTASK threadIDCallee,
1022   DWORD dwTickCount,
1023   DWORD dwRejectType)
1024 {
1025     trace("RetryRejectedCall\n");
1026     return 0;
1027 }
1028
1029 static DWORD WINAPI MessageFilter_MessagePending(
1030   IMessageFilter *iface,
1031   HTASK threadIDCallee,
1032   DWORD dwTickCount,
1033   DWORD dwPendingType)
1034 {
1035     trace("MessagePending\n");
1036     return PENDINGMSG_WAITNOPROCESS;
1037 }
1038
1039 static IMessageFilterVtbl MessageFilter_Vtbl =
1040 {
1041     MessageFilter_QueryInterface,
1042     MessageFilter_AddRef,
1043     MessageFilter_Release,
1044     MessageFilter_HandleInComingCall,
1045     MessageFilter_RetryRejectedCall,
1046     MessageFilter_MessagePending
1047 };
1048
1049 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
1050
1051 static void test_message_filter()
1052 {
1053     HRESULT hr;
1054     IStream *pStream = NULL;
1055     IClassFactory *cf = NULL;
1056     DWORD tid;
1057     IUnknown *proxy = NULL;
1058     IMessageFilter *prev_filter = NULL;
1059     HANDLE thread;
1060
1061     cLocks = 0;
1062
1063     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1064     ok_ole_success(hr, CreateStreamOnHGlobal);
1065     tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
1066
1067     ok_more_than_one_lock();
1068
1069     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1070     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
1071     ok_ole_success(hr, CoUnmarshalInterface);
1072     IStream_Release(pStream);
1073
1074     ok_more_than_one_lock();
1075
1076     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1077     todo_wine { ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08lx instead\n", hr); }
1078     if (proxy) IUnknown_Release(proxy);
1079     proxy = NULL;
1080
1081     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
1082     ok_ole_success(hr, CoRegisterMessageFilter);
1083     if (prev_filter) IMessageFilter_Release(prev_filter);
1084
1085     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1086     ok_ole_success(hr, IClassFactory_CreateInstance);
1087
1088     IUnknown_Release(proxy);
1089
1090     IClassFactory_Release(cf);
1091
1092     ok_no_locks();
1093
1094     end_host_object(tid, thread);
1095 }
1096
1097 /* test failure case of trying to unmarshal from bad stream */
1098 static void test_bad_marshal_stream()
1099 {
1100     HRESULT hr;
1101     IStream *pStream = NULL;
1102
1103     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1104     ok_ole_success(hr, CreateStreamOnHGlobal);
1105     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1106     ok_ole_success(hr, CoMarshalInterface);
1107
1108     ok_more_than_one_lock();
1109
1110     /* try to read beyond end of stream */
1111     hr = CoReleaseMarshalData(pStream);
1112     ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08lx instead\n", hr);
1113
1114     /* now release for real */
1115     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1116     hr = CoReleaseMarshalData(pStream);
1117     ok_ole_success(hr, CoReleaseMarshalData);
1118
1119     IStream_Release(pStream);
1120 }
1121
1122 /* tests that proxies implement certain interfaces */
1123 static void test_proxy_interfaces()
1124 {
1125     HRESULT hr;
1126     IStream *pStream = NULL;
1127     IUnknown *pProxy = NULL;
1128     IUnknown *pOtherUnknown = NULL;
1129     DWORD tid;
1130     HANDLE thread;
1131
1132     cLocks = 0;
1133
1134     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1135     ok_ole_success(hr, CreateStreamOnHGlobal);
1136     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1137
1138     ok_more_than_one_lock();
1139         
1140     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1141     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1142     ok_ole_success(hr, CoUnmarshalInterface);
1143     IStream_Release(pStream);
1144
1145     ok_more_than_one_lock();
1146
1147     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
1148     ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
1149     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1150
1151     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
1152     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity); }
1153     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1154
1155     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
1156     ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
1157     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1158
1159     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
1160     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal); }
1161     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1162
1163     /* IMarshal2 is also supported on NT-based systems, but is pretty much
1164      * useless as it has no more methods over IMarshal that it inherits from. */
1165
1166     IUnknown_Release(pProxy);
1167
1168     ok_no_locks();
1169
1170     end_host_object(tid, thread);
1171 }
1172
1173 static void test_stubbuffer(REFIID riid)
1174 {
1175     HRESULT hr;
1176     IPSFactoryBuffer *psfb;
1177     IRpcStubBuffer *stub;
1178     ULONG refs;
1179     CLSID clsid;
1180
1181     cLocks = 0;
1182
1183     hr = CoGetPSClsid(riid, &clsid);
1184     ok_ole_success(hr, CoGetPSClsid);
1185
1186     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1187     ok_ole_success(hr, CoGetClassObject);
1188
1189     hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
1190     ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
1191
1192     refs = IPSFactoryBuffer_Release(psfb);
1193 #if 0 /* not reliable on native. maybe it leaks references */
1194     ok(refs == 0, "Ref-count leak of %ld on IPSFactoryBuffer\n", refs);
1195 #endif
1196
1197     ok_more_than_one_lock();
1198
1199     IRpcStubBuffer_Disconnect(stub);
1200
1201     ok_no_locks();
1202
1203     refs = IRpcStubBuffer_Release(stub);
1204     ok(refs == 0, "Ref-count leak of %ld on IRpcProxyBuffer\n", refs);
1205 }
1206
1207
1208 /* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
1209 #if 0
1210
1211 static HANDLE heventShutdown;
1212
1213 static void LockModuleOOP()
1214 {
1215     InterlockedIncrement(&cLocks); /* for test purposes only */
1216     CoAddRefServerProcess();
1217 }
1218
1219 static void UnlockModuleOOP()
1220 {
1221     InterlockedDecrement(&cLocks); /* for test purposes only */
1222     if (!CoReleaseServerProcess())
1223         SetEvent(heventShutdown);
1224 }
1225
1226
1227 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
1228     LPCLASSFACTORY iface,
1229     REFIID riid,
1230     LPVOID *ppvObj)
1231 {
1232     if (ppvObj == NULL) return E_POINTER;
1233
1234     if (IsEqualGUID(riid, &IID_IUnknown) ||
1235         IsEqualGUID(riid, &IID_IClassFactory))
1236     {
1237         *ppvObj = (LPVOID)iface;
1238         IClassFactory_AddRef(iface);
1239         return S_OK;
1240     }
1241
1242     return E_NOINTERFACE;
1243 }
1244
1245 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
1246 {
1247     return 2; /* non-heap-based object */
1248 }
1249
1250 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
1251 {
1252     return 1; /* non-heap-based object */
1253 }
1254
1255 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
1256     LPCLASSFACTORY iface,
1257     LPUNKNOWN pUnkOuter,
1258     REFIID riid,
1259     LPVOID *ppvObj)
1260 {
1261     return CLASS_E_CLASSNOTAVAILABLE;
1262 }
1263
1264 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
1265     LPCLASSFACTORY iface,
1266     BOOL fLock)
1267 {
1268     if (fLock)
1269         LockModuleOOP();
1270     else
1271         UnlockModuleOOP();
1272     return S_OK;
1273 }
1274
1275 static IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
1276 {
1277     TestOOP_IClassFactory_QueryInterface,
1278     TestOOP_IClassFactory_AddRef,
1279     TestOOP_IClassFactory_Release,
1280     TestOOP_IClassFactory_CreateInstance,
1281     TestOOP_IClassFactory_LockServer
1282 };
1283
1284 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
1285
1286 /* tests functions commonly used by out of process COM servers */
1287 static void test_out_of_process_com()
1288 {
1289     static const CLSID CLSID_WineOOPTest = {
1290         0x5201163f,
1291         0x8164,
1292         0x4fd0,
1293         {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
1294     }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
1295     DWORD cookie;
1296     HRESULT hr;
1297     IClassFactory * cf;
1298     DWORD ret;
1299
1300     heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
1301
1302     cLocks = 0;
1303
1304     /* Start the object suspended */
1305     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
1306         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
1307     ok_ole_success(hr, CoRegisterClassObject);
1308
1309     /* ... and CoGetClassObject does not find it and fails when it looks for the
1310      * class in the registry */
1311     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1312         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1313     todo_wine {
1314     ok(hr == REGDB_E_CLASSNOTREG,
1315         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08lx\n", hr);
1316     }
1317
1318     /* Resume the object suspended above ... */
1319     hr = CoResumeClassObjects();
1320     ok_ole_success(hr, CoResumeClassObjects);
1321
1322     /* ... and now it should succeed */
1323     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1324         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1325     ok_ole_success(hr, CoGetClassObject);
1326
1327     /* Now check the locking is working */
1328     /* NOTE: we are accessing the class directly, not through a proxy */
1329
1330     ok_no_locks();
1331
1332     hr = IClassFactory_LockServer(cf, TRUE);
1333     trace("IClassFactory_LockServer returned 0x%08lx\n", hr);
1334
1335     ok_more_than_one_lock();
1336     
1337     IClassFactory_LockServer(cf, FALSE);
1338
1339     ok_no_locks();
1340
1341     IClassFactory_Release(cf);
1342
1343     /* wait for shutdown signal */
1344     ret = WaitForSingleObject(heventShutdown, 5000);
1345     todo_wine { ok(ret != WAIT_TIMEOUT, "Server didn't shut down or machine is under very heavy load\n"); }
1346
1347     /* try to connect again after SCM has suspended registered class objects */
1348     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
1349         &IID_IClassFactory, (LPVOID*)&cf);
1350     todo_wine {
1351     ok(hr == CO_E_SERVER_STOPPING,
1352         "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08lx\n", hr);
1353     }
1354
1355     hr = CoRevokeClassObject(cookie);
1356     ok_ole_success(hr, CoRevokeClassObject);
1357
1358     CloseHandle(heventShutdown);
1359 }
1360 #endif
1361
1362 START_TEST(marshal)
1363 {
1364     HMODULE hOle32 = GetModuleHandle("ole32");
1365     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
1366
1367     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1368
1369     /* FIXME: test CoCreateInstanceEx */
1370
1371     /* helper function tests */
1372     test_CoGetPSClsid();
1373
1374     /* lifecycle management and marshaling tests */
1375     test_no_marshaler();
1376     test_normal_marshal_and_release();
1377     test_normal_marshal_and_unmarshal();
1378     test_marshal_and_unmarshal_invalid();
1379     test_interthread_marshal_and_unmarshal();
1380     test_marshal_stub_apartment_shutdown();
1381     test_marshal_proxy_apartment_shutdown();
1382     test_marshal_proxy_mta_apartment_shutdown();
1383     test_no_couninitialize();
1384     test_tableweak_marshal_and_unmarshal_twice();
1385     test_tableweak_marshal_releasedata1();
1386     test_tableweak_marshal_releasedata2();
1387     test_tablestrong_marshal_and_unmarshal_twice();
1388     test_lock_object_external();
1389     test_disconnect_stub();
1390     test_normal_marshal_and_unmarshal_twice();
1391     test_hresult_marshaling();
1392     test_proxy_used_in_wrong_thread();
1393     test_message_filter();
1394     test_bad_marshal_stream();
1395     test_proxy_interfaces();
1396     test_stubbuffer(&IID_IClassFactory);
1397     /* FIXME: test GIT */
1398     /* FIXME: test COM re-entrancy */
1399
1400 /*    test_out_of_process_com(); */
1401     CoUninitialize();
1402     return;
1403
1404 no_test:
1405     trace("You need DCOM95 installed to run this test\n");
1406     return;
1407 }