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