- Make proxy manager use IMultiQI instead of IInternalUnknown as tests
[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 const LARGE_INTEGER ullZero;
41 static LONG cLocks;
42
43 static void LockModule()
44 {
45     InterlockedIncrement(&cLocks);
46 }
47
48 static void UnlockModule()
49 {
50     InterlockedDecrement(&cLocks);
51 }
52
53
54 static HRESULT WINAPI Test_IUnknown_QueryInterface(
55     LPUNKNOWN iface,
56     REFIID riid,
57     LPVOID *ppvObj)
58 {
59     if (ppvObj == NULL) return E_POINTER;
60
61     if (IsEqualGUID(riid, &IID_IUnknown))
62     {
63         *ppvObj = (LPVOID)iface;
64         IUnknown_AddRef(iface);
65         return S_OK;
66     }
67
68     *ppvObj = NULL;
69     return E_NOINTERFACE;
70 }
71
72 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
73 {
74     LockModule();
75     return 2; /* non-heap-based object */
76 }
77
78 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
79 {
80     UnlockModule();
81     return 1; /* non-heap-based object */
82 }
83
84 static IUnknownVtbl TestUnknown_Vtbl =
85 {
86     Test_IUnknown_QueryInterface,
87     Test_IUnknown_AddRef,
88     Test_IUnknown_Release,
89 };
90
91 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
92
93
94 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
95     LPCLASSFACTORY iface,
96     REFIID riid,
97     LPVOID *ppvObj)
98 {
99     if (ppvObj == NULL) return E_POINTER;
100
101     if (IsEqualGUID(riid, &IID_IUnknown) ||
102         IsEqualGUID(riid, &IID_IClassFactory))
103     {
104         *ppvObj = (LPVOID)iface;
105         IClassFactory_AddRef(iface);
106         return S_OK;
107     }
108
109     *ppvObj = NULL;
110     return E_NOINTERFACE;
111 }
112
113 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
114 {
115     LockModule();
116     return 2; /* non-heap-based object */
117 }
118
119 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
120 {
121     UnlockModule();
122     return 1; /* non-heap-based object */
123 }
124
125 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
126     LPCLASSFACTORY iface,
127     LPUNKNOWN pUnkOuter,
128     REFIID riid,
129     LPVOID *ppvObj)
130 {
131     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
132     return IUnknown_QueryInterface((IUnknown*)&Test_Unknown, riid, ppvObj);
133 }
134
135 static HRESULT WINAPI Test_IClassFactory_LockServer(
136     LPCLASSFACTORY iface,
137     BOOL fLock)
138 {
139     return S_OK;
140 }
141
142 static IClassFactoryVtbl TestClassFactory_Vtbl =
143 {
144     Test_IClassFactory_QueryInterface,
145     Test_IClassFactory_AddRef,
146     Test_IClassFactory_Release,
147     Test_IClassFactory_CreateInstance,
148     Test_IClassFactory_LockServer
149 };
150
151 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
152
153 #define RELEASEMARSHALDATA WM_USER
154
155 struct host_object_data
156 {
157     IStream *stream;
158     IID iid;
159     IUnknown *object;
160     MSHLFLAGS marshal_flags;
161     HANDLE marshal_event;
162     IMessageFilter *filter;
163 };
164
165 static DWORD CALLBACK host_object_proc(LPVOID p)
166 {
167     struct host_object_data *data = (struct host_object_data *)p;
168     HRESULT hr;
169     MSG msg;
170
171     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
172
173     if (data->filter)
174     {
175         IMessageFilter * prev_filter = NULL;
176         hr = CoRegisterMessageFilter(data->filter, &prev_filter);
177         if (prev_filter) IMessageFilter_Release(prev_filter);
178         ok_ole_success(hr, CoRegisterMessageFilter);
179     }
180
181     hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
182     ok_ole_success(hr, CoMarshalInterface);
183
184     /* force the message queue to be created before signaling parent thread */
185     PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
186
187     SetEvent(data->marshal_event);
188
189     while (GetMessage(&msg, NULL, 0, 0))
190     {
191         if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
192         {
193             trace("releasing marshal data\n");
194             CoReleaseMarshalData(data->stream);
195             SetEvent((HANDLE)msg.lParam);
196         }
197         else
198             DispatchMessage(&msg);
199     }
200
201     HeapFree(GetProcessHeap(), 0, data);
202
203     CoUninitialize();
204
205     return hr;
206 }
207
208 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
209 {
210     DWORD tid = 0;
211     HANDLE marshal_event = CreateEvent(NULL, FALSE, FALSE, NULL);
212     struct host_object_data *data = (struct host_object_data *)HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
213
214     data->stream = stream;
215     data->iid = *riid;
216     data->object = object;
217     data->marshal_flags = marshal_flags;
218     data->marshal_event = marshal_event;
219     data->filter = filter;
220
221     *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
222
223     /* wait for marshaling to complete before returning */
224     WaitForSingleObject(marshal_event, INFINITE);
225     CloseHandle(marshal_event);
226
227     return tid;
228 }
229
230 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
231 {
232     return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
233 }
234
235 /* asks thread to release the marshal data because it has to be done by the
236  * same thread that marshaled the interface in the first place. */
237 static void release_host_object(DWORD tid)
238 {
239     HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
240     PostThreadMessage(tid, RELEASEMARSHALDATA, 0, (LPARAM)event);
241     WaitForSingleObject(event, INFINITE);
242     CloseHandle(event);
243 }
244
245 static void end_host_object(DWORD tid, HANDLE thread)
246 {
247     BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0);
248     ok(ret, "PostThreadMessage failed with error %ld\n", GetLastError());
249     /* be careful of races - don't return until hosting thread has terminated */
250     WaitForSingleObject(thread, INFINITE);
251     CloseHandle(thread);
252 }
253
254 /* tests normal marshal and then release without unmarshaling */
255 static void test_normal_marshal_and_release()
256 {
257     HRESULT hr;
258     IStream *pStream = NULL;
259
260     cLocks = 0;
261
262     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
263     ok_ole_success(hr, CreateStreamOnHGlobal);
264     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
265     ok_ole_success(hr, CoMarshalInterface);
266
267     ok_more_than_one_lock();
268
269     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
270     hr = CoReleaseMarshalData(pStream);
271     ok_ole_success(hr, CoReleaseMarshalData);
272     IStream_Release(pStream);
273
274     ok_no_locks();
275 }
276
277 /* tests success case of a same-thread marshal and unmarshal */
278 static void test_normal_marshal_and_unmarshal()
279 {
280     HRESULT hr;
281     IStream *pStream = NULL;
282     IUnknown *pProxy = NULL;
283
284     cLocks = 0;
285
286     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
287     ok_ole_success(hr, CreateStreamOnHGlobal);
288     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
289     ok_ole_success(hr, CoMarshalInterface);
290
291     ok_more_than_one_lock();
292     
293     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
294     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
295     ok_ole_success(hr, CoUnmarshalInterface);
296     IStream_Release(pStream);
297
298     ok_more_than_one_lock();
299
300     IUnknown_Release(pProxy);
301
302     ok_no_locks();
303 }
304
305 /* tests success case of an interthread marshal */
306 static void test_interthread_marshal_and_unmarshal()
307 {
308     HRESULT hr;
309     IStream *pStream = NULL;
310     IUnknown *pProxy = NULL;
311     DWORD tid;
312     HANDLE thread;
313
314     cLocks = 0;
315
316     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
317     ok_ole_success(hr, CreateStreamOnHGlobal);
318     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
319
320     ok_more_than_one_lock();
321     
322     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
323     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
324     ok_ole_success(hr, CoUnmarshalInterface);
325     IStream_Release(pStream);
326
327     ok_more_than_one_lock();
328
329     IUnknown_Release(pProxy);
330
331     ok_no_locks();
332
333     end_host_object(tid, thread);
334 }
335
336 /* tests that stubs are released when the containing apartment is destroyed */
337 static void test_marshal_stub_apartment_shutdown()
338 {
339     HRESULT hr;
340     IStream *pStream = NULL;
341     IUnknown *pProxy = NULL;
342     DWORD tid;
343     HANDLE thread;
344
345     cLocks = 0;
346
347     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
348     ok_ole_success(hr, CreateStreamOnHGlobal);
349     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
350
351     ok_more_than_one_lock();
352     
353     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
354     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
355     ok_ole_success(hr, CoReleaseMarshalData);
356     IStream_Release(pStream);
357
358     ok_more_than_one_lock();
359
360     end_host_object(tid, thread);
361
362     ok_no_locks();
363
364     IUnknown_Release(pProxy);
365
366     ok_no_locks();
367 }
368
369 /* tests that proxies are released when the containing apartment is destroyed */
370 static void test_marshal_proxy_apartment_shutdown()
371 {
372     HRESULT hr;
373     IStream *pStream = NULL;
374     IUnknown *pProxy = NULL;
375     DWORD tid;
376     HANDLE thread;
377
378     cLocks = 0;
379
380     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
381     ok_ole_success(hr, CreateStreamOnHGlobal);
382     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
383
384     ok_more_than_one_lock();
385     
386     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
387     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
388     ok_ole_success(hr, CoReleaseMarshalData);
389     IStream_Release(pStream);
390
391     ok_more_than_one_lock();
392
393     CoUninitialize();
394
395     ok_no_locks();
396
397     IUnknown_Release(pProxy);
398
399     ok_no_locks();
400
401     end_host_object(tid, thread);
402
403     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
404 }
405
406 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
407 static void test_tableweak_marshal_and_unmarshal_twice()
408 {
409     HRESULT hr;
410     IStream *pStream = NULL;
411     IUnknown *pProxy1 = NULL;
412     IUnknown *pProxy2 = NULL;
413     DWORD tid;
414     HANDLE thread;
415
416     cLocks = 0;
417
418     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
419     ok_ole_success(hr, CreateStreamOnHGlobal);
420     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
421
422     ok_more_than_one_lock();
423
424     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
425     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
426     ok_ole_success(hr, CoReleaseMarshalData);
427
428     ok_more_than_one_lock();
429
430     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
431     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
432     ok_ole_success(hr, CoUnmarshalInterface);
433
434     ok_more_than_one_lock();
435
436     IUnknown_Release(pProxy1);
437     IUnknown_Release(pProxy2);
438
439     /* this line is shows the difference between weak and strong table marshaling:
440      *  weak has cLocks == 0
441      *  strong has cLocks > 0 */
442     ok_no_locks();
443
444     end_host_object(tid, thread);
445 }
446
447 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
448 static void test_tablestrong_marshal_and_unmarshal_twice()
449 {
450     HRESULT hr;
451     IStream *pStream = NULL;
452     IUnknown *pProxy1 = NULL;
453     IUnknown *pProxy2 = NULL;
454     DWORD tid;
455     HANDLE thread;
456
457     cLocks = 0;
458
459     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
460     ok_ole_success(hr, CreateStreamOnHGlobal);
461     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
462
463     ok_more_than_one_lock();
464
465     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
466     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
467     ok_ole_success(hr, CoReleaseMarshalData);
468
469     ok_more_than_one_lock();
470
471     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
472     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
473     ok_ole_success(hr, CoUnmarshalInterface);
474
475     ok_more_than_one_lock();
476
477     if (pProxy1) IUnknown_Release(pProxy1);
478     if (pProxy2) IUnknown_Release(pProxy2);
479
480     /* this line is shows the difference between weak and strong table marshaling:
481      *  weak has cLocks == 0
482      *  strong has cLocks > 0 */
483     ok_more_than_one_lock();
484
485     /* release the remaining reference on the object by calling
486      * CoReleaseMarshalData in the hosting thread */
487     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
488     release_host_object(tid);
489     IStream_Release(pStream);
490
491     ok_no_locks();
492
493     end_host_object(tid, thread);
494 }
495
496 /* tests CoLockObjectExternal */
497 static void test_lock_object_external()
498 {
499     HRESULT hr;
500     IStream *pStream = NULL;
501
502     cLocks = 0;
503
504     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
505     ok_ole_success(hr, CreateStreamOnHGlobal);
506     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
507     ok_ole_success(hr, CoMarshalInterface);
508
509     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
510
511     ok_more_than_one_lock();
512     
513     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
514     hr = CoReleaseMarshalData(pStream);
515     ok_ole_success(hr, CoReleaseMarshalData);
516     IStream_Release(pStream);
517
518     ok_more_than_one_lock();
519
520     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
521
522     ok_no_locks();
523 }
524
525 /* tests disconnecting stubs */
526 static void test_disconnect_stub()
527 {
528     HRESULT hr;
529     IStream *pStream = NULL;
530
531     cLocks = 0;
532
533     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
534     ok_ole_success(hr, CreateStreamOnHGlobal);
535     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
536     ok_ole_success(hr, CoMarshalInterface);
537
538     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
539
540     ok_more_than_one_lock();
541     
542     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
543     hr = CoReleaseMarshalData(pStream);
544     ok_ole_success(hr, CoReleaseMarshalData);
545     IStream_Release(pStream);
546
547     ok_more_than_one_lock();
548
549     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
550
551     todo_wine { ok_no_locks(); }
552 }
553
554 /* tests failure case of a same-thread marshal and unmarshal twice */
555 static void test_normal_marshal_and_unmarshal_twice()
556 {
557     HRESULT hr;
558     IStream *pStream = NULL;
559     IUnknown *pProxy1 = NULL;
560     IUnknown *pProxy2 = NULL;
561
562     cLocks = 0;
563
564     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
565     ok_ole_success(hr, CreateStreamOnHGlobal);
566     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
567     ok_ole_success(hr, CoMarshalInterface);
568
569     ok_more_than_one_lock();
570     
571     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
572     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
573     ok_ole_success(hr, CoUnmarshalInterface);
574
575     ok_more_than_one_lock();
576
577     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
578     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
579     ok(hr == CO_E_OBJNOTCONNECTED,
580         "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08lx\n", hr);
581
582     IStream_Release(pStream);
583
584     ok_more_than_one_lock();
585
586     IUnknown_Release(pProxy1);
587
588     ok_no_locks();
589 }
590
591 /* tests success case of marshaling and unmarshaling an HRESULT */
592 static void test_hresult_marshaling()
593 {
594     HRESULT hr;
595     HRESULT hr_marshaled = 0;
596     IStream *pStream = NULL;
597     static const HRESULT E_DEADBEEF = 0xdeadbeef;
598
599     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
600     ok_ole_success(hr, CreateStreamOnHGlobal);
601
602     hr = CoMarshalHresult(pStream, E_DEADBEEF);
603     ok_ole_success(hr, CoMarshalHresult);
604
605     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
606     hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
607     ok_ole_success(hr, IStream_Read);
608
609     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
610
611     hr_marshaled = 0;
612     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
613     hr = CoUnmarshalHresult(pStream, &hr_marshaled);
614     ok_ole_success(hr, CoUnmarshalHresult);
615
616     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
617
618     IStream_Release(pStream);
619 }
620
621
622 /* helper for test_proxy_used_in_wrong_thread */
623 static DWORD CALLBACK bad_thread_proc(LPVOID p)
624 {
625     IClassFactory * cf = (IClassFactory *)p;
626     HRESULT hr;
627     IUnknown * proxy = NULL;
628
629     CoInitializeEx(NULL, COINIT_MULTITHREADED);
630     
631     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
632     if (proxy) IUnknown_Release(proxy);
633     todo_wine {
634     ok(hr == RPC_E_WRONG_THREAD,
635         "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n",
636         hr);
637     }
638
639     CoUninitialize();
640
641     return 0;
642 }
643
644 /* tests failure case of a using a proxy in the wrong apartment */
645 static void test_proxy_used_in_wrong_thread()
646 {
647     HRESULT hr;
648     IStream *pStream = NULL;
649     IUnknown *pProxy = NULL;
650     DWORD tid, tid2;
651     HANDLE thread;
652     HANDLE host_thread;
653
654     cLocks = 0;
655
656     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
657     ok_ole_success(hr, CreateStreamOnHGlobal);
658     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
659
660     ok_more_than_one_lock();
661     
662     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
663     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
664     ok_ole_success(hr, CoReleaseMarshalData);
665     IStream_Release(pStream);
666
667     ok_more_than_one_lock();
668
669     /* create a thread that we can misbehave in */
670     thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
671
672     WaitForSingleObject(thread, INFINITE);
673     CloseHandle(thread);
674
675     IUnknown_Release(pProxy);
676
677     ok_no_locks();
678
679     end_host_object(tid, host_thread);
680 }
681
682 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
683 {
684     if (ppvObj == NULL) return E_POINTER;
685
686     if (IsEqualGUID(riid, &IID_IUnknown) ||
687         IsEqualGUID(riid, &IID_IClassFactory))
688     {
689         *ppvObj = (LPVOID)iface;
690         IClassFactory_AddRef(iface);
691         return S_OK;
692     }
693
694     return E_NOINTERFACE;
695 }
696
697 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
698 {
699     return 2; /* non-heap object */
700 }
701
702 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
703 {
704     return 1; /* non-heap object */
705 }
706
707 static DWORD WINAPI MessageFilter_HandleInComingCall(
708   IMessageFilter *iface,
709   DWORD dwCallType,
710   HTASK threadIDCaller,
711   DWORD dwTickCount,
712   LPINTERFACEINFO lpInterfaceInfo)
713 {
714     static int callcount = 0;
715     DWORD ret;
716     trace("HandleInComingCall\n");
717     switch (callcount)
718     {
719     case 0:
720         ret = SERVERCALL_REJECTED;
721         break;
722     case 1:
723         ret = SERVERCALL_RETRYLATER;
724         break;
725     default:
726         ret = SERVERCALL_ISHANDLED;
727         break;
728     }
729     callcount++;
730     return ret;
731 }
732
733 static DWORD WINAPI MessageFilter_RetryRejectedCall(
734   IMessageFilter *iface,
735   HTASK threadIDCallee,
736   DWORD dwTickCount,
737   DWORD dwRejectType)
738 {
739     trace("RetryRejectedCall\n");
740     return 0;
741 }
742
743 static DWORD WINAPI MessageFilter_MessagePending(
744   IMessageFilter *iface,
745   HTASK threadIDCallee,
746   DWORD dwTickCount,
747   DWORD dwPendingType)
748 {
749     trace("MessagePending\n");
750     return PENDINGMSG_WAITNOPROCESS;
751 }
752
753 static IMessageFilterVtbl MessageFilter_Vtbl =
754 {
755     MessageFilter_QueryInterface,
756     MessageFilter_AddRef,
757     MessageFilter_Release,
758     MessageFilter_HandleInComingCall,
759     MessageFilter_RetryRejectedCall,
760     MessageFilter_MessagePending
761 };
762
763 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
764
765 static void test_message_filter()
766 {
767     HRESULT hr;
768     IStream *pStream = NULL;
769     IClassFactory *cf = NULL;
770     DWORD tid;
771     IUnknown *proxy = NULL;
772     IMessageFilter *prev_filter = NULL;
773     HANDLE thread;
774
775     cLocks = 0;
776
777     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
778     ok_ole_success(hr, CreateStreamOnHGlobal);
779     tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
780
781     ok_more_than_one_lock();
782
783     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
784     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
785     ok_ole_success(hr, CoUnmarshalInterface);
786     IStream_Release(pStream);
787
788     ok_more_than_one_lock();
789
790     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
791     todo_wine { ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08lx instead\n", hr); }
792     if (proxy) IUnknown_Release(proxy);
793     proxy = NULL;
794
795     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
796     ok_ole_success(hr, CoRegisterMessageFilter);
797     if (prev_filter) IMessageFilter_Release(prev_filter);
798
799     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
800     ok_ole_success(hr, IClassFactory_CreateInstance);
801
802     IUnknown_Release(proxy);
803
804     IClassFactory_Release(cf);
805
806     /* FIXME: this is a regression caused by the fact that I faked the
807      * IUnknown unmarshaling too much and didn't give it its own ifstub. */
808     todo_wine { ok_no_locks(); }
809
810     end_host_object(tid, thread);
811 }
812
813 /* test failure case of trying to unmarshal from bad stream */
814 static void test_bad_marshal_stream()
815 {
816     HRESULT hr;
817     IStream *pStream = NULL;
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     ok_more_than_one_lock();
825
826     /* try to read beyond end of stream */
827     hr = CoReleaseMarshalData(pStream);
828     ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08lx instead\n", hr);
829
830     /* now release for real */
831     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
832     hr = CoReleaseMarshalData(pStream);
833     ok_ole_success(hr, CoReleaseMarshalData);
834
835     IStream_Release(pStream);
836 }
837
838 /* tests that proxies implement certain interfaces */
839 static void test_proxy_interfaces()
840 {
841     HRESULT hr;
842     IStream *pStream = NULL;
843     IUnknown *pProxy = NULL;
844     IUnknown *pOtherUnknown = NULL;
845     DWORD tid;
846     HANDLE thread;
847     static const IID IID_IMarshal2 =
848     {
849         0x000001cf,
850         0x0000,
851         0x0000,
852         { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 }
853     };
854
855     cLocks = 0;
856
857     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
858     ok_ole_success(hr, CreateStreamOnHGlobal);
859     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
860
861     ok_more_than_one_lock();
862         
863     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
864     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
865     ok_ole_success(hr, CoReleaseMarshalData);
866     IStream_Release(pStream);
867
868     ok_more_than_one_lock();
869
870     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
871     ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
872     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
873
874     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
875     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity); }
876     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
877
878     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
879     ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
880     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
881
882     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
883     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal); }
884     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
885
886     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal2, (LPVOID*)&pOtherUnknown);
887     todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal2); }
888     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
889
890     IUnknown_Release(pProxy);
891
892     ok_no_locks();
893
894     end_host_object(tid, thread);
895 }
896
897
898 /* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
899 #if 0
900
901 static HANDLE heventShutdown;
902
903 static void LockModuleOOP()
904 {
905     InterlockedIncrement(&cLocks); /* for test purposes only */
906     CoAddRefServerProcess();
907 }
908
909 static void UnlockModuleOOP()
910 {
911     InterlockedDecrement(&cLocks); /* for test purposes only */
912     if (!CoReleaseServerProcess())
913         SetEvent(heventShutdown);
914 }
915
916
917 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
918     LPCLASSFACTORY iface,
919     REFIID riid,
920     LPVOID *ppvObj)
921 {
922     if (ppvObj == NULL) return E_POINTER;
923
924     if (IsEqualGUID(riid, &IID_IUnknown) ||
925         IsEqualGUID(riid, &IID_IClassFactory))
926     {
927         *ppvObj = (LPVOID)iface;
928         IClassFactory_AddRef(iface);
929         return S_OK;
930     }
931
932     return E_NOINTERFACE;
933 }
934
935 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
936 {
937     return 2; /* non-heap-based object */
938 }
939
940 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
941 {
942     return 1; /* non-heap-based object */
943 }
944
945 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
946     LPCLASSFACTORY iface,
947     LPUNKNOWN pUnkOuter,
948     REFIID riid,
949     LPVOID *ppvObj)
950 {
951     return CLASS_E_CLASSNOTAVAILABLE;
952 }
953
954 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
955     LPCLASSFACTORY iface,
956     BOOL fLock)
957 {
958     if (fLock)
959         LockModuleOOP();
960     else
961         UnlockModuleOOP();
962     return S_OK;
963 }
964
965 static IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
966 {
967     TestOOP_IClassFactory_QueryInterface,
968     TestOOP_IClassFactory_AddRef,
969     TestOOP_IClassFactory_Release,
970     TestOOP_IClassFactory_CreateInstance,
971     TestOOP_IClassFactory_LockServer
972 };
973
974 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
975
976 /* tests functions commonly used by out of process COM servers */
977 static void test_out_of_process_com()
978 {
979     static const CLSID CLSID_WineOOPTest = {
980         0x5201163f,
981         0x8164,
982         0x4fd0,
983         {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
984     }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
985     DWORD cookie;
986     HRESULT hr;
987     IClassFactory * cf;
988     DWORD ret;
989
990     heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
991
992     cLocks = 0;
993
994     /* Start the object suspended */
995     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
996         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
997     ok_ole_success(hr, CoRegisterClassObject);
998
999     /* ... and CoGetClassObject does not find it and fails when it looks for the
1000      * class in the registry */
1001     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1002         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1003     todo_wine {
1004     ok(hr == REGDB_E_CLASSNOTREG,
1005         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08lx\n", hr);
1006     }
1007
1008     /* Resume the object suspended above ... */
1009     hr = CoResumeClassObjects();
1010     ok_ole_success(hr, CoResumeClassObjects);
1011
1012     /* ... and now it should succeed */
1013     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
1014         NULL, &IID_IClassFactory, (LPVOID*)&cf);
1015     ok_ole_success(hr, CoGetClassObject);
1016
1017     /* Now check the locking is working */
1018     /* NOTE: we are accessing the class directly, not through a proxy */
1019
1020     ok_no_locks();
1021
1022     hr = IClassFactory_LockServer(cf, TRUE);
1023     trace("IClassFactory_LockServer returned 0x%08lx\n", hr);
1024
1025     ok_more_than_one_lock();
1026     
1027     IClassFactory_LockServer(cf, FALSE);
1028
1029     ok_no_locks();
1030
1031     IClassFactory_Release(cf);
1032
1033     /* wait for shutdown signal */
1034     ret = WaitForSingleObject(heventShutdown, 5000);
1035     todo_wine { ok(ret != WAIT_TIMEOUT, "Server didn't shut down or machine is under very heavy load\n"); }
1036
1037     /* try to connect again after SCM has suspended registered class objects */
1038     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
1039         &IID_IClassFactory, (LPVOID*)&cf);
1040     todo_wine {
1041     ok(hr == CO_E_SERVER_STOPPING,
1042         "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08lx\n", hr);
1043     }
1044
1045     hr = CoRevokeClassObject(cookie);
1046     ok_ole_success(hr, CoRevokeClassObject);
1047
1048     CloseHandle(heventShutdown);
1049 }
1050 #endif
1051
1052 START_TEST(marshal)
1053 {
1054     HMODULE hOle32 = GetModuleHandle("ole32");
1055     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
1056
1057     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1058
1059     /* FIXME: test CoCreateInstanceEx */
1060
1061     /* lifecycle management and marshaling tests */
1062     test_normal_marshal_and_release();
1063     test_normal_marshal_and_unmarshal();
1064     test_interthread_marshal_and_unmarshal();
1065     test_marshal_stub_apartment_shutdown();
1066     test_marshal_proxy_apartment_shutdown();
1067     test_tableweak_marshal_and_unmarshal_twice();
1068     test_tablestrong_marshal_and_unmarshal_twice();
1069     test_lock_object_external();
1070     test_disconnect_stub();
1071     test_normal_marshal_and_unmarshal_twice();
1072     test_hresult_marshaling();
1073     test_proxy_used_in_wrong_thread();
1074     test_message_filter();
1075     test_bad_marshal_stream();
1076     test_proxy_interfaces();
1077     /* FIXME: test custom marshaling */
1078     /* FIXME: test GIT */
1079     /* FIXME: test COM re-entrancy */
1080
1081 /*    test_out_of_process_com(); */
1082     CoUninitialize();
1083     return;
1084
1085 no_test:
1086     trace("You need DCOM95 installed to run this test\n");
1087     return;
1088 }