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