d3drm: Implement D3DRMColorGetRed.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define _WIN32_DCOM
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "shlguid.h"
32
33 #include "wine/test.h"
34
35 /* functions that are not present on all versions of Windows */
36 HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
37
38 /* helper macros to make tests a bit leaner */
39 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
40 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
41 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
42
43 static const IID IID_IWineTest =
44 {
45     0x5201163f,
46     0x8164,
47     0x4fd0,
48     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
49 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
50
51 static const IID IID_IRemUnknown =
52 {
53     0x00000131,
54     0x0000,
55     0x0000,
56     {0xc0,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}
57 };
58
59 #define EXTENTID_WineTest IID_IWineTest
60 #define CLSID_WineTest IID_IWineTest
61
62 static const CLSID CLSID_WineOOPTest =
63 {
64     0x5201163f,
65     0x8164,
66     0x4fd0,
67     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
68 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
69
70 static void test_cocreateinstance_proxy(void)
71 {
72     IUnknown *pProxy;
73     IMultiQI *pMQI;
74     HRESULT hr;
75
76     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
77
78     hr = CoCreateInstance(&CLSID_ShellDesktop, NULL, CLSCTX_INPROC, &IID_IUnknown, (void **)&pProxy);
79     ok_ole_success(hr, CoCreateInstance);
80     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (void **)&pMQI);
81     ok(hr == S_OK, "created object is not a proxy, so was created in the wrong apartment\n");
82     if (hr == S_OK)
83         IMultiQI_Release(pMQI);
84     IUnknown_Release(pProxy);
85
86     CoUninitialize();
87 }
88
89 static const LARGE_INTEGER ullZero;
90 static LONG cLocks;
91
92 static void LockModule(void)
93 {
94     InterlockedIncrement(&cLocks);
95 }
96
97 static void UnlockModule(void)
98 {
99     InterlockedDecrement(&cLocks);
100 }
101
102
103 static HRESULT WINAPI Test_IUnknown_QueryInterface(
104     LPUNKNOWN iface,
105     REFIID riid,
106     LPVOID *ppvObj)
107 {
108     if (ppvObj == NULL) return E_POINTER;
109
110     if (IsEqualGUID(riid, &IID_IUnknown))
111     {
112         *ppvObj = (LPVOID)iface;
113         IUnknown_AddRef(iface);
114         return S_OK;
115     }
116
117     *ppvObj = NULL;
118     return E_NOINTERFACE;
119 }
120
121 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
122 {
123     LockModule();
124     return 2; /* non-heap-based object */
125 }
126
127 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
128 {
129     UnlockModule();
130     return 1; /* non-heap-based object */
131 }
132
133 static const IUnknownVtbl TestUnknown_Vtbl =
134 {
135     Test_IUnknown_QueryInterface,
136     Test_IUnknown_AddRef,
137     Test_IUnknown_Release,
138 };
139
140 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
141
142
143 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
144     LPCLASSFACTORY iface,
145     REFIID riid,
146     LPVOID *ppvObj)
147 {
148     if (ppvObj == NULL) return E_POINTER;
149
150     if (IsEqualGUID(riid, &IID_IUnknown) ||
151         IsEqualGUID(riid, &IID_IClassFactory) ||
152         /* the only other interface Wine is currently able to marshal (for testing two proxies) */
153         IsEqualGUID(riid, &IID_IRemUnknown))
154     {
155         *ppvObj = (LPVOID)iface;
156         IClassFactory_AddRef(iface);
157         return S_OK;
158     }
159
160     *ppvObj = NULL;
161     return E_NOINTERFACE;
162 }
163
164 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
165 {
166     LockModule();
167     return 2; /* non-heap-based object */
168 }
169
170 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
171 {
172     UnlockModule();
173     return 1; /* non-heap-based object */
174 }
175
176 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
177     LPCLASSFACTORY iface,
178     LPUNKNOWN pUnkOuter,
179     REFIID riid,
180     LPVOID *ppvObj)
181 {
182     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
183     return IUnknown_QueryInterface((IUnknown*)&Test_Unknown, riid, ppvObj);
184 }
185
186 static HRESULT WINAPI Test_IClassFactory_LockServer(
187     LPCLASSFACTORY iface,
188     BOOL fLock)
189 {
190     return S_OK;
191 }
192
193 static const IClassFactoryVtbl TestClassFactory_Vtbl =
194 {
195     Test_IClassFactory_QueryInterface,
196     Test_IClassFactory_AddRef,
197     Test_IClassFactory_Release,
198     Test_IClassFactory_CreateInstance,
199     Test_IClassFactory_LockServer
200 };
201
202 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
203
204 #define RELEASEMARSHALDATA WM_USER
205
206 struct host_object_data
207 {
208     IStream *stream;
209     IID iid;
210     IUnknown *object;
211     MSHLFLAGS marshal_flags;
212     HANDLE marshal_event;
213     IMessageFilter *filter;
214 };
215
216 static DWORD CALLBACK host_object_proc(LPVOID p)
217 {
218     struct host_object_data *data = (struct host_object_data *)p;
219     HRESULT hr;
220     MSG msg;
221
222     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
223
224     if (data->filter)
225     {
226         IMessageFilter * prev_filter = NULL;
227         hr = CoRegisterMessageFilter(data->filter, &prev_filter);
228         if (prev_filter) IMessageFilter_Release(prev_filter);
229         ok_ole_success(hr, CoRegisterMessageFilter);
230     }
231
232     hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
233     ok_ole_success(hr, CoMarshalInterface);
234
235     /* force the message queue to be created before signaling parent thread */
236     PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
237
238     SetEvent(data->marshal_event);
239
240     while (GetMessage(&msg, NULL, 0, 0))
241     {
242         if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
243         {
244             trace("releasing marshal data\n");
245             CoReleaseMarshalData(data->stream);
246             SetEvent((HANDLE)msg.lParam);
247         }
248         else
249             DispatchMessage(&msg);
250     }
251
252     HeapFree(GetProcessHeap(), 0, data);
253
254     CoUninitialize();
255
256     return hr;
257 }
258
259 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
260 {
261     DWORD tid = 0;
262     HANDLE marshal_event = CreateEvent(NULL, FALSE, FALSE, NULL);
263     struct host_object_data *data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
264
265     data->stream = stream;
266     data->iid = *riid;
267     data->object = object;
268     data->marshal_flags = marshal_flags;
269     data->marshal_event = marshal_event;
270     data->filter = filter;
271
272     *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
273
274     /* wait for marshaling to complete before returning */
275     WaitForSingleObject(marshal_event, INFINITE);
276     CloseHandle(marshal_event);
277
278     return tid;
279 }
280
281 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
282 {
283     return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
284 }
285
286 /* asks thread to release the marshal data because it has to be done by the
287  * same thread that marshaled the interface in the first place. */
288 static void release_host_object(DWORD tid)
289 {
290     HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
291     PostThreadMessage(tid, RELEASEMARSHALDATA, 0, (LPARAM)event);
292     WaitForSingleObject(event, INFINITE);
293     CloseHandle(event);
294 }
295
296 static void end_host_object(DWORD tid, HANDLE thread)
297 {
298     BOOL ret = PostThreadMessage(tid, WM_QUIT, 0, 0);
299     ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
300     /* be careful of races - don't return until hosting thread has terminated */
301     WaitForSingleObject(thread, INFINITE);
302     CloseHandle(thread);
303 }
304
305 /* tests failure case of interface not having a marshaler specified in the
306  * registry */
307 static void test_no_marshaler(void)
308 {
309     IStream *pStream;
310     HRESULT hr;
311
312     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
313     ok_ole_success(hr, CreateStreamOnHGlobal);
314     hr = CoMarshalInterface(pStream, &IID_IWineTest, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
315     ok(hr == E_NOINTERFACE, "CoMarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
316
317     IStream_Release(pStream);
318 }
319
320 /* tests normal marshal and then release without unmarshaling */
321 static void test_normal_marshal_and_release(void)
322 {
323     HRESULT hr;
324     IStream *pStream = NULL;
325
326     cLocks = 0;
327
328     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
329     ok_ole_success(hr, CreateStreamOnHGlobal);
330     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
331     ok_ole_success(hr, CoMarshalInterface);
332
333     ok_more_than_one_lock();
334
335     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
336     hr = CoReleaseMarshalData(pStream);
337     ok_ole_success(hr, CoReleaseMarshalData);
338     IStream_Release(pStream);
339
340     ok_no_locks();
341 }
342
343 /* tests success case of a same-thread marshal and unmarshal */
344 static void test_normal_marshal_and_unmarshal(void)
345 {
346     HRESULT hr;
347     IStream *pStream = NULL;
348     IUnknown *pProxy = NULL;
349
350     cLocks = 0;
351
352     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
353     ok_ole_success(hr, CreateStreamOnHGlobal);
354     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
355     ok_ole_success(hr, CoMarshalInterface);
356
357     ok_more_than_one_lock();
358     
359     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
360     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
361     ok_ole_success(hr, CoUnmarshalInterface);
362     IStream_Release(pStream);
363
364     ok_more_than_one_lock();
365
366     IUnknown_Release(pProxy);
367
368     ok_no_locks();
369 }
370
371 /* tests failure case of unmarshaling a freed object */
372 static void test_marshal_and_unmarshal_invalid(void)
373 {
374     HRESULT hr;
375     IStream *pStream = NULL;
376     IClassFactory *pProxy = NULL;
377     DWORD tid;
378     void * dummy;
379     HANDLE thread;
380
381     cLocks = 0;
382
383     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
384     ok_ole_success(hr, CreateStreamOnHGlobal);
385     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
386
387     ok_more_than_one_lock();
388         
389     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
390     hr = CoReleaseMarshalData(pStream);
391     ok_ole_success(hr, CoReleaseMarshalData);
392
393     ok_no_locks();
394
395     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
396     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
397     todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
398
399     ok_no_locks();
400
401     if (pProxy)
402     {
403         hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, &dummy);
404         ok(hr == RPC_E_DISCONNECTED, "Remote call should have returned RPC_E_DISCONNECTED, instead of 0x%08x\n", hr);
405
406         IClassFactory_Release(pProxy);
407     }
408
409     IStream_Release(pStream);
410
411     end_host_object(tid, thread);
412 }
413
414 static void test_same_apartment_unmarshal_failure(void)
415 {
416     HRESULT hr;
417     IStream *pStream;
418     IUnknown *pProxy;
419     static const LARGE_INTEGER llZero;
420
421     cLocks = 0;
422
423     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
424     ok_ole_success(hr, CreateStreamOnHGlobal);
425
426     hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
427     ok_ole_success(hr, CoMarshalInterface);
428
429     ok_more_than_one_lock();
430
431     hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
432     ok_ole_success(hr, IStream_Seek);
433
434     hr = CoUnmarshalInterface(pStream, &IID_IParseDisplayName, (void **)&pProxy);
435     ok(hr == E_NOINTERFACE, "CoUnmarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
436
437     ok_no_locks();
438 }
439
440 /* tests success case of an interthread marshal */
441 static void test_interthread_marshal_and_unmarshal(void)
442 {
443     HRESULT hr;
444     IStream *pStream = NULL;
445     IUnknown *pProxy = NULL;
446     DWORD tid;
447     HANDLE thread;
448
449     cLocks = 0;
450
451     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
452     ok_ole_success(hr, CreateStreamOnHGlobal);
453     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
454
455     ok_more_than_one_lock();
456     
457     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
458     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
459     ok_ole_success(hr, CoUnmarshalInterface);
460     IStream_Release(pStream);
461
462     ok_more_than_one_lock();
463
464     IUnknown_Release(pProxy);
465
466     ok_no_locks();
467
468     end_host_object(tid, thread);
469 }
470
471 /* the number of external references that Wine's proxy manager normally gives
472  * out, so we can test the border case of running out of references */
473 #define NORMALEXTREFS 5
474
475 /* tests success case of an interthread marshal and then marshaling the proxy */
476 static void test_proxy_marshal_and_unmarshal(void)
477 {
478     HRESULT hr;
479     IStream *pStream = NULL;
480     IUnknown *pProxy = NULL;
481     IUnknown *pProxy2 = NULL;
482     DWORD tid;
483     HANDLE thread;
484     int i;
485
486     cLocks = 0;
487
488     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
489     ok_ole_success(hr, CreateStreamOnHGlobal);
490     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
491
492     ok_more_than_one_lock();
493     
494     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
495     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
496     ok_ole_success(hr, CoUnmarshalInterface);
497
498     ok_more_than_one_lock();
499
500     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
501     /* marshal the proxy */
502     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
503     ok_ole_success(hr, CoMarshalInterface);
504
505     ok_more_than_one_lock();
506
507     /* marshal 5 more times to exhaust the normal external references of 5 */
508     for (i = 0; i < NORMALEXTREFS; i++)
509     {
510         hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
511         ok_ole_success(hr, CoMarshalInterface);
512     }
513
514     ok_more_than_one_lock();
515
516     /* release the original proxy to test that we successfully keep the
517      * original object alive */
518     IUnknown_Release(pProxy);
519
520     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
521     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
522     ok_ole_success(hr, CoUnmarshalInterface);
523
524     ok_more_than_one_lock();
525
526     /* now the proxies should be as follows:
527      *  pProxy2 -> &Test_ClassFactory
528      * they should NOT be as follows:
529      *  pProxy -> &Test_ClassFactory
530      *  pProxy2 -> pProxy
531      * the above can only really be tested by looking in +ole traces
532      */
533
534     IUnknown_Release(pProxy2);
535
536     /* unmarshal all of the proxies to check that the object stub still exists */
537     for (i = 0; i < NORMALEXTREFS; i++)
538     {
539         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
540         ok_ole_success(hr, CoUnmarshalInterface);
541
542         IUnknown_Release(pProxy2);
543     }
544
545     ok_no_locks();
546
547     IStream_Release(pStream);
548
549     end_host_object(tid, thread);
550 }
551
552 /* tests success case of an interthread marshal and then marshaling the proxy
553  * using an iid that hasn't previously been unmarshaled */
554 static void test_proxy_marshal_and_unmarshal2(void)
555 {
556     HRESULT hr;
557     IStream *pStream = NULL;
558     IUnknown *pProxy = NULL;
559     IUnknown *pProxy2 = NULL;
560     DWORD tid;
561     HANDLE thread;
562
563     cLocks = 0;
564
565     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
566     ok_ole_success(hr, CreateStreamOnHGlobal);
567     tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
568
569     ok_more_than_one_lock();
570
571     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
572     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
573     ok_ole_success(hr, CoUnmarshalInterface);
574
575     ok_more_than_one_lock();
576
577     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
578     /* marshal the proxy */
579     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
580     ok_ole_success(hr, CoMarshalInterface);
581
582     ok_more_than_one_lock();
583
584     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
585     /* unmarshal the second proxy to the object */
586     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
587     ok_ole_success(hr, CoUnmarshalInterface);
588     IStream_Release(pStream);
589
590     /* now the proxies should be as follows:
591      *  pProxy -> &Test_ClassFactory
592      *  pProxy2 -> &Test_ClassFactory
593      * they should NOT be as follows:
594      *  pProxy -> &Test_ClassFactory
595      *  pProxy2 -> pProxy
596      * the above can only really be tested by looking in +ole traces
597      */
598
599     ok_more_than_one_lock();
600
601     IUnknown_Release(pProxy);
602
603     ok_more_than_one_lock();
604
605     IUnknown_Release(pProxy2);
606
607     ok_no_locks();
608
609     end_host_object(tid, thread);
610 }
611
612 /* tests that stubs are released when the containing apartment is destroyed */
613 static void test_marshal_stub_apartment_shutdown(void)
614 {
615     HRESULT hr;
616     IStream *pStream = NULL;
617     IUnknown *pProxy = NULL;
618     DWORD tid;
619     HANDLE thread;
620
621     cLocks = 0;
622
623     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
624     ok_ole_success(hr, CreateStreamOnHGlobal);
625     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
626
627     ok_more_than_one_lock();
628     
629     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
630     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
631     ok_ole_success(hr, CoUnmarshalInterface);
632     IStream_Release(pStream);
633
634     ok_more_than_one_lock();
635
636     end_host_object(tid, thread);
637
638     ok_no_locks();
639
640     IUnknown_Release(pProxy);
641
642     ok_no_locks();
643 }
644
645 /* tests that proxies are released when the containing apartment is destroyed */
646 static void test_marshal_proxy_apartment_shutdown(void)
647 {
648     HRESULT hr;
649     IStream *pStream = NULL;
650     IUnknown *pProxy = NULL;
651     DWORD tid;
652     HANDLE 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, &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, CoUnmarshalInterface);
665     IStream_Release(pStream);
666
667     ok_more_than_one_lock();
668
669     CoUninitialize();
670
671     ok_no_locks();
672
673     IUnknown_Release(pProxy);
674
675     ok_no_locks();
676
677     end_host_object(tid, thread);
678
679     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
680 }
681
682 /* tests that proxies are released when the containing mta apartment is destroyed */
683 static void test_marshal_proxy_mta_apartment_shutdown(void)
684 {
685     HRESULT hr;
686     IStream *pStream = NULL;
687     IUnknown *pProxy = NULL;
688     DWORD tid;
689     HANDLE thread;
690
691     CoUninitialize();
692     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
693
694     cLocks = 0;
695
696     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
697     ok_ole_success(hr, CreateStreamOnHGlobal);
698     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
699
700     ok_more_than_one_lock();
701
702     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
703     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
704     ok_ole_success(hr, CoUnmarshalInterface);
705     IStream_Release(pStream);
706
707     ok_more_than_one_lock();
708
709     CoUninitialize();
710
711     ok_no_locks();
712
713     IUnknown_Release(pProxy);
714
715     ok_no_locks();
716
717     end_host_object(tid, thread);
718
719     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
720 }
721
722 struct ncu_params
723 {
724     LPSTREAM stream;
725     HANDLE marshal_event;
726     HANDLE unmarshal_event;
727 };
728
729 /* helper for test_no_couninitialize_server */
730 static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p)
731 {
732     struct ncu_params *ncu_params = (struct ncu_params *)p;
733     HRESULT hr;
734
735     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
736
737     hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
738     ok_ole_success(hr, CoMarshalInterface);
739
740     SetEvent(ncu_params->marshal_event);
741
742     WaitForSingleObject(ncu_params->unmarshal_event, INFINITE);
743
744     /* die without calling CoUninitialize */
745
746     return 0;
747 }
748
749 /* tests apartment that an apartment with a stub is released without deadlock
750  * if the owning thread exits */
751 static void test_no_couninitialize_server(void)
752 {
753     HRESULT hr;
754     IStream *pStream = NULL;
755     IUnknown *pProxy = NULL;
756     DWORD tid;
757     HANDLE thread;
758     struct ncu_params ncu_params;
759
760     cLocks = 0;
761
762     ncu_params.marshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
763     ncu_params.unmarshal_event = CreateEvent(NULL, TRUE, FALSE, NULL);
764
765     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
766     ok_ole_success(hr, CreateStreamOnHGlobal);
767     ncu_params.stream = pStream;
768
769     thread = CreateThread(NULL, 0, no_couninitialize_server_proc, &ncu_params, 0, &tid);
770
771     WaitForSingleObject(ncu_params.marshal_event, INFINITE);
772     ok_more_than_one_lock();
773
774     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
775     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
776     ok_ole_success(hr, CoUnmarshalInterface);
777     IStream_Release(pStream);
778
779     ok_more_than_one_lock();
780
781     SetEvent(ncu_params.unmarshal_event);
782     WaitForSingleObject(thread, INFINITE);
783
784     ok_no_locks();
785
786     CloseHandle(thread);
787     CloseHandle(ncu_params.marshal_event);
788     CloseHandle(ncu_params.unmarshal_event);
789
790     IUnknown_Release(pProxy);
791
792     ok_no_locks();
793 }
794
795 /* STA -> STA call during DLL_THREAD_DETACH */
796 static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p)
797 {
798     struct ncu_params *ncu_params = (struct ncu_params *)p;
799     HRESULT hr;
800     IUnknown *pProxy = NULL;
801
802     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
803
804     hr = CoUnmarshalInterface(ncu_params->stream, &IID_IClassFactory, (void **)&pProxy);
805     ok_ole_success(hr, CoUnmarshalInterface);
806     IStream_Release(ncu_params->stream);
807
808     ok_more_than_one_lock();
809
810     /* die without calling CoUninitialize */
811
812     return 0;
813 }
814
815 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
816 static void test_no_couninitialize_client(void)
817 {
818     HRESULT hr;
819     IStream *pStream = NULL;
820     DWORD tid;
821     DWORD host_tid;
822     HANDLE thread;
823     HANDLE host_thread;
824     struct ncu_params ncu_params;
825
826     cLocks = 0;
827
828     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
829     ok_ole_success(hr, CreateStreamOnHGlobal);
830     ncu_params.stream = pStream;
831
832     /* NOTE: assumes start_host_object uses an STA to host the object, as MTAs
833      * always deadlock when called from within DllMain */
834     host_tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
835     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
836
837     ok_more_than_one_lock();
838
839     thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
840
841     WaitForSingleObject(thread, INFINITE);
842     CloseHandle(thread);
843
844     ok_no_locks();
845
846     end_host_object(host_tid, host_thread);
847 }
848
849 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
850 static void test_tableweak_marshal_and_unmarshal_twice(void)
851 {
852     HRESULT hr;
853     IStream *pStream = NULL;
854     IUnknown *pProxy1 = NULL;
855     IUnknown *pProxy2 = NULL;
856     DWORD tid;
857     HANDLE thread;
858
859     cLocks = 0;
860
861     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
862     ok_ole_success(hr, CreateStreamOnHGlobal);
863     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
864
865     ok_more_than_one_lock();
866
867     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
868     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
869     ok_ole_success(hr, CoUnmarshalInterface);
870
871     ok_more_than_one_lock();
872
873     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
874     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
875     IStream_Release(pStream);
876     ok_ole_success(hr, CoUnmarshalInterface);
877
878     ok_more_than_one_lock();
879
880     IUnknown_Release(pProxy1);
881     IUnknown_Release(pProxy2);
882
883     /* this line is shows the difference between weak and strong table marshaling:
884      *  weak has cLocks == 0
885      *  strong has cLocks > 0 */
886     ok_no_locks();
887
888     end_host_object(tid, thread);
889 }
890
891 /* tests releasing after unmarshaling one object */
892 static void test_tableweak_marshal_releasedata1(void)
893 {
894     HRESULT hr;
895     IStream *pStream = NULL;
896     IUnknown *pProxy1 = NULL;
897     IUnknown *pProxy2 = NULL;
898     DWORD tid;
899     HANDLE thread;
900
901     cLocks = 0;
902
903     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
904     ok_ole_success(hr, CreateStreamOnHGlobal);
905     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
906
907     ok_more_than_one_lock();
908
909     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
910     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
911     ok_ole_success(hr, CoUnmarshalInterface);
912
913     ok_more_than_one_lock();
914
915     /* release the remaining reference on the object by calling
916      * CoReleaseMarshalData in the hosting thread */
917     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
918     release_host_object(tid);
919
920     ok_more_than_one_lock();
921
922     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
923     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
924     ok_ole_success(hr, CoUnmarshalInterface);
925     IStream_Release(pStream);
926
927     ok_more_than_one_lock();
928
929     IUnknown_Release(pProxy1);
930     if (pProxy2)
931         IUnknown_Release(pProxy2);
932
933     /* this line is shows the difference between weak and strong table marshaling:
934      *  weak has cLocks == 0
935      *  strong has cLocks > 0 */
936     ok_no_locks();
937
938     end_host_object(tid, thread);
939 }
940
941 /* tests releasing after unmarshaling one object */
942 static void test_tableweak_marshal_releasedata2(void)
943 {
944     HRESULT hr;
945     IStream *pStream = NULL;
946     IUnknown *pProxy = NULL;
947     DWORD tid;
948     HANDLE thread;
949
950     cLocks = 0;
951
952     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
953     ok_ole_success(hr, CreateStreamOnHGlobal);
954     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
955
956     ok_more_than_one_lock();
957
958     /* release the remaining reference on the object by calling
959      * CoReleaseMarshalData in the hosting thread */
960     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
961     release_host_object(tid);
962
963     ok_no_locks();
964
965     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
966     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
967     todo_wine
968     {
969     ok(hr == CO_E_OBJNOTREG,
970        "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08x instead\n",
971        hr);
972     }
973     IStream_Release(pStream);
974
975     ok_no_locks();
976
977     end_host_object(tid, thread);
978 }
979
980 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
981 static void test_tablestrong_marshal_and_unmarshal_twice(void)
982 {
983     HRESULT hr;
984     IStream *pStream = NULL;
985     IUnknown *pProxy1 = NULL;
986     IUnknown *pProxy2 = NULL;
987     DWORD tid;
988     HANDLE thread;
989
990     cLocks = 0;
991
992     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
993     ok_ole_success(hr, CreateStreamOnHGlobal);
994     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
995
996     ok_more_than_one_lock();
997
998     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
999     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1000     ok_ole_success(hr, CoUnmarshalInterface);
1001
1002     ok_more_than_one_lock();
1003
1004     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1005     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1006     ok_ole_success(hr, CoUnmarshalInterface);
1007
1008     ok_more_than_one_lock();
1009
1010     if (pProxy1) IUnknown_Release(pProxy1);
1011     if (pProxy2) IUnknown_Release(pProxy2);
1012
1013     /* this line is shows the difference between weak and strong table marshaling:
1014      *  weak has cLocks == 0
1015      *  strong has cLocks > 0 */
1016     ok_more_than_one_lock();
1017
1018     /* release the remaining reference on the object by calling
1019      * CoReleaseMarshalData in the hosting thread */
1020     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1021     release_host_object(tid);
1022     IStream_Release(pStream);
1023
1024     ok_no_locks();
1025
1026     end_host_object(tid, thread);
1027 }
1028
1029 /* tests CoLockObjectExternal */
1030 static void test_lock_object_external(void)
1031 {
1032     HRESULT hr;
1033     IStream *pStream = NULL;
1034
1035     cLocks = 0;
1036
1037     /* test the stub manager creation aspect of CoLockObjectExternal when the
1038      * object hasn't been marshaled yet */
1039     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1040
1041     ok_more_than_one_lock();
1042
1043     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
1044
1045     ok_no_locks();
1046
1047     /* test our empty stub manager being handled correctly in
1048      * CoMarshalInterface */
1049     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1050
1051     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1052     ok_ole_success(hr, CreateStreamOnHGlobal);
1053     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1054     ok_ole_success(hr, CoMarshalInterface);
1055
1056     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1057
1058     ok_more_than_one_lock();
1059
1060     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1061     hr = CoReleaseMarshalData(pStream);
1062     ok_ole_success(hr, CoReleaseMarshalData);
1063     IStream_Release(pStream);
1064
1065     ok_more_than_one_lock();
1066
1067     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
1068
1069     ok_more_than_one_lock();
1070
1071     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
1072
1073     ok_no_locks();
1074 }
1075
1076 /* tests disconnecting stubs */
1077 static void test_disconnect_stub(void)
1078 {
1079     HRESULT hr;
1080     IStream *pStream = NULL;
1081
1082     cLocks = 0;
1083
1084     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1085     ok_ole_success(hr, CreateStreamOnHGlobal);
1086     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1087     ok_ole_success(hr, CoMarshalInterface);
1088
1089     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1090
1091     ok_more_than_one_lock();
1092     
1093     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1094     hr = CoReleaseMarshalData(pStream);
1095     ok_ole_success(hr, CoReleaseMarshalData);
1096     IStream_Release(pStream);
1097
1098     ok_more_than_one_lock();
1099
1100     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
1101
1102     ok_no_locks();
1103 }
1104
1105 /* tests failure case of a same-thread marshal and unmarshal twice */
1106 static void test_normal_marshal_and_unmarshal_twice(void)
1107 {
1108     HRESULT hr;
1109     IStream *pStream = NULL;
1110     IUnknown *pProxy1 = NULL;
1111     IUnknown *pProxy2 = NULL;
1112
1113     cLocks = 0;
1114
1115     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1116     ok_ole_success(hr, CreateStreamOnHGlobal);
1117     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1118     ok_ole_success(hr, CoMarshalInterface);
1119
1120     ok_more_than_one_lock();
1121     
1122     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1123     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1124     ok_ole_success(hr, CoUnmarshalInterface);
1125
1126     ok_more_than_one_lock();
1127
1128     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1129     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1130     ok(hr == CO_E_OBJNOTCONNECTED,
1131         "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08x\n", hr);
1132
1133     IStream_Release(pStream);
1134
1135     ok_more_than_one_lock();
1136
1137     IUnknown_Release(pProxy1);
1138
1139     ok_no_locks();
1140 }
1141
1142 /* tests success case of marshaling and unmarshaling an HRESULT */
1143 static void test_hresult_marshaling(void)
1144 {
1145     HRESULT hr;
1146     HRESULT hr_marshaled = 0;
1147     IStream *pStream = NULL;
1148     static const HRESULT E_DEADBEEF = 0xdeadbeef;
1149
1150     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1151     ok_ole_success(hr, CreateStreamOnHGlobal);
1152
1153     hr = CoMarshalHresult(pStream, E_DEADBEEF);
1154     ok_ole_success(hr, CoMarshalHresult);
1155
1156     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1157     hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
1158     ok_ole_success(hr, IStream_Read);
1159
1160     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
1161
1162     hr_marshaled = 0;
1163     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1164     hr = CoUnmarshalHresult(pStream, &hr_marshaled);
1165     ok_ole_success(hr, CoUnmarshalHresult);
1166
1167     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
1168
1169     IStream_Release(pStream);
1170 }
1171
1172
1173 /* helper for test_proxy_used_in_wrong_thread */
1174 static DWORD CALLBACK bad_thread_proc(LPVOID p)
1175 {
1176     IClassFactory * cf = (IClassFactory *)p;
1177     HRESULT hr;
1178     IUnknown * proxy = NULL;
1179
1180     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1181
1182     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1183     if (proxy) IUnknown_Release(proxy);
1184     ok(hr == RPC_E_WRONG_THREAD,
1185         "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08x\n",
1186         hr);
1187
1188     CoUninitialize();
1189
1190     return 0;
1191 }
1192
1193 /* tests failure case of a using a proxy in the wrong apartment */
1194 static void test_proxy_used_in_wrong_thread(void)
1195 {
1196     HRESULT hr;
1197     IStream *pStream = NULL;
1198     IUnknown *pProxy = NULL;
1199     DWORD tid, tid2;
1200     HANDLE thread;
1201     HANDLE host_thread;
1202
1203     cLocks = 0;
1204
1205     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1206     ok_ole_success(hr, CreateStreamOnHGlobal);
1207     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
1208
1209     ok_more_than_one_lock();
1210     
1211     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1212     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1213     ok_ole_success(hr, CoUnmarshalInterface);
1214     IStream_Release(pStream);
1215
1216     ok_more_than_one_lock();
1217
1218     /* create a thread that we can misbehave in */
1219     thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
1220
1221     WaitForSingleObject(thread, INFINITE);
1222     CloseHandle(thread);
1223
1224     IUnknown_Release(pProxy);
1225
1226     ok_no_locks();
1227
1228     end_host_object(tid, host_thread);
1229 }
1230
1231 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
1232 {
1233     if (ppvObj == NULL) return E_POINTER;
1234
1235     if (IsEqualGUID(riid, &IID_IUnknown) ||
1236         IsEqualGUID(riid, &IID_IClassFactory))
1237     {
1238         *ppvObj = (LPVOID)iface;
1239         IClassFactory_AddRef(iface);
1240         return S_OK;
1241     }
1242
1243     return E_NOINTERFACE;
1244 }
1245
1246 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
1247 {
1248     return 2; /* non-heap object */
1249 }
1250
1251 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
1252 {
1253     return 1; /* non-heap object */
1254 }
1255
1256 static DWORD WINAPI MessageFilter_HandleInComingCall(
1257   IMessageFilter *iface,
1258   DWORD dwCallType,
1259   HTASK threadIDCaller,
1260   DWORD dwTickCount,
1261   LPINTERFACEINFO lpInterfaceInfo)
1262 {
1263     static int callcount = 0;
1264     DWORD ret;
1265     trace("HandleInComingCall\n");
1266     switch (callcount)
1267     {
1268     case 0:
1269         ret = SERVERCALL_REJECTED;
1270         break;
1271     case 1:
1272         ret = SERVERCALL_RETRYLATER;
1273         break;
1274     default:
1275         ret = SERVERCALL_ISHANDLED;
1276         break;
1277     }
1278     callcount++;
1279     return ret;
1280 }
1281
1282 static DWORD WINAPI MessageFilter_RetryRejectedCall(
1283   IMessageFilter *iface,
1284   HTASK threadIDCallee,
1285   DWORD dwTickCount,
1286   DWORD dwRejectType)
1287 {
1288     trace("RetryRejectedCall\n");
1289     return 0;
1290 }
1291
1292 static DWORD WINAPI MessageFilter_MessagePending(
1293   IMessageFilter *iface,
1294   HTASK threadIDCallee,
1295   DWORD dwTickCount,
1296   DWORD dwPendingType)
1297 {
1298     trace("MessagePending\n");
1299     return PENDINGMSG_WAITNOPROCESS;
1300 }
1301
1302 static const IMessageFilterVtbl MessageFilter_Vtbl =
1303 {
1304     MessageFilter_QueryInterface,
1305     MessageFilter_AddRef,
1306     MessageFilter_Release,
1307     MessageFilter_HandleInComingCall,
1308     MessageFilter_RetryRejectedCall,
1309     MessageFilter_MessagePending
1310 };
1311
1312 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
1313
1314 static void test_message_filter(void)
1315 {
1316     HRESULT hr;
1317     IStream *pStream = NULL;
1318     IClassFactory *cf = NULL;
1319     DWORD tid;
1320     IUnknown *proxy = NULL;
1321     IMessageFilter *prev_filter = NULL;
1322     HANDLE thread;
1323
1324     cLocks = 0;
1325
1326     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1327     ok_ole_success(hr, CreateStreamOnHGlobal);
1328     tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
1329
1330     ok_more_than_one_lock();
1331
1332     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1333     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
1334     ok_ole_success(hr, CoUnmarshalInterface);
1335     IStream_Release(pStream);
1336
1337     ok_more_than_one_lock();
1338
1339     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1340     ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08x instead\n", hr);
1341     if (proxy) IUnknown_Release(proxy);
1342     proxy = NULL;
1343
1344     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
1345     ok_ole_success(hr, CoRegisterMessageFilter);
1346
1347     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
1348     ok_ole_success(hr, IClassFactory_CreateInstance);
1349
1350     IUnknown_Release(proxy);
1351
1352     IClassFactory_Release(cf);
1353
1354     ok_no_locks();
1355
1356     end_host_object(tid, thread);
1357
1358     hr = CoRegisterMessageFilter(prev_filter, NULL);
1359     ok_ole_success(hr, CoRegisterMessageFilter);
1360 }
1361
1362 /* test failure case of trying to unmarshal from bad stream */
1363 static void test_bad_marshal_stream(void)
1364 {
1365     HRESULT hr;
1366     IStream *pStream = NULL;
1367
1368     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1369     ok_ole_success(hr, CreateStreamOnHGlobal);
1370     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1371     ok_ole_success(hr, CoMarshalInterface);
1372
1373     ok_more_than_one_lock();
1374
1375     /* try to read beyond end of stream */
1376     hr = CoReleaseMarshalData(pStream);
1377     ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08x instead\n", hr);
1378
1379     /* now release for real */
1380     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1381     hr = CoReleaseMarshalData(pStream);
1382     ok_ole_success(hr, CoReleaseMarshalData);
1383
1384     IStream_Release(pStream);
1385 }
1386
1387 /* tests that proxies implement certain interfaces */
1388 static void test_proxy_interfaces(void)
1389 {
1390     HRESULT hr;
1391     IStream *pStream = NULL;
1392     IUnknown *pProxy = NULL;
1393     IUnknown *pOtherUnknown = NULL;
1394     DWORD tid;
1395     HANDLE thread;
1396
1397     cLocks = 0;
1398
1399     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1400     ok_ole_success(hr, CreateStreamOnHGlobal);
1401     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1402
1403     ok_more_than_one_lock();
1404         
1405     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1406     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
1407     ok_ole_success(hr, CoUnmarshalInterface);
1408     IStream_Release(pStream);
1409
1410     ok_more_than_one_lock();
1411
1412     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
1413     ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
1414     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1415
1416     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
1417     ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity);
1418     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1419
1420     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
1421     ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
1422     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1423
1424     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
1425     ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal);
1426     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
1427
1428     /* IMarshal2 is also supported on NT-based systems, but is pretty much
1429      * useless as it has no more methods over IMarshal that it inherits from. */
1430
1431     IUnknown_Release(pProxy);
1432
1433     ok_no_locks();
1434
1435     end_host_object(tid, thread);
1436 }
1437
1438 typedef struct
1439 {
1440     const IUnknownVtbl *lpVtbl;
1441     ULONG refs;
1442 } HeapUnknown;
1443
1444 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1445 {
1446     if (IsEqualIID(riid, &IID_IUnknown))
1447     {
1448         IUnknown_AddRef(iface);
1449         *ppv = (LPVOID)iface;
1450         return S_OK;
1451     }
1452     *ppv = NULL;
1453     return E_NOINTERFACE;
1454 }
1455
1456 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
1457 {
1458     HeapUnknown *This = (HeapUnknown *)iface;
1459     return InterlockedIncrement((LONG*)&This->refs);
1460 }
1461
1462 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
1463 {
1464     HeapUnknown *This = (HeapUnknown *)iface;
1465     ULONG refs = InterlockedDecrement((LONG*)&This->refs);
1466     if (!refs) HeapFree(GetProcessHeap(), 0, This);
1467     return refs;
1468 }
1469
1470 static const IUnknownVtbl HeapUnknown_Vtbl =
1471 {
1472     HeapUnknown_QueryInterface,
1473     HeapUnknown_AddRef,
1474     HeapUnknown_Release
1475 };
1476
1477 static void test_proxybuffer(REFIID riid)
1478 {
1479     HRESULT hr;
1480     IPSFactoryBuffer *psfb;
1481     IRpcProxyBuffer *proxy;
1482     LPVOID lpvtbl;
1483     ULONG refs;
1484     CLSID clsid;
1485     HeapUnknown *pUnkOuter = (HeapUnknown *)HeapAlloc(GetProcessHeap(), 0, sizeof(*pUnkOuter));
1486
1487     pUnkOuter->lpVtbl = &HeapUnknown_Vtbl;
1488     pUnkOuter->refs = 1;
1489
1490     hr = CoGetPSClsid(riid, &clsid);
1491     ok_ole_success(hr, CoGetPSClsid);
1492
1493     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1494     ok_ole_success(hr, CoGetClassObject);
1495
1496     hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown*)pUnkOuter, riid, &proxy, &lpvtbl);
1497     ok_ole_success(hr, IPSFactoryBuffer_CreateProxy);
1498     ok(lpvtbl != NULL, "IPSFactoryBuffer_CreateProxy succeeded, but returned a NULL vtable!\n");
1499
1500     /* release our reference to the outer unknown object - the PS factory
1501      * buffer will have AddRef's it in the CreateProxy call */
1502     refs = IUnknown_Release((IUnknown *)pUnkOuter);
1503     ok(refs == 1, "Ref count of outer unknown should have been 1 instead of %d\n", refs);
1504
1505     refs = IPSFactoryBuffer_Release(psfb);
1506     if (0)
1507     {
1508     /* not reliable on native. maybe it leaks references! */
1509     ok(refs == 0, "Ref-count leak of %d on IPSFactoryBuffer\n", refs);
1510     }
1511
1512     refs = IUnknown_Release((IUnknown *)lpvtbl);
1513     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
1514
1515     refs = IRpcProxyBuffer_Release(proxy);
1516     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
1517 }
1518
1519 static void test_stubbuffer(REFIID riid)
1520 {
1521     HRESULT hr;
1522     IPSFactoryBuffer *psfb;
1523     IRpcStubBuffer *stub;
1524     ULONG refs;
1525     CLSID clsid;
1526
1527     cLocks = 0;
1528
1529     hr = CoGetPSClsid(riid, &clsid);
1530     ok_ole_success(hr, CoGetPSClsid);
1531
1532     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
1533     ok_ole_success(hr, CoGetClassObject);
1534
1535     hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
1536     ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
1537
1538     refs = IPSFactoryBuffer_Release(psfb);
1539     if (0)
1540     {
1541     /* not reliable on native. maybe it leaks references */
1542     ok(refs == 0, "Ref-count leak of %d on IPSFactoryBuffer\n", refs);
1543     }
1544
1545     ok_more_than_one_lock();
1546
1547     IRpcStubBuffer_Disconnect(stub);
1548
1549     ok_no_locks();
1550
1551     refs = IRpcStubBuffer_Release(stub);
1552     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
1553 }
1554
1555 static HWND hwnd_app;
1556
1557 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
1558     LPCLASSFACTORY iface,
1559     LPUNKNOWN pUnkOuter,
1560     REFIID riid,
1561     LPVOID *ppvObj)
1562 {
1563     DWORD_PTR res;
1564     if (IsEqualIID(riid, &IID_IWineTest))
1565     {
1566         BOOL ret = SendMessageTimeout(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
1567         ok(ret, "Timed out sending a message to originating window during RPC call\n");
1568     }
1569     return S_FALSE;
1570 }
1571
1572 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
1573 {
1574     Test_IClassFactory_QueryInterface,
1575     Test_IClassFactory_AddRef,
1576     Test_IClassFactory_Release,
1577     TestRE_IClassFactory_CreateInstance,
1578     Test_IClassFactory_LockServer
1579 };
1580
1581 IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
1582
1583 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
1584 {
1585     switch (msg)
1586     {
1587     case WM_USER:
1588     {
1589         HRESULT hr;
1590         IStream *pStream = NULL;
1591         IClassFactory *proxy = NULL;
1592         IUnknown *object;
1593         DWORD tid;
1594         HANDLE thread;
1595
1596         cLocks = 0;
1597
1598         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1599         ok_ole_success(hr, CreateStreamOnHGlobal);
1600         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1601
1602         ok_more_than_one_lock();
1603
1604         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1605         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1606         ok_ole_success(hr, CoReleaseMarshalData);
1607         IStream_Release(pStream);
1608
1609         ok_more_than_one_lock();
1610
1611         /* note the use of the magic IID_IWineTest value to tell remote thread
1612          * to try to send a message back to us */
1613         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IWineTest, (void **)&object);
1614
1615         IClassFactory_Release(proxy);
1616
1617         ok_no_locks();
1618
1619         end_host_object(tid, thread);
1620
1621         PostMessage(hwnd, WM_QUIT, 0, 0);
1622
1623         return 0;
1624     }
1625     case WM_USER+1:
1626     {
1627         HRESULT hr;
1628         IStream *pStream = NULL;
1629         IClassFactory *proxy = NULL;
1630         IUnknown *object;
1631         DWORD tid;
1632         HANDLE thread;
1633
1634         cLocks = 0;
1635
1636         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1637         ok_ole_success(hr, CreateStreamOnHGlobal);
1638         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1639
1640         ok_more_than_one_lock();
1641
1642         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1643         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1644         ok_ole_success(hr, CoReleaseMarshalData);
1645         IStream_Release(pStream);
1646
1647         ok_more_than_one_lock();
1648
1649         /* post quit message before a doing a COM call to show that a pending
1650         * WM_QUIT message doesn't stop the call from succeeding */
1651         PostMessage(hwnd, WM_QUIT, 0, 0);
1652         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1653
1654         IClassFactory_Release(proxy);
1655
1656         ok_no_locks();
1657
1658         end_host_object(tid, thread);
1659
1660         return 0;
1661     }
1662     case WM_USER+2:
1663     {
1664         HRESULT hr;
1665         IStream *pStream = NULL;
1666         IClassFactory *proxy = NULL;
1667         IUnknown *object;
1668         DWORD tid;
1669         HANDLE thread;
1670
1671         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1672         ok_ole_success(hr, CreateStreamOnHGlobal);
1673         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1674
1675         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1676         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1677         ok_ole_success(hr, CoReleaseMarshalData);
1678         IStream_Release(pStream);
1679
1680         /* shows that COM calls executed during the processing of sent
1681          * messages should fail */
1682         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1683         ok(hr == RPC_E_CANTCALLOUT_ININPUTSYNCCALL,
1684            "COM call during processing of sent message should return RPC_E_CANTCALLOUT_ININPUTSYNCCALL instead of 0x%08x\n", hr);
1685
1686         IClassFactory_Release(proxy);
1687
1688         end_host_object(tid, thread);
1689
1690         PostQuitMessage(0);
1691
1692         return 0;
1693     }
1694     default:
1695         return DefWindowProc(hwnd, msg, wparam, lparam);
1696     }
1697 }
1698
1699 static void test_message_reentrancy(void)
1700 {
1701     WNDCLASS wndclass;
1702     MSG msg;
1703
1704     memset(&wndclass, 0, sizeof(wndclass));
1705     wndclass.lpfnWndProc = window_proc;
1706     wndclass.lpszClassName = "WineCOMTest";
1707     RegisterClass(&wndclass);
1708
1709     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1710     ok(hwnd_app != NULL, "Window creation failed\n");
1711
1712     /* start message re-entrancy test */
1713     PostMessage(hwnd_app, WM_USER, 0, 0);
1714
1715     while (GetMessage(&msg, NULL, 0, 0))
1716     {
1717         TranslateMessage(&msg);
1718         DispatchMessage(&msg);
1719     }
1720 }
1721
1722 static HRESULT WINAPI TestMsg_IClassFactory_CreateInstance(
1723     LPCLASSFACTORY iface,
1724     LPUNKNOWN pUnkOuter,
1725     REFIID riid,
1726     LPVOID *ppvObj)
1727 {
1728     *ppvObj = NULL;
1729     SendMessage(hwnd_app, WM_USER+2, 0, 0);
1730     return S_OK;
1731 }
1732
1733 static IClassFactoryVtbl TestMsgClassFactory_Vtbl =
1734 {
1735     Test_IClassFactory_QueryInterface,
1736     Test_IClassFactory_AddRef,
1737     Test_IClassFactory_Release,
1738     TestMsg_IClassFactory_CreateInstance,
1739     Test_IClassFactory_LockServer
1740 };
1741
1742 IClassFactory TestMsg_ClassFactory = { &TestMsgClassFactory_Vtbl };
1743
1744 static void test_call_from_message(void)
1745 {
1746     MSG msg;
1747     IStream *pStream;
1748     HRESULT hr;
1749     IClassFactory *proxy;
1750     DWORD tid;
1751     HANDLE thread;
1752     IUnknown *object;
1753
1754     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1755     ok(hwnd_app != NULL, "Window creation failed\n");
1756
1757     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1758     ok_ole_success(hr, CreateStreamOnHGlobal);
1759     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestMsg_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1760
1761     ok_more_than_one_lock();
1762
1763     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1764     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
1765     ok_ole_success(hr, CoReleaseMarshalData);
1766     IStream_Release(pStream);
1767
1768     ok_more_than_one_lock();
1769
1770     /* start message re-entrancy test */
1771     hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
1772     ok_ole_success(hr, IClassFactory_CreateInstance);
1773
1774     IClassFactory_Release(proxy);
1775
1776     ok_no_locks();
1777
1778     end_host_object(tid, thread);
1779
1780     while (GetMessage(&msg, NULL, 0, 0))
1781     {
1782         TranslateMessage(&msg);
1783         DispatchMessage(&msg);
1784     }
1785 }
1786
1787 static void test_WM_QUIT_handling(void)
1788 {
1789     MSG msg;
1790
1791     hwnd_app = CreateWindow("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
1792     ok(hwnd_app != NULL, "Window creation failed\n");
1793
1794     /* start WM_QUIT handling test */
1795     PostMessage(hwnd_app, WM_USER+1, 0, 0);
1796
1797     while (GetMessage(&msg, NULL, 0, 0))
1798     {
1799         TranslateMessage(&msg);
1800         DispatchMessage(&msg);
1801     }
1802 }
1803
1804 static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void *ptr, DWORD mshlflags)
1805 {
1806     HGLOBAL hglobal;
1807     DWORD size;
1808     char *marshal_data;
1809     HRESULT hr;
1810
1811     hr = GetHGlobalFromStream(pStream, &hglobal);
1812     ok_ole_success(hr, GetHGlobalFromStream);
1813
1814     size = GlobalSize(hglobal);
1815
1816     marshal_data = (char *)GlobalLock(hglobal);
1817
1818     if (mshctx == MSHCTX_INPROC)
1819     {
1820         DWORD expected_size = sizeof(DWORD) + sizeof(void *) + sizeof(DWORD) + sizeof(GUID);
1821         ok(size == expected_size, "size should have been %d instead of %d\n", expected_size, size);
1822
1823         ok(*(DWORD *)marshal_data == mshlflags, "expected 0x%x, but got 0x%x for mshctx\n", mshlflags, *(DWORD *)marshal_data);
1824         marshal_data += sizeof(DWORD);
1825         ok(*(void **)marshal_data == ptr, "expected %p, but got %p for mshctx\n", ptr, *(void **)marshal_data);
1826         marshal_data += sizeof(void *);
1827         ok(*(DWORD *)marshal_data == 0, "expected 0x0, but got 0x%x\n", *(DWORD *)marshal_data);
1828         marshal_data += sizeof(DWORD);
1829         trace("got guid data: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
1830             ((GUID *)marshal_data)->Data1, ((GUID *)marshal_data)->Data2, ((GUID *)marshal_data)->Data3,
1831             ((GUID *)marshal_data)->Data4[0], ((GUID *)marshal_data)->Data4[1], ((GUID *)marshal_data)->Data4[2], ((GUID *)marshal_data)->Data4[3],
1832             ((GUID *)marshal_data)->Data4[4], ((GUID *)marshal_data)->Data4[5], ((GUID *)marshal_data)->Data4[6], ((GUID *)marshal_data)->Data4[7]);
1833     }
1834     else
1835     {
1836         ok(size > sizeof(DWORD), "size should have been > sizeof(DWORD), not %d\n", size);
1837         ok(*(DWORD *)marshal_data == 0x574f454d /* MEOW */,
1838             "marshal data should be filled by standard marshal and start with MEOW signature\n");
1839     }
1840
1841     GlobalUnlock(hglobal);
1842 }
1843
1844 static void test_freethreadedmarshaler(void)
1845 {
1846     HRESULT hr;
1847     IUnknown *pFTUnknown;
1848     IMarshal *pFTMarshal;
1849     IStream *pStream;
1850     IUnknown *pProxy;
1851     static const LARGE_INTEGER llZero;
1852
1853     cLocks = 0;
1854     hr = CoCreateFreeThreadedMarshaler(NULL, &pFTUnknown);
1855     ok_ole_success(hr, CoCreateFreeThreadedMarshaler);
1856     hr = IUnknown_QueryInterface(pFTUnknown, &IID_IMarshal, (void **)&pFTMarshal);
1857     ok_ole_success(hr, IUnknown_QueryInterface);
1858     IUnknown_Release(pFTUnknown);
1859
1860     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1861     ok_ole_success(hr, CreateStreamOnHGlobal);
1862
1863     /* inproc normal marshaling */
1864
1865     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
1866         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1867     ok_ole_success(hr, IMarshal_MarshalInterface);
1868
1869     ok_more_than_one_lock();
1870
1871     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_NORMAL);
1872
1873     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1874     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
1875     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1876
1877     IUnknown_Release(pProxy);
1878
1879     ok_no_locks();
1880
1881 /* native doesn't allow us to unmarshal or release the stream data,
1882  * presumably because it wants us to call CoMarshalInterface instead */
1883     if (0)
1884     {
1885     /* local normal marshaling */
1886
1887     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1888     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
1889     ok_ole_success(hr, IMarshal_MarshalInterface);
1890
1891     ok_more_than_one_lock();
1892
1893     test_freethreadedmarshaldata(pStream, MSHCTX_LOCAL, &Test_ClassFactory, MSHLFLAGS_NORMAL);
1894
1895     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1896     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
1897     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1898
1899     ok_no_locks();
1900     }
1901
1902     /* inproc table-strong marshaling */
1903
1904     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1905     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
1906         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
1907         MSHLFLAGS_TABLESTRONG);
1908     ok_ole_success(hr, IMarshal_MarshalInterface);
1909
1910     ok_more_than_one_lock();
1911
1912     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLESTRONG);
1913
1914     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1915     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
1916     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1917
1918     IUnknown_Release(pProxy);
1919
1920     ok_more_than_one_lock();
1921
1922     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1923     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
1924     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1925
1926     ok_no_locks();
1927
1928     /* inproc table-weak marshaling */
1929
1930     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1931     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
1932         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
1933         MSHLFLAGS_TABLEWEAK);
1934     ok_ole_success(hr, IMarshal_MarshalInterface);
1935
1936     ok_no_locks();
1937
1938     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLEWEAK);
1939
1940     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1941     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
1942     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1943
1944     ok_more_than_one_lock();
1945
1946     IUnknown_Release(pProxy);
1947
1948     ok_no_locks();
1949
1950     /* inproc normal marshaling (for extraordinary cases) */
1951
1952     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1953     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
1954         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1955     ok_ole_success(hr, IMarshal_MarshalInterface);
1956
1957     ok_more_than_one_lock();
1958
1959     /* this call shows that DisconnectObject does nothing */
1960     hr = IMarshal_DisconnectObject(pFTMarshal, 0);
1961     ok_ole_success(hr, IMarshal_DisconnectObject);
1962
1963     ok_more_than_one_lock();
1964
1965     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1966     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
1967     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
1968
1969     ok_no_locks();
1970
1971     /* doesn't enforce marshaling rules here and allows us to unmarshal the
1972      * interface, even though it was freed above */
1973     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
1974     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
1975     ok_ole_success(hr, IMarshal_UnmarshalInterface);
1976
1977     ok_no_locks();
1978
1979     IStream_Release(pStream);
1980     IMarshal_Release(pFTMarshal);
1981 }
1982
1983 static void test_inproc_handler(void)
1984 {
1985     HRESULT hr;
1986     IUnknown *pObject;
1987     IUnknown *pObject2;
1988     char buffer[256];
1989     LPOLESTR pszClsid;
1990     HKEY hkey;
1991     DWORD dwDisposition;
1992     DWORD error;
1993
1994     hr = StringFromCLSID(&CLSID_WineTest, &pszClsid);
1995     ok_ole_success(hr, "StringFromCLSID");
1996     strcpy(buffer, "CLSID\\");
1997     WideCharToMultiByte(CP_ACP, 0, pszClsid, -1, buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), NULL, NULL);
1998     CoTaskMemFree(pszClsid);
1999     strcat(buffer, "\\InprocHandler32");
2000     error = RegCreateKeyEx(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
2001     ok(error == ERROR_SUCCESS, "RegCreateKeyEx failed with error %d\n", error);
2002     error = RegSetValueEx(hkey, NULL, 0, REG_SZ, (const unsigned char *)"ole32.dll", strlen("ole32.dll") + 1);
2003     ok(error == ERROR_SUCCESS, "RegSetValueEx failed with error %d\n", error);
2004     RegCloseKey(hkey);
2005
2006     hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pObject);
2007     todo_wine
2008     ok_ole_success(hr, "CoCreateInstance");
2009
2010     if (SUCCEEDED(hr))
2011     {
2012         hr = IUnknown_QueryInterface(pObject, &IID_IWineTest, (void **)&pObject2);
2013         ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface on handler for invalid interface returned 0x%08x instead of E_NOINTERFACE\n", hr);
2014
2015         /* it's a handler as it supports IOleObject */
2016         hr = IUnknown_QueryInterface(pObject, &IID_IOleObject, (void **)&pObject2);
2017         ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
2018         IUnknown_Release(pObject2);
2019
2020         IUnknown_Release(pObject);
2021     }
2022
2023     RegDeleteKey(HKEY_CLASSES_ROOT, buffer);
2024     *strrchr(buffer, '\\') = '\0';
2025     RegDeleteKey(HKEY_CLASSES_ROOT, buffer);
2026 }
2027
2028 static HRESULT WINAPI Test_SMI_QueryInterface(
2029     IStdMarshalInfo *iface,
2030     REFIID riid,
2031     LPVOID *ppvObj)
2032 {
2033     if (ppvObj == NULL) return E_POINTER;
2034
2035     if (IsEqualGUID(riid, &IID_IUnknown) ||
2036         IsEqualGUID(riid, &IID_IStdMarshalInfo))
2037     {
2038         *ppvObj = (LPVOID)iface;
2039         IClassFactory_AddRef(iface);
2040         return S_OK;
2041     }
2042
2043     return E_NOINTERFACE;
2044 }
2045
2046 static ULONG WINAPI Test_SMI_AddRef(IStdMarshalInfo *iface)
2047 {
2048     LockModule();
2049     return 2; /* non-heap-based object */
2050 }
2051
2052 static ULONG WINAPI Test_SMI_Release(IStdMarshalInfo *iface)
2053 {
2054     UnlockModule();
2055     return 1; /* non-heap-based object */
2056 }
2057
2058 static HRESULT WINAPI Test_SMI_GetClassForHandler(
2059     IStdMarshalInfo *iface,
2060     DWORD dwDestContext,
2061     void *pvDestContext,
2062     CLSID *pClsid)
2063 {
2064     *pClsid = CLSID_WineTest;
2065     return S_OK;
2066 }
2067
2068 static const IStdMarshalInfoVtbl Test_SMI_Vtbl =
2069 {
2070     Test_SMI_QueryInterface,
2071     Test_SMI_AddRef,
2072     Test_SMI_Release,
2073     Test_SMI_GetClassForHandler
2074 };
2075
2076 static IStdMarshalInfo Test_SMI = {&Test_SMI_Vtbl};
2077
2078 static void test_handler_marshaling(void)
2079 {
2080     HRESULT hr;
2081     IStream *pStream = NULL;
2082     IUnknown *pProxy = NULL;
2083     IUnknown *pObject;
2084     DWORD tid;
2085     HANDLE thread;
2086     static const LARGE_INTEGER ullZero;
2087
2088     cLocks = 0;
2089
2090     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2091     ok_ole_success(hr, "CreateStreamOnHGlobal");
2092     tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_SMI, MSHLFLAGS_NORMAL, &thread);
2093
2094     ok_more_than_one_lock();
2095
2096     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2097     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
2098     ok_ole_success(hr, "CoUnmarshalInterface");
2099     IStream_Release(pStream);
2100
2101     ok_more_than_one_lock();
2102
2103     hr = IUnknown_QueryInterface(pProxy, &IID_IWineTest, (void **)&pObject);
2104     ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface with unknown IID should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
2105
2106     /* it's a handler as it supports IOleObject */
2107     hr = IUnknown_QueryInterface(pProxy, &IID_IOleObject, (void **)&pObject);
2108     todo_wine
2109     ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
2110     if (SUCCEEDED(hr)) IUnknown_Release(pObject);
2111
2112     IUnknown_Release(pProxy);
2113
2114     ok_no_locks();
2115
2116     end_host_object(tid, thread);
2117
2118     /* FIXME: test IPersist interface has the same effect as IStdMarshalInfo */
2119 }
2120
2121
2122 static void test_client_security(void)
2123 {
2124     HRESULT hr;
2125     IStream *pStream = NULL;
2126     IClassFactory *pProxy = NULL;
2127     IUnknown *pProxy2 = NULL;
2128     IUnknown *pUnknown1 = NULL;
2129     IUnknown *pUnknown2 = NULL;
2130     IClientSecurity *pCliSec = NULL;
2131     IMarshal *pMarshal;
2132     DWORD tid;
2133     HANDLE thread;
2134     static const LARGE_INTEGER ullZero;
2135     DWORD dwAuthnSvc;
2136     DWORD dwAuthzSvc;
2137     OLECHAR *pServerPrincName;
2138     DWORD dwAuthnLevel;
2139     DWORD dwImpLevel;
2140     void *pAuthInfo;
2141     DWORD dwCapabilities;
2142     void *pv;
2143
2144     cLocks = 0;
2145
2146     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2147     ok_ole_success(hr, "CreateStreamOnHGlobal");
2148     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2149
2150     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2151     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
2152     ok_ole_success(hr, "CoUnmarshalInterface");
2153     IStream_Release(pStream);
2154
2155     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pUnknown1);
2156     ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
2157
2158     hr = IUnknown_QueryInterface(pProxy, &IID_IRemUnknown, (LPVOID*)&pProxy2);
2159     ok_ole_success(hr, "IUnknown_QueryInterface IID_IStream");
2160
2161     hr = IUnknown_QueryInterface(pProxy2, &IID_IUnknown, (LPVOID*)&pUnknown2);
2162     ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
2163
2164     ok(pUnknown1 == pUnknown2, "both proxy's IUnknowns should be the same - %p, %p\n", pUnknown1, pUnknown2);
2165
2166     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pMarshal);
2167     ok_ole_success(hr, "IUnknown_QueryInterface IID_IMarshal");
2168
2169     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pCliSec);
2170     ok_ole_success(hr, "IUnknown_QueryInterface IID_IClientSecurity");
2171
2172     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2173     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket (all NULLs)");
2174
2175     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pMarshal, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
2176     todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_QueryBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
2177
2178     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
2179     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket");
2180
2181     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, RPC_C_IMP_LEVEL_IMPERSONATE, pAuthInfo, dwCapabilities);
2182     todo_wine ok_ole_success(hr, "IClientSecurity_SetBlanket");
2183
2184     hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IWineTest, &pv);
2185     ok(hr == E_NOINTERFACE, "COM call should have succeeded instead of returning 0x%08x\n", hr);
2186
2187     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pMarshal, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
2188     todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_SetBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
2189
2190     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, 0xdeadbeef, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
2191     todo_wine ok(hr == E_INVALIDARG, "IClientSecurity_SetBlanke with invalid dwAuthnSvc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
2192
2193     CoTaskMemFree(pServerPrincName);
2194
2195     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pUnknown1, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
2196     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket(IUnknown)");
2197
2198     CoTaskMemFree(pServerPrincName);
2199
2200     IClassFactory_Release(pProxy);
2201     IUnknown_Release(pProxy2);
2202     IUnknown_Release(pUnknown1);
2203     IUnknown_Release(pUnknown2);
2204     IMarshal_Release(pMarshal);
2205     IClientSecurity_Release(pCliSec);
2206
2207     end_host_object(tid, thread);
2208 }
2209
2210 static HANDLE heventShutdown;
2211
2212 static void LockModuleOOP(void)
2213 {
2214     InterlockedIncrement(&cLocks); /* for test purposes only */
2215     CoAddRefServerProcess();
2216 }
2217
2218 static void UnlockModuleOOP(void)
2219 {
2220     InterlockedDecrement(&cLocks); /* for test purposes only */
2221     if (!CoReleaseServerProcess())
2222         SetEvent(heventShutdown);
2223 }
2224
2225 static HWND hwnd_app;
2226
2227 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
2228     LPCLASSFACTORY iface,
2229     REFIID riid,
2230     LPVOID *ppvObj)
2231 {
2232     if (ppvObj == NULL) return E_POINTER;
2233
2234     if (IsEqualGUID(riid, &IID_IUnknown) ||
2235         IsEqualGUID(riid, &IID_IClassFactory))
2236     {
2237         *ppvObj = (LPVOID)iface;
2238         IClassFactory_AddRef(iface);
2239         return S_OK;
2240     }
2241
2242     return E_NOINTERFACE;
2243 }
2244
2245 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
2246 {
2247     return 2; /* non-heap-based object */
2248 }
2249
2250 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
2251 {
2252     return 1; /* non-heap-based object */
2253 }
2254
2255 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
2256     LPCLASSFACTORY iface,
2257     LPUNKNOWN pUnkOuter,
2258     REFIID riid,
2259     LPVOID *ppvObj)
2260 {
2261     if (IsEqualIID(riid, &IID_IClassFactory) || IsEqualIID(riid, &IID_IUnknown))
2262     {
2263         *ppvObj = iface;
2264         return S_OK;
2265     }
2266     return CLASS_E_CLASSNOTAVAILABLE;
2267 }
2268
2269 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
2270     LPCLASSFACTORY iface,
2271     BOOL fLock)
2272 {
2273     if (fLock)
2274         LockModuleOOP();
2275     else
2276         UnlockModuleOOP();
2277     return S_OK;
2278 }
2279
2280 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
2281 {
2282     TestOOP_IClassFactory_QueryInterface,
2283     TestOOP_IClassFactory_AddRef,
2284     TestOOP_IClassFactory_Release,
2285     TestOOP_IClassFactory_CreateInstance,
2286     TestOOP_IClassFactory_LockServer
2287 };
2288
2289 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
2290
2291 static void test_register_local_server(void)
2292 {
2293     DWORD cookie;
2294     HRESULT hr;
2295     HANDLE ready_event;
2296     HANDLE quit_event;
2297     DWORD wait;
2298
2299     heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
2300
2301     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
2302                                CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
2303     ok_ole_success(hr, CoRegisterClassObject);
2304
2305     ready_event = CreateEvent(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
2306     SetEvent(ready_event);
2307
2308     quit_event = CreateEvent(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
2309
2310     do
2311     {
2312         wait = MsgWaitForMultipleObjects(1, &quit_event, FALSE, INFINITE, QS_ALLINPUT);
2313         if (wait == WAIT_OBJECT_0+1)
2314         {
2315             MSG msg;
2316             BOOL ret = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
2317             if (ret)
2318             {
2319                 trace("Message 0x%x\n", msg.message);
2320                 TranslateMessage(&msg);
2321                 DispatchMessage(&msg);
2322             }
2323         }
2324     }
2325     while (wait == WAIT_OBJECT_0+1);
2326
2327     hr = CoRevokeClassObject(cookie);
2328     ok_ole_success(hr, CoRevokeClassObject);
2329 }
2330
2331 static HANDLE create_target_process(const char *arg)
2332 {
2333     char **argv;
2334     char cmdline[MAX_PATH];
2335     PROCESS_INFORMATION pi;
2336     STARTUPINFO si = { 0 };
2337     si.cb = sizeof(si);
2338
2339     winetest_get_mainargs( &argv );
2340     sprintf(cmdline, "%s %s %s", argv[0], argv[1], arg);
2341     ok(CreateProcess(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL,
2342                      &si, &pi) != 0, "error: %u\n", GetLastError());
2343     ok(CloseHandle(pi.hThread) != 0, "error %u\n", GetLastError());
2344     return pi.hProcess;
2345 }
2346
2347 /* tests functions commonly used by out of process COM servers */
2348 static void test_local_server(void)
2349 {
2350     DWORD cookie;
2351     HRESULT hr;
2352     IClassFactory * cf;
2353     DWORD ret;
2354     HANDLE process;
2355     HANDLE quit_event;
2356     HANDLE ready_event;
2357
2358     heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
2359
2360     cLocks = 0;
2361
2362     /* Start the object suspended */
2363     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
2364         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
2365     ok_ole_success(hr, CoRegisterClassObject);
2366
2367     /* ... and CoGetClassObject does not find it and fails when it looks for the
2368      * class in the registry */
2369     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
2370         NULL, &IID_IClassFactory, (LPVOID*)&cf);
2371     ok(hr == REGDB_E_CLASSNOTREG || /* NT */
2372        hr == S_OK /* Win9x */,
2373         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
2374
2375     /* Resume the object suspended above ... */
2376     hr = CoResumeClassObjects();
2377     ok_ole_success(hr, CoResumeClassObjects);
2378
2379     /* ... and now it should succeed */
2380     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
2381         NULL, &IID_IClassFactory, (LPVOID*)&cf);
2382     ok_ole_success(hr, CoGetClassObject);
2383
2384     /* Now check the locking is working */
2385     /* NOTE: we are accessing the class directly, not through a proxy */
2386
2387     ok_no_locks();
2388
2389     hr = IClassFactory_LockServer(cf, TRUE);
2390     ok_ole_success(hr, IClassFactory_LockServer);
2391
2392     ok_more_than_one_lock();
2393     
2394     IClassFactory_LockServer(cf, FALSE);
2395     ok_ole_success(hr, IClassFactory_LockServer);
2396
2397     ok_no_locks();
2398
2399     IClassFactory_Release(cf);
2400
2401     /* wait for shutdown signal */
2402     ret = WaitForSingleObject(heventShutdown, 0);
2403     ok(ret != WAIT_TIMEOUT, "Server didn't shut down\n");
2404
2405     /* try to connect again after SCM has suspended registered class objects */
2406     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
2407         &IID_IClassFactory, (LPVOID*)&cf);
2408     ok(hr == CO_E_SERVER_STOPPING || /* NT */
2409        hr == S_OK /* Win9x */,
2410         "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08x\n", hr);
2411
2412     hr = CoRevokeClassObject(cookie);
2413     ok_ole_success(hr, CoRevokeClassObject);
2414
2415     CloseHandle(heventShutdown);
2416
2417     process = create_target_process("-Embedding");
2418     ok(process != NULL, "couldn't start local server process, error was %d\n", GetLastError());
2419
2420     ready_event = CreateEvent(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
2421     WaitForSingleObject(ready_event, 1000);
2422     CloseHandle(ready_event);
2423
2424     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IClassFactory, (void **)&cf);
2425     ok_ole_success(hr, CoCreateInstance);
2426
2427     IClassFactory_Release(cf);
2428
2429     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IClassFactory, (void **)&cf);
2430     ok(hr == REGDB_E_CLASSNOTREG, "Second CoCreateInstance on REGCLS_SINGLEUSE object should have failed\n");
2431
2432     quit_event = CreateEvent(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
2433     SetEvent(quit_event);
2434
2435     WaitForSingleObject(process, INFINITE);
2436     CloseHandle(quit_event);
2437     CloseHandle(process);
2438 }
2439
2440 struct git_params
2441 {
2442         DWORD cookie;
2443         IGlobalInterfaceTable *git;
2444 };
2445
2446 static DWORD CALLBACK get_global_interface_proc(LPVOID pv)
2447 {
2448         HRESULT hr;
2449         struct git_params *params = (struct git_params *)pv;
2450         IClassFactory *cf;
2451
2452         hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
2453         ok(hr == CO_E_NOTINITIALIZED,
2454                 "IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED instead of 0x%08x\n",
2455                 hr);
2456
2457         CoInitialize(NULL);
2458         hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
2459         ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
2460
2461         IGlobalInterfaceTable_Release(params->git);
2462
2463         CoUninitialize();
2464
2465         return hr;
2466 }
2467
2468 static void test_globalinterfacetable(void)
2469 {
2470         HRESULT hr;
2471         IGlobalInterfaceTable *git;
2472         DWORD cookie;
2473         HANDLE thread;
2474         DWORD tid;
2475         struct git_params params;
2476         DWORD ret;
2477
2478         hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)&git);
2479         ok_ole_success(hr, CoCreateInstance);
2480
2481         hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&Test_ClassFactory, &IID_IClassFactory, &cookie);
2482         ok_ole_success(hr, IGlobalInterfaceTable_RegisterInterfaceInGlobal);
2483
2484         params.cookie = cookie;
2485         params.git = git;
2486         /* note: params is on stack so we MUST wait for get_global_interface_proc
2487          * to exit before we can return */
2488         thread = CreateThread(NULL, 0, get_global_interface_proc, &params, 0, &tid);
2489
2490         ret = MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT);
2491         while (ret == WAIT_OBJECT_0 + 1)
2492         {
2493                 MSG msg;
2494                 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
2495                         DispatchMessage(&msg);
2496                 ret = MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT);
2497         }
2498
2499         CloseHandle(thread);
2500 }
2501
2502 static const char *debugstr_iid(REFIID riid)
2503 {
2504     static char name[256];
2505     HKEY hkeyInterface;
2506     WCHAR bufferW[39];
2507     char buffer[39];
2508     LONG name_size = sizeof(name);
2509     StringFromGUID2(riid, bufferW, sizeof(bufferW)/sizeof(bufferW[0]));
2510     WideCharToMultiByte(CP_ACP, 0, bufferW, sizeof(bufferW)/sizeof(bufferW[0]), buffer, sizeof(buffer), NULL, NULL);
2511     if (RegOpenKeyEx(HKEY_CLASSES_ROOT, "Interface", 0, KEY_QUERY_VALUE, &hkeyInterface) != ERROR_SUCCESS)
2512     {
2513         memcpy(name, buffer, sizeof(buffer));
2514         goto done;
2515     }
2516     if (RegQueryValue(hkeyInterface, buffer, name, &name_size) != ERROR_SUCCESS)
2517     {
2518         memcpy(name, buffer, sizeof(buffer));
2519         goto done;
2520     }
2521     RegCloseKey(hkeyInterface);
2522 done:
2523     return name;
2524 }
2525
2526 static HRESULT WINAPI TestChannelHook_QueryInterface(IChannelHook *iface, REFIID riid, void **ppv)
2527 {
2528     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IChannelHook))
2529     {
2530         *ppv = iface;
2531         IUnknown_AddRef(iface);
2532         return S_OK;
2533     }
2534
2535     *ppv = NULL;
2536     return E_NOINTERFACE;
2537 }
2538
2539 static ULONG WINAPI TestChannelHook_AddRef(IChannelHook *iface)
2540 {
2541     return 2;
2542 }
2543
2544 static ULONG WINAPI TestChannelHook_Release(IChannelHook *iface)
2545 {
2546     return 1;
2547 }
2548
2549 static void WINAPI TestChannelHook_ClientGetSize(
2550     IChannelHook *iface,
2551     REFGUID uExtent,
2552     REFIID  riid,
2553     ULONG  *pDataSize )
2554 {
2555     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
2556     trace("TestChannelHook_ClientGetBuffer\n");
2557     trace("\t%s method %d\n", debugstr_iid(riid), info->iMethod);
2558     trace("\tcid: %s\n", debugstr_iid(&info->uCausality));
2559     ok(info->cbSize == sizeof(*info), "info->cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
2560     ok(info->dwServerPid == GetCurrentProcessId(), "info->dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
2561     ok(!info->pObject, "info->pObject should be NULL\n");
2562     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
2563
2564     *pDataSize = 1;
2565 }
2566
2567 static void WINAPI TestChannelHook_ClientFillBuffer(
2568     IChannelHook *iface,
2569     REFGUID uExtent,
2570     REFIID  riid,
2571     ULONG  *pDataSize,
2572     void   *pDataBuffer )
2573 {
2574     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
2575     trace("TestChannelHook_ClientFillBuffer\n");
2576     ok(info->cbSize == sizeof(*info), "info->cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
2577     ok(info->dwServerPid == GetCurrentProcessId(), "info->dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
2578     ok(!info->pObject, "info->pObject should be NULL\n");
2579     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
2580
2581     *(unsigned char *)pDataBuffer = 0xcc;
2582     *pDataSize = 1;
2583 }
2584
2585 static void WINAPI TestChannelHook_ClientNotify(
2586     IChannelHook *iface,
2587     REFGUID uExtent,
2588     REFIID  riid,
2589     ULONG   cbDataSize,
2590     void   *pDataBuffer,
2591     DWORD   lDataRep,
2592     HRESULT hrFault )
2593 {
2594     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
2595     trace("TestChannelHook_ClientNotify hrFault = 0x%08x\n", hrFault);
2596     ok(info->cbSize == sizeof(*info), "info->cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
2597     ok(info->dwServerPid == GetCurrentProcessId(), "info->dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
2598     todo_wine {
2599     ok(info->pObject != NULL, "info->pObject shouldn't be NULL\n");
2600     }
2601     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
2602 }
2603
2604 static void WINAPI TestChannelHook_ServerNotify(
2605     IChannelHook *iface,
2606     REFGUID uExtent,
2607     REFIID  riid,
2608     ULONG   cbDataSize,
2609     void   *pDataBuffer,
2610     DWORD   lDataRep )
2611 {
2612     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
2613     trace("TestChannelHook_ServerNotify\n");
2614     ok(info->cbSize == sizeof(*info), "info->cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
2615     ok(info->dwServerPid == GetCurrentProcessId(), "info->dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
2616     ok(info->pObject != NULL, "info->pObject shouldn't be NULL\n");
2617     ok(cbDataSize == 1, "cbDataSize should have been 1 instead of %d\n", cbDataSize);
2618     ok(*(unsigned char *)pDataBuffer == 0xcc, "pDataBuffer should have contained 0xcc instead of 0x%x\n", *(unsigned char *)pDataBuffer);
2619     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
2620 }
2621
2622 static void WINAPI TestChannelHook_ServerGetSize(
2623     IChannelHook *iface,
2624     REFGUID uExtent,
2625     REFIID  riid,
2626     HRESULT hrFault,
2627     ULONG  *pDataSize )
2628 {
2629     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
2630     trace("TestChannelHook_ServerGetSize\n");
2631     trace("\t%s method %d\n", debugstr_iid(riid), info->iMethod);
2632     ok(info->cbSize == sizeof(*info), "info->cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
2633     ok(info->dwServerPid == GetCurrentProcessId(), "info->dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
2634     ok(info->pObject != NULL, "info->pObject shouldn't be NULL\n");
2635     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
2636     if (hrFault != S_OK)
2637         trace("\thrFault = 0x%08x\n", hrFault);
2638
2639     *pDataSize = 0;
2640 }
2641
2642 static void WINAPI TestChannelHook_ServerFillBuffer(
2643     IChannelHook *iface,
2644     REFGUID uExtent,
2645     REFIID  riid,
2646     ULONG  *pDataSize,
2647     void   *pDataBuffer,
2648     HRESULT hrFault )
2649 {
2650     trace("TestChannelHook_ServerFillBuffer\n");
2651     ok(0, "TestChannelHook_ServerFillBuffer shouldn't be called\n");
2652 }
2653
2654 static const IChannelHookVtbl TestChannelHookVtbl =
2655 {
2656     TestChannelHook_QueryInterface,
2657     TestChannelHook_AddRef,
2658     TestChannelHook_Release,
2659     TestChannelHook_ClientGetSize,
2660     TestChannelHook_ClientFillBuffer,
2661     TestChannelHook_ClientNotify,
2662     TestChannelHook_ServerNotify,
2663     TestChannelHook_ServerGetSize,
2664     TestChannelHook_ServerFillBuffer,
2665 };
2666
2667 static IChannelHook TestChannelHook = { &TestChannelHookVtbl };
2668
2669 static void test_channel_hook(void)
2670 {
2671     IStream *pStream = NULL;
2672     IClassFactory *cf = NULL;
2673     DWORD tid;
2674     IUnknown *proxy = NULL;
2675     HANDLE thread;
2676     HRESULT hr;
2677
2678     hr = CoRegisterChannelHook(&EXTENTID_WineTest, &TestChannelHook);
2679     ok_ole_success(hr, CoRegisterChannelHook);
2680
2681     hr = CoRegisterMessageFilter(&MessageFilter, NULL);
2682     ok_ole_success(hr, CoRegisterMessageFilter);
2683
2684     cLocks = 0;
2685
2686     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2687     ok_ole_success(hr, CreateStreamOnHGlobal);
2688     tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
2689
2690     ok_more_than_one_lock();
2691
2692     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2693     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
2694     ok_ole_success(hr, CoUnmarshalInterface);
2695     IStream_Release(pStream);
2696
2697     ok_more_than_one_lock();
2698
2699     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2700     ok_ole_success(hr, IClassFactory_CreateInstance);
2701     IUnknown_Release(proxy);
2702
2703     IClassFactory_Release(cf);
2704
2705     ok_no_locks();
2706
2707     end_host_object(tid, thread);
2708
2709     hr = CoRegisterMessageFilter(NULL, NULL);
2710     ok_ole_success(hr, CoRegisterMessageFilter);
2711 }
2712
2713 START_TEST(marshal)
2714 {
2715     WNDCLASS wndclass;
2716     HMODULE hOle32 = GetModuleHandle("ole32");
2717     int argc;
2718     char **argv;
2719
2720     if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
2721
2722     argc = winetest_get_mainargs( &argv );
2723     if (argc > 2 && (!strcmp(argv[2], "-Embedding")))
2724     {
2725         pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2726         test_register_local_server();
2727         CoUninitialize();
2728
2729         return;
2730     }
2731
2732     /* register a window class used in several tests */
2733     memset(&wndclass, 0, sizeof(wndclass));
2734     wndclass.lpfnWndProc = window_proc;
2735     wndclass.lpszClassName = "WineCOMTest";
2736     RegisterClass(&wndclass);
2737
2738     test_cocreateinstance_proxy();
2739
2740     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2741
2742     /* FIXME: test CoCreateInstanceEx */
2743
2744     /* lifecycle management and marshaling tests */
2745     test_no_marshaler();
2746     test_normal_marshal_and_release();
2747     test_normal_marshal_and_unmarshal();
2748     test_marshal_and_unmarshal_invalid();
2749     test_same_apartment_unmarshal_failure();
2750     test_interthread_marshal_and_unmarshal();
2751     test_proxy_marshal_and_unmarshal();
2752     test_proxy_marshal_and_unmarshal2();
2753     test_marshal_stub_apartment_shutdown();
2754     test_marshal_proxy_apartment_shutdown();
2755     test_marshal_proxy_mta_apartment_shutdown();
2756     test_no_couninitialize_server();
2757     test_no_couninitialize_client();
2758     test_tableweak_marshal_and_unmarshal_twice();
2759     test_tableweak_marshal_releasedata1();
2760     test_tableweak_marshal_releasedata2();
2761     test_tablestrong_marshal_and_unmarshal_twice();
2762     test_lock_object_external();
2763     test_disconnect_stub();
2764     test_normal_marshal_and_unmarshal_twice();
2765     test_hresult_marshaling();
2766     test_proxy_used_in_wrong_thread();
2767     test_message_filter();
2768     test_bad_marshal_stream();
2769     test_proxy_interfaces();
2770     test_stubbuffer(&IID_IClassFactory);
2771     test_proxybuffer(&IID_IClassFactory);
2772     test_message_reentrancy();
2773     test_call_from_message();
2774     test_WM_QUIT_handling();
2775     test_freethreadedmarshaler();
2776     test_inproc_handler();
2777     test_handler_marshaling();
2778     test_client_security();
2779
2780     test_local_server();
2781
2782     test_globalinterfacetable();
2783
2784     /* must be last test as channel hooks can't be unregistered */
2785     test_channel_hook();
2786
2787     CoUninitialize();
2788     return;
2789
2790 no_test:
2791     trace("You need DCOM95 installed to run this test\n");
2792     return;
2793 }