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 "olectl.h"
32 #include "shlguid.h"
33 #include "shobjidl.h"
34 #include "initguid.h"
35 
36 #include "wine/test.h"
37 #include "wine/heap.h"
38 
39 #define DEFINE_EXPECT(func) \
40     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
41 
42 #define SET_EXPECT(func) \
43     expect_ ## func = TRUE
44 
45 #define CHECK_EXPECT2(func) \
46     do { \
47         ok(expect_ ##func, "unexpected call " #func "\n"); \
48         called_ ## func = TRUE; \
49     }while(0)
50 
51 #define CHECK_EXPECT(func) \
52     do { \
53         CHECK_EXPECT2(func); \
54         expect_ ## func = FALSE; \
55     }while(0)
56 
57 #define CHECK_CALLED(func) \
58     do { \
59         ok(called_ ## func, "expected " #func "\n"); \
60         expect_ ## func = called_ ## func = FALSE; \
61     }while(0)
62 
63 DEFINE_GUID(CLSID_StdGlobalInterfaceTable,0x00000323,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
64 DEFINE_GUID(CLSID_ManualResetEvent,       0x0000032c,0x0000,0x0000,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
65 
66 static const GUID CLSID_WineTestPSFactoryBuffer = { 0x22222222, 0x1234, 0x1234, { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0 } };
67 
68 /* functions that are not present on all versions of Windows */
69 static HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
70 static HRESULT (WINAPI *pDllGetClassObject)(REFCLSID,REFIID,LPVOID);
71 
72 /* helper macros to make tests a bit leaner */
73 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
74 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
75 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
76 #define ok_non_zero_external_conn() do {if (with_external_conn) ok(external_connections, "got no external connections\n");} while(0);
77 #define ok_zero_external_conn() do {if (with_external_conn) ok(!external_connections, "got %d external connections\n", external_connections);} while(0);
78 #define ok_last_release_closes(b) do {if (with_external_conn) ok(last_release_closes == b, "got %d expected %d\n", last_release_closes, b);} while(0);
79 
80 static const IID IID_IWineTest =
81 {
82     0x5201163f,
83     0x8164,
84     0x4fd0,
85     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
86 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
87 
88 static const IID IID_IRemUnknown =
89 {
90     0x00000131,
91     0x0000,
92     0x0000,
93     {0xc0,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}
94 };
95 
96 #define EXTENTID_WineTest IID_IWineTest
97 #define CLSID_WineTest IID_IWineTest
98 
99 static const CLSID CLSID_WineOOPTest =
100 {
101     0x5201163f,
102     0x8164,
103     0x4fd0,
104     {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
105 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
106 
107 static void test_cocreateinstance_proxy(void)
108 {
109     IUnknown *pProxy;
110     IMultiQI *pMQI;
111     HRESULT hr;
112 
113     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
114 
115     hr = CoCreateInstance(&CLSID_ShellDesktop, NULL, CLSCTX_INPROC, &IID_IUnknown, (void **)&pProxy);
116     ok_ole_success(hr, CoCreateInstance);
117     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (void **)&pMQI);
118     ok(hr == S_OK, "created object is not a proxy, so was created in the wrong apartment\n");
119     if (hr == S_OK)
120         IMultiQI_Release(pMQI);
121     IUnknown_Release(pProxy);
122 
123     CoUninitialize();
124 }
125 
126 static const LARGE_INTEGER ullZero;
127 static LONG cLocks;
128 
129 static void LockModule(void)
130 {
131     InterlockedIncrement(&cLocks);
132 }
133 
134 static void UnlockModule(void)
135 {
136     InterlockedDecrement(&cLocks);
137 }
138 
139 static BOOL with_external_conn;
140 static DWORD external_connections;
141 static BOOL last_release_closes;
142 
143 static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv)
144 {
145     ok(0, "unexpected call\n");
146     *ppv = NULL;
147     return E_NOINTERFACE;
148 }
149 
150 static ULONG WINAPI ExternalConnection_AddRef(IExternalConnection *iface)
151 {
152     return 2;
153 }
154 
155 static ULONG WINAPI ExternalConnection_Release(IExternalConnection *iface)
156 {
157     return 1;
158 }
159 
160 static DWORD WINAPI ExternalConnection_AddConnection(IExternalConnection *iface, DWORD extconn, DWORD reserved)
161 {
162     trace("add connection\n");
163     return ++external_connections;
164 }
165 
166 
167 static DWORD WINAPI ExternalConnection_ReleaseConnection(IExternalConnection *iface, DWORD extconn,
168         DWORD reserved, BOOL fLastReleaseCloses)
169 {
170     trace("release connection %d\n", fLastReleaseCloses);
171     last_release_closes = fLastReleaseCloses;
172     return --external_connections;
173 }
174 
175 static const IExternalConnectionVtbl ExternalConnectionVtbl = {
176     ExternalConnection_QueryInterface,
177     ExternalConnection_AddRef,
178     ExternalConnection_Release,
179     ExternalConnection_AddConnection,
180     ExternalConnection_ReleaseConnection
181 };
182 
183 static IExternalConnection ExternalConnection = { &ExternalConnectionVtbl };
184 
185 
186 static HRESULT WINAPI Test_IUnknown_QueryInterface(
187     LPUNKNOWN iface,
188     REFIID riid,
189     LPVOID *ppvObj)
190 {
191     if (ppvObj == NULL) return E_POINTER;
192 
193     if (IsEqualGUID(riid, &IID_IUnknown))
194     {
195         *ppvObj = iface;
196         IUnknown_AddRef(iface);
197         return S_OK;
198     }
199 
200     *ppvObj = NULL;
201     return E_NOINTERFACE;
202 }
203 
204 static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
205 {
206     LockModule();
207     return 2; /* non-heap-based object */
208 }
209 
210 static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
211 {
212     UnlockModule();
213     return 1; /* non-heap-based object */
214 }
215 
216 static const IUnknownVtbl TestUnknown_Vtbl =
217 {
218     Test_IUnknown_QueryInterface,
219     Test_IUnknown_AddRef,
220     Test_IUnknown_Release,
221 };
222 
223 static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
224 
225 static ULONG WINAPI TestCrash_IUnknown_Release(LPUNKNOWN iface)
226 {
227     UnlockModule();
228     if(!cLocks) {
229         trace("crashing...\n");
230         *(int**)0xc = 0;
231     }
232     return 1; /* non-heap-based object */
233 }
234 
235 static const IUnknownVtbl TestCrashUnknown_Vtbl =
236 {
237     Test_IUnknown_QueryInterface,
238     Test_IUnknown_AddRef,
239     TestCrash_IUnknown_Release,
240 };
241 
242 static IUnknown TestCrash_Unknown = { &TestCrashUnknown_Vtbl };
243 
244 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
245     LPCLASSFACTORY iface,
246     REFIID riid,
247     LPVOID *ppvObj)
248 {
249     if (ppvObj == NULL) return E_POINTER;
250 
251     if (IsEqualGUID(riid, &IID_IUnknown) ||
252         IsEqualGUID(riid, &IID_IClassFactory) ||
253         /* the only other interface Wine is currently able to marshal (for testing two proxies) */
254         IsEqualGUID(riid, &IID_IRemUnknown))
255     {
256         *ppvObj = iface;
257         IClassFactory_AddRef(iface);
258         return S_OK;
259     }
260 
261     if (with_external_conn && IsEqualGUID(riid, &IID_IExternalConnection))
262     {
263         *ppvObj = &ExternalConnection;
264         return S_OK;
265     }
266 
267     *ppvObj = NULL;
268     return E_NOINTERFACE;
269 }
270 
271 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
272 {
273     LockModule();
274     return 2; /* non-heap-based object */
275 }
276 
277 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
278 {
279     UnlockModule();
280     return 1; /* non-heap-based object */
281 }
282 
283 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
284     LPCLASSFACTORY iface,
285     LPUNKNOWN pUnkOuter,
286     REFIID riid,
287     LPVOID *ppvObj)
288 {
289     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
290     return IUnknown_QueryInterface((IUnknown*)&Test_Unknown, riid, ppvObj);
291 }
292 
293 static HRESULT WINAPI Test_IClassFactory_LockServer(
294     LPCLASSFACTORY iface,
295     BOOL fLock)
296 {
297     return S_OK;
298 }
299 
300 static const IClassFactoryVtbl TestClassFactory_Vtbl =
301 {
302     Test_IClassFactory_QueryInterface,
303     Test_IClassFactory_AddRef,
304     Test_IClassFactory_Release,
305     Test_IClassFactory_CreateInstance,
306     Test_IClassFactory_LockServer
307 };
308 
309 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
310 
311 DEFINE_EXPECT(Invoke);
312 DEFINE_EXPECT(CreateStub);
313 DEFINE_EXPECT(CreateProxy);
314 DEFINE_EXPECT(GetWindow);
315 DEFINE_EXPECT(Disconnect);
316 
317 static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **ppv)
318 {
319     ok(0, "unexpected call %s\n", wine_dbgstr_guid(riid));
320     *ppv = NULL;
321     return E_NOINTERFACE;
322 }
323 
324 static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
325 {
326     return 2;
327 }
328 
329 static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
330 {
331     return 1;
332 }
333 
334 static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
335 {
336     CHECK_EXPECT(GetWindow);
337     *hwnd = (HWND)0xdeadbeef;
338     return S_OK;
339 }
340 
341 static const IOleWindowVtbl OleWindowVtbl = {
342     OleWindow_QueryInterface,
343     OleWindow_AddRef,
344     OleWindow_Release,
345     OleWindow_GetWindow,
346     /* not needed */
347 };
348 
349 static IOleWindow Test_OleWindow = { &OleWindowVtbl };
350 
351 static HRESULT WINAPI OleClientSite_QueryInterface(IOleClientSite *iface, REFIID riid, void **ppv)
352 {
353     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IOleClientSite))
354         *ppv = iface;
355     else if (IsEqualGUID(riid, &IID_IOleWindow))
356         *ppv = &Test_OleWindow;
357     else
358     {
359         *ppv = NULL;
360         return E_NOINTERFACE;
361     }
362 
363     IUnknown_AddRef((IUnknown*)*ppv);
364     return S_OK;
365 }
366 
367 static ULONG WINAPI OleClientSite_AddRef(IOleClientSite *iface)
368 {
369     return 2;
370 }
371 
372 static ULONG WINAPI OleClientSite_Release(IOleClientSite *iface)
373 {
374     return 1;
375 }
376 
377 static const IOleClientSiteVtbl OleClientSiteVtbl = {
378     OleClientSite_QueryInterface,
379     OleClientSite_AddRef,
380     OleClientSite_Release,
381     /* we don't need the rest, we never call it */
382 };
383 
384 static IOleClientSite Test_OleClientSite = { &OleClientSiteVtbl };
385 
386 typedef struct {
387     IRpcStubBuffer IRpcStubBuffer_iface;
388     LONG ref;
389     IRpcStubBuffer *buffer;
390 } StubBufferWrapper;
391 
392 static StubBufferWrapper *impl_from_IRpcStubBuffer(IRpcStubBuffer *iface)
393 {
394     return CONTAINING_RECORD(iface, StubBufferWrapper, IRpcStubBuffer_iface);
395 }
396 
397 static HRESULT WINAPI RpcStubBuffer_QueryInterface(IRpcStubBuffer *iface, REFIID riid, void **ppv)
398 {
399     StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
400 
401     if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IRpcStubBuffer, riid)) {
402         *ppv = &This->IRpcStubBuffer_iface;
403     }else {
404         *ppv = NULL;
405         return E_NOINTERFACE;
406     }
407 
408     IUnknown_AddRef((IUnknown*)*ppv);
409     return S_OK;
410 }
411 
412 static ULONG WINAPI RpcStubBuffer_AddRef(IRpcStubBuffer *iface)
413 {
414     StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
415     return InterlockedIncrement(&This->ref);
416 }
417 
418 static ULONG WINAPI RpcStubBuffer_Release(IRpcStubBuffer *iface)
419 {
420     StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
421     LONG ref = InterlockedDecrement(&This->ref);
422     if(!ref) {
423         IRpcStubBuffer_Release(This->buffer);
424         heap_free(This);
425     }
426     return ref;
427 }
428 
429 static HRESULT WINAPI RpcStubBuffer_Connect(IRpcStubBuffer *iface, IUnknown *pUnkServer)
430 {
431     ok(0, "unexpected call\n");
432     return E_NOTIMPL;
433 }
434 
435 static void WINAPI RpcStubBuffer_Disconnect(IRpcStubBuffer *iface)
436 {
437     CHECK_EXPECT(Disconnect);
438 }
439 
440 static HRESULT WINAPI RpcStubBuffer_Invoke(IRpcStubBuffer *iface, RPCOLEMESSAGE *_prpcmsg,
441     IRpcChannelBuffer *_pRpcChannelBuffer)
442 {
443     StubBufferWrapper *This = impl_from_IRpcStubBuffer(iface);
444     void *dest_context_data;
445     DWORD dest_context;
446     HRESULT hr;
447 
448     CHECK_EXPECT(Invoke);
449 
450     hr = IRpcChannelBuffer_GetDestCtx(_pRpcChannelBuffer, &dest_context, &dest_context_data);
451     ok(hr == S_OK, "GetDestCtx failed: %08x\n", hr);
452     ok(dest_context == MSHCTX_INPROC, "desc_context = %x\n", dest_context);
453     ok(!dest_context_data, "desc_context_data = %p\n", dest_context_data);
454 
455     return IRpcStubBuffer_Invoke(This->buffer, _prpcmsg, _pRpcChannelBuffer);
456 }
457 
458 static IRpcStubBuffer *WINAPI RpcStubBuffer_IsIIDSupported(IRpcStubBuffer *iface, REFIID riid)
459 {
460     ok(0, "unexpected call\n");
461     return NULL;
462 }
463 
464 static ULONG WINAPI RpcStubBuffer_CountRefs(IRpcStubBuffer *iface)
465 {
466     ok(0, "unexpected call\n");
467     return E_NOTIMPL;
468 }
469 
470 static HRESULT WINAPI RpcStubBuffer_DebugServerQueryInterface(IRpcStubBuffer *iface, void **ppv)
471 {
472     ok(0, "unexpected call\n");
473     return E_NOTIMPL;
474 }
475 
476 static void WINAPI RpcStubBuffer_DebugServerRelease(IRpcStubBuffer *iface, void *pv)
477 {
478     ok(0, "unexpected call\n");
479 }
480 
481 static const IRpcStubBufferVtbl RpcStubBufferVtbl = {
482     RpcStubBuffer_QueryInterface,
483     RpcStubBuffer_AddRef,
484     RpcStubBuffer_Release,
485     RpcStubBuffer_Connect,
486     RpcStubBuffer_Disconnect,
487     RpcStubBuffer_Invoke,
488     RpcStubBuffer_IsIIDSupported,
489     RpcStubBuffer_CountRefs,
490     RpcStubBuffer_DebugServerQueryInterface,
491     RpcStubBuffer_DebugServerRelease
492 };
493 
494 static IPSFactoryBuffer *ps_factory_buffer;
495 
496 static HRESULT WINAPI PSFactoryBuffer_QueryInterface(IPSFactoryBuffer *iface, REFIID riid, void **ppv)
497 {
498     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPSFactoryBuffer))
499         *ppv = iface;
500     else
501     {
502         *ppv = NULL;
503         return E_NOINTERFACE;
504     }
505     IUnknown_AddRef((IUnknown*)*ppv);
506     return S_OK;
507 }
508 
509 static ULONG WINAPI PSFactoryBuffer_AddRef(IPSFactoryBuffer *iface)
510 {
511     return 2;
512 }
513 
514 static ULONG WINAPI PSFactoryBuffer_Release(IPSFactoryBuffer *iface)
515 {
516     return 1;
517 }
518 
519 static HRESULT WINAPI PSFactoryBuffer_CreateProxy(IPSFactoryBuffer *iface, IUnknown *outer,
520     REFIID riid, IRpcProxyBuffer **ppProxy, void **ppv)
521 {
522     CHECK_EXPECT(CreateProxy);
523     return IPSFactoryBuffer_CreateProxy(ps_factory_buffer, outer, riid, ppProxy, ppv);
524 }
525 
526 static HRESULT WINAPI PSFactoryBuffer_CreateStub(IPSFactoryBuffer *iface, REFIID riid,
527     IUnknown *server, IRpcStubBuffer **ppStub)
528 {
529     StubBufferWrapper *stub;
530     HRESULT hr;
531 
532     CHECK_EXPECT(CreateStub);
533 
534     ok(server == (IUnknown*)&Test_OleClientSite, "unexpected server %p\n", server);
535 
536     stub = heap_alloc(sizeof(*stub));
537     stub->IRpcStubBuffer_iface.lpVtbl = &RpcStubBufferVtbl;
538     stub->ref = 1;
539 
540     hr = IPSFactoryBuffer_CreateStub(ps_factory_buffer, riid, server, &stub->buffer);
541     ok(hr == S_OK, "CreateStub failed: %08x\n", hr);
542 
543     *ppStub = &stub->IRpcStubBuffer_iface;
544     return S_OK;
545 }
546 
547 static IPSFactoryBufferVtbl PSFactoryBufferVtbl =
548 {
549     PSFactoryBuffer_QueryInterface,
550     PSFactoryBuffer_AddRef,
551     PSFactoryBuffer_Release,
552     PSFactoryBuffer_CreateProxy,
553     PSFactoryBuffer_CreateStub
554 };
555 
556 static IPSFactoryBuffer PSFactoryBuffer = { &PSFactoryBufferVtbl };
557 
558 #define RELEASEMARSHALDATA WM_USER
559 
560 struct host_object_data
561 {
562     IStream *stream;
563     const IID *iid;
564     IUnknown *object;
565     MSHLFLAGS marshal_flags;
566     IMessageFilter *filter;
567     IUnknown *register_object;
568     const CLSID *register_clsid;
569     HANDLE marshal_event;
570 };
571 
572 #ifndef __REACTOS__ /* FIXME: Inspect */
573 static IPSFactoryBuffer PSFactoryBuffer;
574 #endif
575 
576 static DWORD CALLBACK host_object_proc(LPVOID p)
577 {
578     struct host_object_data *data = p;
579     DWORD registration_key;
580     HRESULT hr;
581     MSG msg;
582 
583     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
584 
585     if(data->register_object) {
586         hr = CoRegisterClassObject(data->register_clsid, data->register_object,
587             CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &registration_key);
588         ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
589     }
590 
591     if (data->filter)
592     {
593         IMessageFilter * prev_filter = NULL;
594         hr = CoRegisterMessageFilter(data->filter, &prev_filter);
595         if (prev_filter) IMessageFilter_Release(prev_filter);
596         ok_ole_success(hr, CoRegisterMessageFilter);
597     }
598 
599     hr = CoMarshalInterface(data->stream, data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
600     ok_ole_success(hr, CoMarshalInterface);
601 
602     /* force the message queue to be created before signaling parent thread */
603     PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
604 
605     SetEvent(data->marshal_event);
606 
607     while (GetMessageA(&msg, NULL, 0, 0))
608     {
609         if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
610         {
611             CoReleaseMarshalData(data->stream);
612             SetEvent((HANDLE)msg.lParam);
613         }
614         else
615             DispatchMessageA(&msg);
616     }
617 
618     HeapFree(GetProcessHeap(), 0, data);
619 
620     CoUninitialize();
621 
622     return hr;
623 }
624 
625 static DWORD start_host_object2(struct host_object_data *object_data, HANDLE *thread)
626 {
627     DWORD tid = 0;
628     struct host_object_data *data;
629 
630     data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
631     *data = *object_data;
632     data->marshal_event = CreateEventA(NULL, FALSE, FALSE, NULL);
633     *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
634 
635     /* wait for marshaling to complete before returning */
636     ok( !WaitForSingleObject(data->marshal_event, 10000), "wait timed out\n" );
637     CloseHandle(data->marshal_event);
638 
639     return tid;
640 }
641 
642 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
643 {
644     struct host_object_data object_data = { stream, riid, object, marshal_flags };
645     return start_host_object2(&object_data, thread);
646 }
647 
648 /* asks thread to release the marshal data because it has to be done by the
649  * same thread that marshaled the interface in the first place. */
650 static void release_host_object(DWORD tid, WPARAM wp)
651 {
652     HANDLE event = CreateEventA(NULL, FALSE, FALSE, NULL);
653     PostThreadMessageA(tid, RELEASEMARSHALDATA, wp, (LPARAM)event);
654     ok( !WaitForSingleObject(event, 10000), "wait timed out\n" );
655     CloseHandle(event);
656 }
657 
658 static void end_host_object(DWORD tid, HANDLE thread)
659 {
660     BOOL ret = PostThreadMessageA(tid, WM_QUIT, 0, 0);
661     ok(ret, "PostThreadMessage failed with error %d\n", GetLastError());
662     /* be careful of races - don't return until hosting thread has terminated */
663     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
664     CloseHandle(thread);
665 }
666 
667 /* tests failure case of interface not having a marshaler specified in the
668  * registry */
669 static void test_no_marshaler(void)
670 {
671     IStream *pStream;
672     HRESULT hr;
673 
674     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
675     ok_ole_success(hr, CreateStreamOnHGlobal);
676     hr = CoMarshalInterface(pStream, &IID_IWineTest, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
677     ok(hr == E_NOINTERFACE, "CoMarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
678 
679     IStream_Release(pStream);
680 }
681 
682 /* tests normal marshal and then release without unmarshaling */
683 static void test_normal_marshal_and_release(void)
684 {
685     HRESULT hr;
686     IStream *pStream = NULL;
687 
688     cLocks = 0;
689     external_connections = 0;
690 
691     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
692     ok_ole_success(hr, CreateStreamOnHGlobal);
693     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
694     ok_ole_success(hr, CoMarshalInterface);
695 
696     ok_more_than_one_lock();
697     ok_non_zero_external_conn();
698 
699     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
700     hr = CoReleaseMarshalData(pStream);
701     ok_ole_success(hr, CoReleaseMarshalData);
702     IStream_Release(pStream);
703 
704     ok_no_locks();
705     ok_zero_external_conn();
706     ok_last_release_closes(TRUE);
707 }
708 
709 /* tests success case of a same-thread marshal and unmarshal */
710 static void test_normal_marshal_and_unmarshal(void)
711 {
712     HRESULT hr;
713     IStream *pStream = NULL;
714     IUnknown *pProxy = NULL;
715 
716     cLocks = 0;
717     external_connections = 0;
718 
719     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
720     ok_ole_success(hr, CreateStreamOnHGlobal);
721     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
722     ok_ole_success(hr, CoMarshalInterface);
723 
724     ok_more_than_one_lock();
725     ok_non_zero_external_conn();
726 
727     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
728     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
729     ok_ole_success(hr, CoUnmarshalInterface);
730     IStream_Release(pStream);
731 
732     ok_more_than_one_lock();
733     ok_zero_external_conn();
734     ok_last_release_closes(FALSE);
735 
736     IUnknown_Release(pProxy);
737 
738     ok_no_locks();
739 }
740 
741 /* tests failure case of unmarshaling a freed object */
742 static void test_marshal_and_unmarshal_invalid(void)
743 {
744     HRESULT hr;
745     IStream *pStream = NULL;
746     IClassFactory *pProxy = NULL;
747     DWORD tid;
748     void * dummy;
749     HANDLE thread;
750 
751     cLocks = 0;
752     external_connections = 0;
753 
754     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
755     ok_ole_success(hr, CreateStreamOnHGlobal);
756     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
757 
758     ok_more_than_one_lock();
759     ok_non_zero_external_conn();
760 
761     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
762     hr = CoReleaseMarshalData(pStream);
763     ok_ole_success(hr, CoReleaseMarshalData);
764 
765     ok_no_locks();
766     ok_zero_external_conn();
767     ok_last_release_closes(TRUE);
768 
769     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
770     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
771     todo_wine { ok_ole_success(hr, CoUnmarshalInterface); }
772 
773     ok_no_locks();
774 
775     if (pProxy)
776     {
777         hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IUnknown, &dummy);
778         ok(hr == RPC_E_DISCONNECTED, "Remote call should have returned RPC_E_DISCONNECTED, instead of 0x%08x\n", hr);
779 
780         IClassFactory_Release(pProxy);
781     }
782 
783     IStream_Release(pStream);
784 
785     end_host_object(tid, thread);
786 }
787 
788 static void test_same_apartment_unmarshal_failure(void)
789 {
790     HRESULT hr;
791     IStream *pStream;
792     IUnknown *pProxy;
793     static const LARGE_INTEGER llZero;
794 
795     cLocks = 0;
796     external_connections = 0;
797 
798     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
799     ok_ole_success(hr, CreateStreamOnHGlobal);
800 
801     hr = CoMarshalInterface(pStream, &IID_IUnknown, (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
802     ok_ole_success(hr, CoMarshalInterface);
803 
804     ok_more_than_one_lock();
805     ok_non_zero_external_conn();
806 
807     hr = IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
808     ok_ole_success(hr, IStream_Seek);
809 
810     hr = CoUnmarshalInterface(pStream, &IID_IParseDisplayName, (void **)&pProxy);
811     ok(hr == E_NOINTERFACE, "CoUnmarshalInterface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
812 
813     ok_no_locks();
814     ok_zero_external_conn();
815     ok_last_release_closes(FALSE);
816 
817     IStream_Release(pStream);
818 }
819 
820 /* tests success case of an interthread marshal */
821 static void test_interthread_marshal_and_unmarshal(void)
822 {
823     HRESULT hr;
824     IStream *pStream = NULL;
825     IUnknown *pProxy = NULL;
826     DWORD tid;
827     HANDLE thread;
828 
829     cLocks = 0;
830     external_connections = 0;
831 
832     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
833     ok_ole_success(hr, CreateStreamOnHGlobal);
834     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
835 
836     ok_more_than_one_lock();
837     ok_non_zero_external_conn();
838 
839     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
840     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
841     ok_ole_success(hr, CoUnmarshalInterface);
842     IStream_Release(pStream);
843 
844     ok_more_than_one_lock();
845     ok_non_zero_external_conn();
846 
847     IUnknown_Release(pProxy);
848 
849     ok_no_locks();
850     ok_zero_external_conn();
851     ok_last_release_closes(TRUE);
852 
853     end_host_object(tid, thread);
854 }
855 
856 /* the number of external references that Wine's proxy manager normally gives
857  * out, so we can test the border case of running out of references */
858 #define NORMALEXTREFS 5
859 
860 /* tests success case of an interthread marshal and then marshaling the proxy */
861 static void test_proxy_marshal_and_unmarshal(void)
862 {
863     HRESULT hr;
864     IStream *pStream = NULL;
865     IUnknown *pProxy = NULL;
866     IUnknown *pProxy2 = NULL;
867     DWORD tid;
868     HANDLE thread;
869     int i;
870 
871     cLocks = 0;
872     external_connections = 0;
873 
874     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
875     ok_ole_success(hr, CreateStreamOnHGlobal);
876     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
877 
878     ok_more_than_one_lock();
879     ok_non_zero_external_conn();
880 
881     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
882     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
883     ok_ole_success(hr, CoUnmarshalInterface);
884 
885     ok_more_than_one_lock();
886 
887     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
888     /* marshal the proxy */
889     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
890     ok_ole_success(hr, CoMarshalInterface);
891 
892     ok_more_than_one_lock();
893 
894     /* marshal 5 more times to exhaust the normal external references of 5 */
895     for (i = 0; i < NORMALEXTREFS; i++)
896     {
897         hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
898         ok_ole_success(hr, CoMarshalInterface);
899     }
900 
901     ok_more_than_one_lock();
902 
903     /* release the original proxy to test that we successfully keep the
904      * original object alive */
905     IUnknown_Release(pProxy);
906 
907     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
908     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
909     ok_ole_success(hr, CoUnmarshalInterface);
910 
911     ok_more_than_one_lock();
912     ok_non_zero_external_conn();
913 
914     IUnknown_Release(pProxy2);
915 
916     /* unmarshal all of the proxies to check that the object stub still exists */
917     for (i = 0; i < NORMALEXTREFS; i++)
918     {
919         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
920         ok_ole_success(hr, CoUnmarshalInterface);
921 
922         IUnknown_Release(pProxy2);
923     }
924 
925     ok_no_locks();
926     ok_zero_external_conn();
927     ok_last_release_closes(TRUE);
928 
929     IStream_Release(pStream);
930 
931     end_host_object(tid, thread);
932 }
933 
934 /* tests success case of an interthread marshal and then marshaling the proxy
935  * using an iid that hasn't previously been unmarshaled */
936 static void test_proxy_marshal_and_unmarshal2(void)
937 {
938     HRESULT hr;
939     IStream *pStream = NULL;
940     IUnknown *pProxy = NULL;
941     IUnknown *pProxy2 = NULL;
942     DWORD tid;
943     HANDLE thread;
944 
945     cLocks = 0;
946     external_connections = 0;
947 
948     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
949     ok_ole_success(hr, CreateStreamOnHGlobal);
950     tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
951 
952     ok_more_than_one_lock();
953     ok_non_zero_external_conn();
954 
955     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
956     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
957     ok_ole_success(hr, CoUnmarshalInterface);
958 
959     ok_more_than_one_lock();
960 
961     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
962     /* marshal the proxy */
963     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
964     ok_ole_success(hr, CoMarshalInterface);
965 
966     ok_more_than_one_lock();
967 
968     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
969     /* unmarshal the second proxy to the object */
970     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
971     ok_ole_success(hr, CoUnmarshalInterface);
972     IStream_Release(pStream);
973 
974     /* now the proxies should be as follows:
975      *  pProxy -> &Test_ClassFactory
976      *  pProxy2 -> &Test_ClassFactory
977      * they should NOT be as follows:
978      *  pProxy -> &Test_ClassFactory
979      *  pProxy2 -> pProxy
980      * the above can only really be tested by looking in +ole traces
981      */
982 
983     ok_more_than_one_lock();
984 
985     IUnknown_Release(pProxy);
986 
987     ok_more_than_one_lock();
988     ok_non_zero_external_conn();
989 
990     IUnknown_Release(pProxy2);
991 
992     ok_no_locks();
993     ok_zero_external_conn();
994     ok_last_release_closes(TRUE);
995 
996     end_host_object(tid, thread);
997 }
998 
999 /* tests success case of an interthread marshal and then table-weak-marshaling the proxy */
1000 static void test_proxy_marshal_and_unmarshal_weak(void)
1001 {
1002     HRESULT hr;
1003     IStream *pStream = NULL;
1004     IUnknown *pProxy = NULL;
1005     IUnknown *pProxy2 = NULL;
1006     DWORD tid;
1007     HANDLE thread;
1008 
1009     cLocks = 0;
1010     external_connections = 0;
1011 
1012     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1013     ok_ole_success(hr, CreateStreamOnHGlobal);
1014     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1015 
1016     ok_more_than_one_lock();
1017     ok_non_zero_external_conn();
1018 
1019     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1020     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1021     ok_ole_success(hr, CoUnmarshalInterface);
1022 
1023     ok_more_than_one_lock();
1024     ok_non_zero_external_conn();
1025 
1026     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1027     /* marshal the proxy */
1028     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
1029     ok_ole_success(hr, CoMarshalInterface);
1030 
1031     ok_more_than_one_lock();
1032     ok_non_zero_external_conn();
1033 
1034     /* release the original proxy to test that we successfully keep the
1035      * original object alive */
1036     IUnknown_Release(pProxy);
1037 
1038     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1039     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1040     todo_wine
1041     ok(hr == CO_E_OBJNOTREG, "CoUnmarshalInterface should return CO_E_OBJNOTREG instead of 0x%08x\n", hr);
1042 
1043     ok_no_locks();
1044     ok_zero_external_conn();
1045     ok_last_release_closes(TRUE);
1046 
1047     IStream_Release(pStream);
1048 
1049     end_host_object(tid, thread);
1050 }
1051 
1052 /* tests success case of an interthread marshal and then table-strong-marshaling the proxy */
1053 static void test_proxy_marshal_and_unmarshal_strong(void)
1054 {
1055     HRESULT hr;
1056     IStream *pStream = NULL;
1057     IUnknown *pProxy = NULL;
1058     IUnknown *pProxy2 = NULL;
1059     DWORD tid;
1060     HANDLE thread;
1061 
1062     cLocks = 0;
1063     external_connections = 0;
1064 
1065     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1066     ok_ole_success(hr, CreateStreamOnHGlobal);
1067     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1068 
1069     ok_more_than_one_lock();
1070     ok_non_zero_external_conn();
1071 
1072     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1073     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1074     ok_ole_success(hr, CoUnmarshalInterface);
1075 
1076     ok_more_than_one_lock();
1077     ok_non_zero_external_conn();
1078 
1079     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1080     /* marshal the proxy */
1081     hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG);
1082     ok(hr == S_OK /* WinNT */ || hr == E_INVALIDARG /* Win9x */,
1083         "CoMarshalInterface should have return S_OK or E_INVALIDARG instead of 0x%08x\n", hr);
1084     if (FAILED(hr))
1085     {
1086         IUnknown_Release(pProxy);
1087         goto end;
1088     }
1089 
1090     ok_more_than_one_lock();
1091     ok_non_zero_external_conn();
1092 
1093     /* release the original proxy to test that we successfully keep the
1094      * original object alive */
1095     IUnknown_Release(pProxy);
1096 
1097     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1098     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1099     ok_ole_success(hr, CoUnmarshalInterface);
1100 
1101     ok_more_than_one_lock();
1102     ok_non_zero_external_conn();
1103 
1104     IUnknown_Release(pProxy2);
1105 
1106     ok_more_than_one_lock();
1107     ok_non_zero_external_conn();
1108 
1109 end:
1110     IStream_Release(pStream);
1111 
1112     end_host_object(tid, thread);
1113 
1114     ok_no_locks();
1115 todo_wine {
1116     ok_zero_external_conn();
1117     ok_last_release_closes(FALSE);
1118 }
1119 }
1120 
1121 /* tests that stubs are released when the containing apartment is destroyed */
1122 static void test_marshal_stub_apartment_shutdown(void)
1123 {
1124     HRESULT hr;
1125     IStream *pStream = NULL;
1126     IUnknown *pProxy = NULL;
1127     DWORD tid;
1128     HANDLE thread;
1129 
1130     cLocks = 0;
1131     external_connections = 0;
1132 
1133     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1134     ok_ole_success(hr, CreateStreamOnHGlobal);
1135     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1136 
1137     ok_more_than_one_lock();
1138     ok_non_zero_external_conn();
1139 
1140     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1141     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1142     ok_ole_success(hr, CoUnmarshalInterface);
1143     IStream_Release(pStream);
1144 
1145     ok_more_than_one_lock();
1146     ok_non_zero_external_conn();
1147 
1148     end_host_object(tid, thread);
1149 
1150     ok_no_locks();
1151 todo_wine {
1152     ok_zero_external_conn();
1153     ok_last_release_closes(FALSE);
1154 }
1155 
1156     IUnknown_Release(pProxy);
1157 
1158     ok_no_locks();
1159 }
1160 
1161 /* tests that proxies are released when the containing apartment is destroyed */
1162 static void test_marshal_proxy_apartment_shutdown(void)
1163 {
1164     HRESULT hr;
1165     IStream *pStream = NULL;
1166     IUnknown *pProxy = NULL;
1167     DWORD tid;
1168     HANDLE thread;
1169 
1170     cLocks = 0;
1171     external_connections = 0;
1172 
1173     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1174     ok_ole_success(hr, CreateStreamOnHGlobal);
1175     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1176 
1177     ok_more_than_one_lock();
1178     ok_non_zero_external_conn();
1179 
1180     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1181     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1182     ok_ole_success(hr, CoUnmarshalInterface);
1183     IStream_Release(pStream);
1184 
1185     ok_more_than_one_lock();
1186     ok_non_zero_external_conn();
1187 
1188     CoUninitialize();
1189 
1190     ok_no_locks();
1191     ok_zero_external_conn();
1192     ok_last_release_closes(TRUE);
1193 
1194     IUnknown_Release(pProxy);
1195 
1196     ok_no_locks();
1197 
1198     end_host_object(tid, thread);
1199 
1200     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1201 }
1202 
1203 /* tests that proxies are released when the containing mta apartment is destroyed */
1204 static void test_marshal_proxy_mta_apartment_shutdown(void)
1205 {
1206     HRESULT hr;
1207     IStream *pStream = NULL;
1208     IUnknown *pProxy = NULL;
1209     DWORD tid;
1210     HANDLE thread;
1211 
1212     CoUninitialize();
1213     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1214 
1215     cLocks = 0;
1216     external_connections = 0;
1217 
1218     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1219     ok_ole_success(hr, CreateStreamOnHGlobal);
1220     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
1221 
1222     ok_more_than_one_lock();
1223     ok_non_zero_external_conn();
1224 
1225     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1226     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1227     ok_ole_success(hr, CoUnmarshalInterface);
1228     IStream_Release(pStream);
1229 
1230     ok_more_than_one_lock();
1231     ok_non_zero_external_conn();
1232 
1233     CoUninitialize();
1234 
1235     ok_no_locks();
1236     ok_zero_external_conn();
1237     ok_last_release_closes(TRUE);
1238 
1239     IUnknown_Release(pProxy);
1240 
1241     ok_no_locks();
1242 
1243     end_host_object(tid, thread);
1244 
1245     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1246 }
1247 
1248 static void test_marshal_channel_buffer(void)
1249 {
1250     DWORD registration_key;
1251     IUnknown *proxy = NULL;
1252     IOleWindow *ole_window;
1253     HWND hwnd;
1254     CLSID clsid;
1255     DWORD tid;
1256     HANDLE thread;
1257     HRESULT hr;
1258 
1259     struct host_object_data object_data = { NULL, &IID_IOleClientSite, (IUnknown*)&Test_OleClientSite,
1260                                             MSHLFLAGS_NORMAL, NULL, (IUnknown*)&PSFactoryBuffer,
1261                                             &CLSID_WineTestPSFactoryBuffer };
1262 
1263     cLocks = 0;
1264     external_connections = 0;
1265 
1266     hr = CoGetPSClsid(&IID_IOleWindow, &clsid);
1267     ok_ole_success(hr, "CoGetPSClsid");
1268 
1269     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer,
1270         (void **)&ps_factory_buffer);
1271     ok_ole_success(hr, "CoGetClassObject");
1272 
1273     hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
1274     ok_ole_success(hr, CreateStreamOnHGlobal);
1275     tid = start_host_object2(&object_data, &thread);
1276 
1277     IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
1278     hr = CoUnmarshalInterface(object_data.stream, &IID_IUnknown, (void **)&proxy);
1279     ok_ole_success(hr, CoUnmarshalInterface);
1280     IStream_Release(object_data.stream);
1281 
1282     hr = CoRegisterClassObject(&CLSID_WineTestPSFactoryBuffer, (IUnknown *)&PSFactoryBuffer,
1283         CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE, &registration_key);
1284     ok(hr == S_OK, "CoRegisterClassObject failed: %08x\n", hr);
1285 
1286     hr = CoRegisterPSClsid(&IID_IOleWindow, &CLSID_WineTestPSFactoryBuffer);
1287     ok(hr == S_OK, "CoRegisterPSClsid failed: %08x\n", hr);
1288 
1289     SET_EXPECT(CreateStub);
1290     SET_EXPECT(CreateProxy);
1291     hr = IUnknown_QueryInterface(proxy, &IID_IOleWindow, (void**)&ole_window);
1292     ok(hr == S_OK, "Could not get IOleWindow iface: %08x\n", hr);
1293     CHECK_CALLED(CreateStub);
1294     CHECK_CALLED(CreateProxy);
1295 
1296     SET_EXPECT(Invoke);
1297     SET_EXPECT(GetWindow);
1298     hr = IOleWindow_GetWindow(ole_window, &hwnd);
1299     ok(hr == S_OK, "GetWindow failed: %08x\n", hr);
1300     ok(hwnd == (HWND)0xdeadbeef, "hwnd = %p\n", hwnd);
1301     CHECK_CALLED(Invoke);
1302     CHECK_CALLED(GetWindow);
1303 
1304     IOleWindow_Release(ole_window);
1305 
1306     SET_EXPECT(Disconnect);
1307     IUnknown_Release(proxy);
1308 todo_wine
1309     CHECK_CALLED(Disconnect);
1310 
1311     hr = CoRevokeClassObject(registration_key);
1312     ok(hr == S_OK, "CoRevokeClassObject failed: %08x\n", hr);
1313 
1314     end_host_object(tid, thread);
1315 }
1316 
1317 struct ncu_params
1318 {
1319     LPSTREAM stream;
1320     HANDLE marshal_event;
1321     HANDLE unmarshal_event;
1322 };
1323 
1324 /* helper for test_no_couninitialize_server */
1325 static DWORD CALLBACK no_couninitialize_server_proc(LPVOID p)
1326 {
1327     struct ncu_params *ncu_params = p;
1328     HRESULT hr;
1329 
1330     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
1331 
1332     hr = CoMarshalInterface(ncu_params->stream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1333     ok_ole_success(hr, CoMarshalInterface);
1334 
1335     SetEvent(ncu_params->marshal_event);
1336 
1337     ok( !WaitForSingleObject(ncu_params->unmarshal_event, 10000), "wait timed out\n" );
1338 
1339     /* die without calling CoUninitialize */
1340 
1341     return 0;
1342 }
1343 
1344 /* tests apartment that an apartment with a stub is released without deadlock
1345  * if the owning thread exits */
1346 static void test_no_couninitialize_server(void)
1347 {
1348     HRESULT hr;
1349     IStream *pStream = NULL;
1350     IUnknown *pProxy = NULL;
1351     DWORD tid;
1352     HANDLE thread;
1353     struct ncu_params ncu_params;
1354 
1355     cLocks = 0;
1356     external_connections = 0;
1357 
1358     ncu_params.marshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
1359     ncu_params.unmarshal_event = CreateEventA(NULL, TRUE, FALSE, NULL);
1360 
1361     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1362     ok_ole_success(hr, CreateStreamOnHGlobal);
1363     ncu_params.stream = pStream;
1364 
1365     thread = CreateThread(NULL, 0, no_couninitialize_server_proc, &ncu_params, 0, &tid);
1366 
1367     ok( !WaitForSingleObject(ncu_params.marshal_event, 10000), "wait timed out\n" );
1368     ok_more_than_one_lock();
1369     ok_non_zero_external_conn();
1370 
1371     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1372     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1373     ok_ole_success(hr, CoUnmarshalInterface);
1374     IStream_Release(pStream);
1375 
1376     ok_more_than_one_lock();
1377     ok_non_zero_external_conn();
1378 
1379     SetEvent(ncu_params.unmarshal_event);
1380     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1381 
1382     ok_no_locks();
1383 todo_wine {
1384     ok_zero_external_conn();
1385     ok_last_release_closes(FALSE);
1386 }
1387 
1388     CloseHandle(thread);
1389     CloseHandle(ncu_params.marshal_event);
1390     CloseHandle(ncu_params.unmarshal_event);
1391 
1392     IUnknown_Release(pProxy);
1393 
1394     ok_no_locks();
1395 }
1396 
1397 /* STA -> STA call during DLL_THREAD_DETACH */
1398 static DWORD CALLBACK no_couninitialize_client_proc(LPVOID p)
1399 {
1400     struct ncu_params *ncu_params = p;
1401     HRESULT hr;
1402     IUnknown *pProxy = NULL;
1403 
1404     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1405 
1406     hr = CoUnmarshalInterface(ncu_params->stream, &IID_IClassFactory, (void **)&pProxy);
1407     ok_ole_success(hr, CoUnmarshalInterface);
1408     IStream_Release(ncu_params->stream);
1409 
1410     ok_more_than_one_lock();
1411 
1412     /* die without calling CoUninitialize */
1413 
1414     return 0;
1415 }
1416 
1417 /* tests STA -> STA call during DLL_THREAD_DETACH doesn't deadlock */
1418 static void test_no_couninitialize_client(void)
1419 {
1420     HRESULT hr;
1421     IStream *pStream = NULL;
1422     DWORD tid;
1423     DWORD host_tid;
1424     HANDLE thread;
1425     HANDLE host_thread;
1426     struct ncu_params ncu_params;
1427 
1428     cLocks = 0;
1429     external_connections = 0;
1430 
1431     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1432     ok_ole_success(hr, CreateStreamOnHGlobal);
1433     ncu_params.stream = pStream;
1434 
1435     /* NOTE: assumes start_host_object uses an STA to host the object, as MTAs
1436      * always deadlock when called from within DllMain */
1437     host_tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
1438     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1439 
1440     ok_more_than_one_lock();
1441     ok_non_zero_external_conn();
1442 
1443     thread = CreateThread(NULL, 0, no_couninitialize_client_proc, &ncu_params, 0, &tid);
1444 
1445     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1446     CloseHandle(thread);
1447 
1448     ok_no_locks();
1449     ok_zero_external_conn();
1450     ok_last_release_closes(TRUE);
1451 
1452     end_host_object(host_tid, host_thread);
1453 }
1454 
1455 static BOOL crash_thread_success;
1456 
1457 static DWORD CALLBACK crash_couninitialize_proc(void *p)
1458 {
1459     IStream *stream;
1460     HRESULT hr;
1461 
1462     cLocks = 0;
1463 
1464     CoInitialize(NULL);
1465 
1466     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1467     ok_ole_success(hr, CreateStreamOnHGlobal);
1468 
1469     hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1470     ok_ole_success(hr, CoMarshalInterface);
1471 
1472     IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
1473 
1474     hr = CoReleaseMarshalData(stream);
1475     ok_ole_success(hr, CoReleaseMarshalData);
1476 
1477     ok_no_locks();
1478 
1479     hr = CoMarshalInterface(stream, &IID_IUnknown, &TestCrash_Unknown, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1480     ok_ole_success(hr, CoMarshalInterface);
1481 
1482     ok_more_than_one_lock();
1483 
1484     trace("CoUninitialize >>>\n");
1485     CoUninitialize();
1486     trace("CoUninitialize <<<\n");
1487 
1488     ok_no_locks();
1489 
1490     IStream_Release(stream);
1491     crash_thread_success = TRUE;
1492     return 0;
1493 }
1494 
1495 static void test_crash_couninitialize(void)
1496 {
1497     HANDLE thread;
1498     DWORD tid;
1499 
1500     if(!GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateActCtxW")) {
1501         win_skip("Skipping crash tests on win2k.\n");
1502         return;
1503     }
1504 
1505     crash_thread_success = FALSE;
1506     thread = CreateThread(NULL, 0, crash_couninitialize_proc, NULL, 0, &tid);
1507     ok(!WaitForSingleObject(thread, 10000), "wait timed out\n");
1508     CloseHandle(thread);
1509     ok(crash_thread_success, "Crash thread failed\n");
1510 }
1511 
1512 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
1513 static void test_tableweak_marshal_and_unmarshal_twice(void)
1514 {
1515     HRESULT hr;
1516     IStream *pStream = NULL;
1517     IUnknown *pProxy1 = NULL;
1518     IUnknown *pProxy2 = NULL;
1519     DWORD tid;
1520     HANDLE thread;
1521 
1522     cLocks = 0;
1523     external_connections = 0;
1524 
1525     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1526     ok_ole_success(hr, CreateStreamOnHGlobal);
1527     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1528 
1529     ok_more_than_one_lock();
1530     ok_zero_external_conn();
1531 
1532     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1533     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1534     ok_ole_success(hr, CoUnmarshalInterface);
1535 
1536     ok_more_than_one_lock();
1537     ok_non_zero_external_conn();
1538 
1539     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1540     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1541     ok_ole_success(hr, CoUnmarshalInterface);
1542 
1543     ok_more_than_one_lock();
1544 
1545     IUnknown_Release(pProxy1);
1546     ok_non_zero_external_conn();
1547     IUnknown_Release(pProxy2);
1548     ok_zero_external_conn();
1549     ok_last_release_closes(TRUE);
1550 
1551     /* When IExternalConnection is present COM's lifetime management
1552      * behaviour is altered; the remaining weak ref prevents stub shutdown. */
1553     if (with_external_conn)
1554     {
1555         ok_more_than_one_lock();
1556         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1557         release_host_object(tid, 0);
1558     }
1559 
1560     /* Without IExternalConnection this line is shows the difference between weak and strong table marshaling
1561      * weak has cLocks == 0, strong has cLocks > 0. */
1562     ok_no_locks();
1563 
1564     IStream_Release(pStream);
1565     end_host_object(tid, thread);
1566 }
1567 
1568 /* tests releasing after unmarshaling one object */
1569 static void test_tableweak_marshal_releasedata1(void)
1570 {
1571     HRESULT hr;
1572     IStream *pStream = NULL;
1573     IUnknown *pProxy1 = NULL;
1574     IUnknown *pProxy2 = NULL;
1575     DWORD tid;
1576     HANDLE thread;
1577 
1578     cLocks = 0;
1579     external_connections = 0;
1580 
1581     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1582     ok_ole_success(hr, CreateStreamOnHGlobal);
1583     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1584 
1585     ok_more_than_one_lock();
1586     ok_zero_external_conn();
1587 
1588     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1589     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1590     ok_ole_success(hr, CoUnmarshalInterface);
1591 
1592     ok_more_than_one_lock();
1593     ok_non_zero_external_conn();
1594 
1595     /* release the remaining reference on the object by calling
1596      * CoReleaseMarshalData in the hosting thread */
1597     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1598     release_host_object(tid, 0);
1599 
1600     ok_more_than_one_lock();
1601     ok_non_zero_external_conn();
1602 
1603     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1604     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1605     ok_ole_success(hr, CoUnmarshalInterface);
1606     IStream_Release(pStream);
1607 
1608     ok_more_than_one_lock();
1609     ok_non_zero_external_conn();
1610 
1611     IUnknown_Release(pProxy1);
1612 
1613     if (pProxy2)
1614     {
1615         ok_non_zero_external_conn();
1616         IUnknown_Release(pProxy2);
1617     }
1618 
1619     /* this line is shows the difference between weak and strong table marshaling:
1620      *  weak has cLocks == 0
1621      *  strong has cLocks > 0 */
1622     ok_no_locks();
1623     ok_zero_external_conn();
1624     ok_last_release_closes(TRUE);
1625 
1626     end_host_object(tid, thread);
1627 }
1628 
1629 /* tests releasing after unmarshaling one object */
1630 static void test_tableweak_marshal_releasedata2(void)
1631 {
1632     HRESULT hr;
1633     IStream *pStream = NULL;
1634     IUnknown *pProxy = NULL;
1635     DWORD tid;
1636     HANDLE thread;
1637 
1638     cLocks = 0;
1639     external_connections = 0;
1640 
1641     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1642     ok_ole_success(hr, CreateStreamOnHGlobal);
1643     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
1644 
1645     ok_more_than_one_lock();
1646     ok_zero_external_conn();
1647 
1648     /* release the remaining reference on the object by calling
1649      * CoReleaseMarshalData in the hosting thread */
1650     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1651     release_host_object(tid, 0);
1652 
1653     ok_no_locks();
1654 
1655     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1656     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
1657     todo_wine
1658     {
1659     ok(hr == CO_E_OBJNOTREG,
1660        "CoUnmarshalInterface should have failed with CO_E_OBJNOTREG, but returned 0x%08x instead\n",
1661        hr);
1662     }
1663     IStream_Release(pStream);
1664 
1665     ok_no_locks();
1666     ok_zero_external_conn();
1667 
1668     end_host_object(tid, thread);
1669 }
1670 
1671 struct duo_marshal_data
1672 {
1673     MSHLFLAGS marshal_flags1, marshal_flags2;
1674     IStream *pStream1, *pStream2;
1675     HANDLE hReadyEvent;
1676     HANDLE hQuitEvent;
1677 };
1678 
1679 static DWORD CALLBACK duo_marshal_thread_proc(void *p)
1680 {
1681     HRESULT hr;
1682     struct duo_marshal_data *data = p;
1683     HANDLE hQuitEvent = data->hQuitEvent;
1684     MSG msg;
1685 
1686     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1687 
1688     hr = CoMarshalInterface(data->pStream1, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags1);
1689     ok_ole_success(hr, "CoMarshalInterface");
1690 
1691     hr = CoMarshalInterface(data->pStream2, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, data->marshal_flags2);
1692     ok_ole_success(hr, "CoMarshalInterface");
1693 
1694     /* force the message queue to be created before signaling parent thread */
1695     PeekMessageA(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
1696 
1697     SetEvent(data->hReadyEvent);
1698 
1699     while (WAIT_OBJECT_0 + 1 == MsgWaitForMultipleObjects(1, &hQuitEvent, FALSE, 10000, QS_ALLINPUT))
1700     {
1701         while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
1702         {
1703             if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
1704             {
1705                 CoReleaseMarshalData(msg.wParam == 1 ? data->pStream1 : data->pStream2);
1706                 SetEvent((HANDLE)msg.lParam);
1707             }
1708             else
1709                 DispatchMessageA(&msg);
1710         }
1711     }
1712     CloseHandle(hQuitEvent);
1713 
1714     CoUninitialize();
1715 
1716     return 0;
1717 }
1718 
1719 /* tests interaction between table-weak and normal marshalling of an object */
1720 static void test_tableweak_and_normal_marshal_and_unmarshal(void)
1721 {
1722     HRESULT hr;
1723     IUnknown *pProxyWeak = NULL;
1724     IUnknown *pProxyNormal = NULL;
1725     DWORD tid;
1726     HANDLE thread;
1727     struct duo_marshal_data data;
1728 
1729     cLocks = 0;
1730     external_connections = 0;
1731 
1732     data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1733     data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1734     data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
1735     data.marshal_flags2 = MSHLFLAGS_NORMAL;
1736     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
1737     ok_ole_success(hr, CreateStreamOnHGlobal);
1738     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
1739     ok_ole_success(hr, CreateStreamOnHGlobal);
1740 
1741     thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
1742     ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
1743     CloseHandle(data.hReadyEvent);
1744 
1745     ok_more_than_one_lock();
1746     ok_non_zero_external_conn();
1747 
1748     /* weak */
1749     IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
1750     hr = CoUnmarshalInterface(data.pStream1, &IID_IClassFactory, (void **)&pProxyWeak);
1751     ok_ole_success(hr, CoUnmarshalInterface);
1752 
1753     ok_more_than_one_lock();
1754 
1755     /* normal */
1756     IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
1757     hr = CoUnmarshalInterface(data.pStream2, &IID_IClassFactory, (void **)&pProxyNormal);
1758     ok_ole_success(hr, CoUnmarshalInterface);
1759 
1760     ok_more_than_one_lock();
1761 
1762     IUnknown_Release(pProxyNormal);
1763 
1764     ok_more_than_one_lock();
1765     ok_non_zero_external_conn();
1766 
1767     IUnknown_Release(pProxyWeak);
1768 
1769     ok_zero_external_conn();
1770     ok_last_release_closes(TRUE);
1771 
1772     /* When IExternalConnection is present COM's lifetime management
1773      * behaviour is altered; the remaining weak ref prevents stub shutdown. */
1774     if (with_external_conn)
1775     {
1776         ok_more_than_one_lock();
1777         IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
1778         release_host_object(tid, 1);
1779     }
1780     ok_no_locks();
1781 
1782     IStream_Release(data.pStream1);
1783     IStream_Release(data.pStream2);
1784 
1785     SetEvent(data.hQuitEvent);
1786     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1787     CloseHandle(thread);
1788 }
1789 
1790 static void test_tableweak_and_normal_marshal_and_releasedata(void)
1791 {
1792     HRESULT hr;
1793     DWORD tid;
1794     HANDLE thread;
1795     struct duo_marshal_data data;
1796 
1797     cLocks = 0;
1798     external_connections = 0;
1799 
1800     data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1801     data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1802     data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
1803     data.marshal_flags2 = MSHLFLAGS_NORMAL;
1804     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
1805     ok_ole_success(hr, CreateStreamOnHGlobal);
1806     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
1807     ok_ole_success(hr, CreateStreamOnHGlobal);
1808 
1809     thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
1810     ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
1811     CloseHandle(data.hReadyEvent);
1812 
1813     ok_more_than_one_lock();
1814     ok_non_zero_external_conn();
1815 
1816     /* release normal - which in the non-external conn case will free the object despite the weak ref. */
1817     IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
1818     release_host_object(tid, 2);
1819 
1820     ok_zero_external_conn();
1821     ok_last_release_closes(TRUE);
1822 
1823     if (with_external_conn)
1824     {
1825         ok_more_than_one_lock();
1826         IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
1827         release_host_object(tid, 1);
1828     }
1829 
1830     ok_no_locks();
1831 
1832     IStream_Release(data.pStream1);
1833     IStream_Release(data.pStream2);
1834 
1835     SetEvent(data.hQuitEvent);
1836     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1837     CloseHandle(thread);
1838 }
1839 
1840 static void test_two_tableweak_marshal_and_releasedata(void)
1841 {
1842     HRESULT hr;
1843     DWORD tid;
1844     HANDLE thread;
1845     struct duo_marshal_data data;
1846 
1847     cLocks = 0;
1848     external_connections = 0;
1849 
1850     data.hReadyEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1851     data.hQuitEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
1852     data.marshal_flags1 = MSHLFLAGS_TABLEWEAK;
1853     data.marshal_flags2 = MSHLFLAGS_TABLEWEAK;
1854     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream1);
1855     ok_ole_success(hr, CreateStreamOnHGlobal);
1856     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.pStream2);
1857     ok_ole_success(hr, CreateStreamOnHGlobal);
1858 
1859     thread = CreateThread(NULL, 0, duo_marshal_thread_proc, &data, 0, &tid);
1860     ok( !WaitForSingleObject(data.hReadyEvent, 10000), "wait timed out\n" );
1861     CloseHandle(data.hReadyEvent);
1862 
1863     ok_more_than_one_lock();
1864     ok_zero_external_conn();
1865 
1866     /* release one weak ref - the remaining weak ref will keep the obj alive */
1867     IStream_Seek(data.pStream1, ullZero, STREAM_SEEK_SET, NULL);
1868     release_host_object(tid, 1);
1869 
1870     ok_more_than_one_lock();
1871 
1872     IStream_Seek(data.pStream2, ullZero, STREAM_SEEK_SET, NULL);
1873     release_host_object(tid, 2);
1874 
1875     ok_no_locks();
1876 
1877     IStream_Release(data.pStream1);
1878     IStream_Release(data.pStream2);
1879 
1880     SetEvent(data.hQuitEvent);
1881     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
1882     CloseHandle(thread);
1883 }
1884 
1885 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
1886 static void test_tablestrong_marshal_and_unmarshal_twice(void)
1887 {
1888     HRESULT hr;
1889     IStream *pStream = NULL;
1890     IUnknown *pProxy1 = NULL;
1891     IUnknown *pProxy2 = NULL;
1892     DWORD tid;
1893     HANDLE thread;
1894 
1895     cLocks = 0;
1896     external_connections = 0;
1897 
1898     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1899     ok_ole_success(hr, CreateStreamOnHGlobal);
1900     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
1901 
1902     ok_more_than_one_lock();
1903     ok_non_zero_external_conn();
1904 
1905     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1906     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
1907     ok_ole_success(hr, CoUnmarshalInterface);
1908 
1909     ok_more_than_one_lock();
1910 
1911     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1912     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
1913     ok_ole_success(hr, CoUnmarshalInterface);
1914 
1915     ok_more_than_one_lock();
1916 
1917     if (pProxy1) IUnknown_Release(pProxy1);
1918     if (pProxy2) IUnknown_Release(pProxy2);
1919 
1920     /* this line is shows the difference between weak and strong table marshaling:
1921      *  weak has cLocks == 0
1922      *  strong has cLocks > 0 */
1923     ok_more_than_one_lock();
1924 
1925     /* release the remaining reference on the object by calling
1926      * CoReleaseMarshalData in the hosting thread */
1927     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1928     release_host_object(tid, 0);
1929     IStream_Release(pStream);
1930 
1931     ok_no_locks();
1932     ok_zero_external_conn();
1933     ok_last_release_closes(TRUE);
1934 
1935     end_host_object(tid, thread);
1936 }
1937 
1938 /* tests CoLockObjectExternal */
1939 static void test_lock_object_external(void)
1940 {
1941     HRESULT hr;
1942     IStream *pStream = NULL;
1943 
1944     cLocks = 0;
1945     external_connections = 0;
1946 
1947     /* test the stub manager creation aspect of CoLockObjectExternal when the
1948      * object hasn't been marshaled yet */
1949     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1950 
1951     ok_more_than_one_lock();
1952     ok_non_zero_external_conn();
1953 
1954     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
1955 
1956     ok_no_locks();
1957     ok_non_zero_external_conn();
1958     external_connections = 0;
1959 
1960     /* test our empty stub manager being handled correctly in
1961      * CoMarshalInterface */
1962     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1963 
1964     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1965     ok_ole_success(hr, CreateStreamOnHGlobal);
1966     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1967     ok_ole_success(hr, CoMarshalInterface);
1968 
1969     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
1970 
1971     ok_more_than_one_lock();
1972     ok_non_zero_external_conn();
1973 
1974     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1975     hr = CoReleaseMarshalData(pStream);
1976     ok_ole_success(hr, CoReleaseMarshalData);
1977     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
1978 
1979     ok_more_than_one_lock();
1980     ok_non_zero_external_conn();
1981     ok_last_release_closes(TRUE);
1982 
1983     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
1984 
1985     ok_more_than_one_lock();
1986     ok_non_zero_external_conn();
1987     ok_last_release_closes(TRUE);
1988 
1989     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
1990 
1991     ok_no_locks();
1992     ok_zero_external_conn();
1993     ok_last_release_closes(TRUE);
1994 
1995     /* test CoLockObjectExternal releases reference to object with
1996      * fLastUnlockReleases as TRUE and there are only strong references on
1997      * the object */
1998     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
1999 
2000     ok_more_than_one_lock();
2001     ok_non_zero_external_conn();
2002 
2003     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
2004 
2005     ok_no_locks();
2006     ok_zero_external_conn();
2007     ok_last_release_closes(FALSE);
2008 
2009     /* test CoLockObjectExternal doesn't release the last reference to an
2010      * object with fLastUnlockReleases as TRUE and there is a weak reference
2011      * on the object */
2012     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLEWEAK);
2013     ok_ole_success(hr, CoMarshalInterface);
2014 
2015     ok_more_than_one_lock();
2016     ok_zero_external_conn();
2017 
2018     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, FALSE);
2019 
2020     ok_more_than_one_lock();
2021     ok_non_zero_external_conn();
2022 
2023     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, FALSE);
2024 
2025     ok_more_than_one_lock();
2026     ok_zero_external_conn();
2027     ok_last_release_closes(FALSE);
2028 
2029     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2030 
2031     ok_no_locks();
2032 
2033     IStream_Release(pStream);
2034 }
2035 
2036 /* tests disconnecting stubs */
2037 static void test_disconnect_stub(void)
2038 {
2039     HRESULT hr;
2040     IStream *pStream = NULL;
2041 
2042     cLocks = 0;
2043     external_connections = 0;
2044 
2045     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2046     ok_ole_success(hr, CreateStreamOnHGlobal);
2047     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2048     ok_ole_success(hr, CoMarshalInterface);
2049 
2050     ok_non_zero_external_conn();
2051 
2052     CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
2053 
2054     ok_more_than_one_lock();
2055     ok_non_zero_external_conn();
2056 
2057     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2058     hr = CoReleaseMarshalData(pStream);
2059     ok_ole_success(hr, CoReleaseMarshalData);
2060     IStream_Release(pStream);
2061 
2062     ok_more_than_one_lock();
2063     ok_non_zero_external_conn();
2064 
2065     CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
2066 
2067     ok_no_locks();
2068     ok_non_zero_external_conn();
2069 
2070     hr = CoDisconnectObject(NULL, 0);
2071     ok( hr == E_INVALIDARG, "wrong status %x\n", hr );
2072 }
2073 
2074 /* tests failure case of a same-thread marshal and unmarshal twice */
2075 static void test_normal_marshal_and_unmarshal_twice(void)
2076 {
2077     HRESULT hr;
2078     IStream *pStream = NULL;
2079     IUnknown *pProxy1 = NULL;
2080     IUnknown *pProxy2 = NULL;
2081 
2082     cLocks = 0;
2083     external_connections = 0;
2084 
2085     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2086     ok_ole_success(hr, CreateStreamOnHGlobal);
2087     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2088     ok_ole_success(hr, CoMarshalInterface);
2089 
2090     ok_more_than_one_lock();
2091     ok_non_zero_external_conn();
2092 
2093     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2094     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
2095     ok_ole_success(hr, CoUnmarshalInterface);
2096 
2097     ok_more_than_one_lock();
2098     ok_zero_external_conn();
2099     ok_last_release_closes(FALSE);
2100 
2101     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2102     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
2103     ok(hr == CO_E_OBJNOTCONNECTED,
2104         "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08x\n", hr);
2105 
2106     IStream_Release(pStream);
2107 
2108     ok_more_than_one_lock();
2109 
2110     IUnknown_Release(pProxy1);
2111 
2112     ok_no_locks();
2113 }
2114 
2115 /* tests success case of marshaling and unmarshaling an HRESULT */
2116 static void test_hresult_marshaling(void)
2117 {
2118     HRESULT hr;
2119     HRESULT hr_marshaled = 0;
2120     IStream *pStream = NULL;
2121     static const HRESULT E_DEADBEEF = 0xdeadbeef;
2122 
2123     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2124     ok_ole_success(hr, CreateStreamOnHGlobal);
2125 
2126     hr = CoMarshalHresult(pStream, E_DEADBEEF);
2127     ok_ole_success(hr, CoMarshalHresult);
2128 
2129     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2130     hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
2131     ok_ole_success(hr, IStream_Read);
2132 
2133     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
2134 
2135     hr_marshaled = 0;
2136     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2137     hr = CoUnmarshalHresult(pStream, &hr_marshaled);
2138     ok_ole_success(hr, CoUnmarshalHresult);
2139 
2140     ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08x instead\n", hr_marshaled);
2141 
2142     IStream_Release(pStream);
2143 }
2144 
2145 
2146 /* helper for test_proxy_used_in_wrong_thread */
2147 static DWORD CALLBACK bad_thread_proc(LPVOID p)
2148 {
2149     IClassFactory * cf = p;
2150     HRESULT hr;
2151     IUnknown * proxy = NULL;
2152 
2153     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2154     todo_wine
2155     ok(hr == CO_E_NOTINITIALIZED,
2156        "COM should have failed with CO_E_NOTINITIALIZED on using proxy without apartment, but instead returned 0x%08x\n",
2157        hr);
2158 
2159     hr = IClassFactory_QueryInterface(cf, &IID_IMultiQI, (LPVOID *)&proxy);
2160     /* Win9x returns S_OK, whilst NT returns RPC_E_WRONG_THREAD */
2161     trace("call to proxy's QueryInterface for local interface without apartment returned 0x%08x\n", hr);
2162     if (SUCCEEDED(hr))
2163         IUnknown_Release(proxy);
2164 
2165     hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
2166     /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
2167     trace("call to proxy's QueryInterface without apartment returned 0x%08x\n", hr);
2168     if (SUCCEEDED(hr))
2169         IUnknown_Release(proxy);
2170 
2171     pCoInitializeEx(NULL, COINIT_MULTITHREADED);
2172 
2173     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2174     if (proxy) IUnknown_Release(proxy);
2175     ok(hr == RPC_E_WRONG_THREAD,
2176         "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08x\n",
2177         hr);
2178 
2179     hr = IClassFactory_QueryInterface(cf, &IID_IStream, (LPVOID *)&proxy);
2180     /* Win9x returns E_NOINTERFACE, whilst NT returns RPC_E_WRONG_THREAD */
2181     trace("call to proxy's QueryInterface from wrong apartment returned 0x%08x\n", hr);
2182 
2183     /* now be really bad and release the proxy from the wrong apartment */
2184     IClassFactory_Release(cf);
2185 
2186     CoUninitialize();
2187 
2188     return 0;
2189 }
2190 
2191 /* tests failure case of a using a proxy in the wrong apartment */
2192 static void test_proxy_used_in_wrong_thread(void)
2193 {
2194     HRESULT hr;
2195     IStream *pStream = NULL;
2196     IUnknown *pProxy = NULL;
2197     DWORD tid, tid2;
2198     HANDLE thread;
2199     HANDLE host_thread;
2200 
2201     cLocks = 0;
2202 
2203     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2204     ok_ole_success(hr, CreateStreamOnHGlobal);
2205     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
2206 
2207     ok_more_than_one_lock();
2208 
2209     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2210     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
2211     ok_ole_success(hr, CoUnmarshalInterface);
2212     IStream_Release(pStream);
2213 
2214     ok_more_than_one_lock();
2215 
2216     /* do a call that will fail, but result in IRemUnknown being used by the proxy */
2217     IUnknown_QueryInterface(pProxy, &IID_IStream, (LPVOID *)&pStream);
2218 
2219     /* create a thread that we can misbehave in */
2220     thread = CreateThread(NULL, 0, bad_thread_proc, pProxy, 0, &tid2);
2221 
2222     ok( !WaitForSingleObject(thread, 10000), "wait timed out\n" );
2223     CloseHandle(thread);
2224 
2225     /* do release statement on Win9x that we should have done above */
2226     if (!GetProcAddress(GetModuleHandleA("ole32"), "CoRegisterSurrogateEx"))
2227         IUnknown_Release(pProxy);
2228 
2229     ok_no_locks();
2230 
2231     end_host_object(tid, host_thread);
2232 }
2233 
2234 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
2235 {
2236     if (ppvObj == NULL) return E_POINTER;
2237 
2238     if (IsEqualGUID(riid, &IID_IUnknown) ||
2239         IsEqualGUID(riid, &IID_IClassFactory))
2240     {
2241         *ppvObj = iface;
2242         IMessageFilter_AddRef(iface);
2243         return S_OK;
2244     }
2245 
2246     return E_NOINTERFACE;
2247 }
2248 
2249 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
2250 {
2251     return 2; /* non-heap object */
2252 }
2253 
2254 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
2255 {
2256     return 1; /* non-heap object */
2257 }
2258 
2259 static DWORD WINAPI MessageFilter_HandleInComingCall(
2260   IMessageFilter *iface,
2261   DWORD dwCallType,
2262   HTASK threadIDCaller,
2263   DWORD dwTickCount,
2264   LPINTERFACEINFO lpInterfaceInfo)
2265 {
2266     static int callcount = 0;
2267     DWORD ret;
2268     trace("HandleInComingCall\n");
2269     switch (callcount)
2270     {
2271     case 0:
2272         ret = SERVERCALL_REJECTED;
2273         break;
2274     case 1:
2275         ret = SERVERCALL_RETRYLATER;
2276         break;
2277     default:
2278         ret = SERVERCALL_ISHANDLED;
2279         break;
2280     }
2281     callcount++;
2282     return ret;
2283 }
2284 
2285 static DWORD WINAPI MessageFilter_RetryRejectedCall(
2286   IMessageFilter *iface,
2287   HTASK threadIDCallee,
2288   DWORD dwTickCount,
2289   DWORD dwRejectType)
2290 {
2291     trace("RetryRejectedCall\n");
2292     return 0;
2293 }
2294 
2295 static DWORD WINAPI MessageFilter_MessagePending(
2296   IMessageFilter *iface,
2297   HTASK threadIDCallee,
2298   DWORD dwTickCount,
2299   DWORD dwPendingType)
2300 {
2301     trace("MessagePending\n");
2302     return PENDINGMSG_WAITNOPROCESS;
2303 }
2304 
2305 static const IMessageFilterVtbl MessageFilter_Vtbl =
2306 {
2307     MessageFilter_QueryInterface,
2308     MessageFilter_AddRef,
2309     MessageFilter_Release,
2310     MessageFilter_HandleInComingCall,
2311     MessageFilter_RetryRejectedCall,
2312     MessageFilter_MessagePending
2313 };
2314 
2315 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
2316 
2317 static void test_message_filter(void)
2318 {
2319     HRESULT hr;
2320     IClassFactory *cf = NULL;
2321     DWORD tid;
2322     IUnknown *proxy = NULL;
2323     IMessageFilter *prev_filter = NULL;
2324     HANDLE thread;
2325 
2326     struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
2327                                             MSHLFLAGS_NORMAL, &MessageFilter };
2328 
2329     cLocks = 0;
2330 
2331     hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
2332     ok_ole_success(hr, CreateStreamOnHGlobal);
2333     tid = start_host_object2(&object_data, &thread);
2334 
2335     ok_more_than_one_lock();
2336 
2337     IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
2338     hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
2339     ok_ole_success(hr, CoUnmarshalInterface);
2340     IStream_Release(object_data.stream);
2341 
2342     ok_more_than_one_lock();
2343 
2344     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2345     ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08x instead\n", hr);
2346     if (proxy) IUnknown_Release(proxy);
2347     proxy = NULL;
2348 
2349     hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
2350     ok_ole_success(hr, CoRegisterMessageFilter);
2351 
2352     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
2353     ok_ole_success(hr, IClassFactory_CreateInstance);
2354 
2355     IUnknown_Release(proxy);
2356 
2357     IClassFactory_Release(cf);
2358 
2359     ok_no_locks();
2360 
2361     end_host_object(tid, thread);
2362 
2363     hr = CoRegisterMessageFilter(prev_filter, NULL);
2364     ok_ole_success(hr, CoRegisterMessageFilter);
2365 }
2366 
2367 /* test failure case of trying to unmarshal from bad stream */
2368 static void test_bad_marshal_stream(void)
2369 {
2370     HRESULT hr;
2371     IStream *pStream = NULL;
2372 
2373     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2374     ok_ole_success(hr, CreateStreamOnHGlobal);
2375     hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2376     ok_ole_success(hr, CoMarshalInterface);
2377 
2378     ok_more_than_one_lock();
2379 
2380     /* try to read beyond end of stream */
2381     hr = CoReleaseMarshalData(pStream);
2382     ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08x instead\n", hr);
2383 
2384     /* now release for real */
2385     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2386     hr = CoReleaseMarshalData(pStream);
2387     ok_ole_success(hr, CoReleaseMarshalData);
2388 
2389     IStream_Release(pStream);
2390 }
2391 
2392 /* tests that proxies implement certain interfaces */
2393 static void test_proxy_interfaces(void)
2394 {
2395     HRESULT hr;
2396     IStream *pStream = NULL;
2397     IUnknown *pProxy = NULL;
2398     IUnknown *pOtherUnknown = NULL;
2399     DWORD tid;
2400     HANDLE thread;
2401 
2402     cLocks = 0;
2403 
2404     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2405     ok_ole_success(hr, CreateStreamOnHGlobal);
2406     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2407 
2408     ok_more_than_one_lock();
2409 
2410     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2411     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
2412     ok_ole_success(hr, CoUnmarshalInterface);
2413     IStream_Release(pStream);
2414 
2415     ok_more_than_one_lock();
2416 
2417     hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
2418     ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
2419     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2420 
2421     hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
2422     ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity);
2423     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2424 
2425     hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
2426     ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI);
2427     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2428 
2429     hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
2430     ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal);
2431     if (hr == S_OK) IUnknown_Release(pOtherUnknown);
2432 
2433     /* IMarshal2 is also supported on NT-based systems, but is pretty much
2434      * useless as it has no more methods over IMarshal that it inherits from. */
2435 
2436     IUnknown_Release(pProxy);
2437 
2438     ok_no_locks();
2439 
2440     end_host_object(tid, thread);
2441 }
2442 
2443 typedef struct
2444 {
2445     IUnknown IUnknown_iface;
2446     ULONG refs;
2447 } HeapUnknown;
2448 
2449 static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
2450 {
2451     return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
2452 }
2453 
2454 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
2455 {
2456     if (IsEqualIID(riid, &IID_IUnknown))
2457     {
2458         IUnknown_AddRef(iface);
2459         *ppv = iface;
2460         return S_OK;
2461     }
2462     *ppv = NULL;
2463     return E_NOINTERFACE;
2464 }
2465 
2466 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
2467 {
2468     HeapUnknown *This = impl_from_IUnknown(iface);
2469     return InterlockedIncrement((LONG*)&This->refs);
2470 }
2471 
2472 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
2473 {
2474     HeapUnknown *This = impl_from_IUnknown(iface);
2475     ULONG refs = InterlockedDecrement((LONG*)&This->refs);
2476     if (!refs) HeapFree(GetProcessHeap(), 0, This);
2477     return refs;
2478 }
2479 
2480 static const IUnknownVtbl HeapUnknown_Vtbl =
2481 {
2482     HeapUnknown_QueryInterface,
2483     HeapUnknown_AddRef,
2484     HeapUnknown_Release
2485 };
2486 
2487 static void test_proxybuffer(REFIID riid)
2488 {
2489     HRESULT hr;
2490     IPSFactoryBuffer *psfb;
2491     IRpcProxyBuffer *proxy;
2492     LPVOID lpvtbl;
2493     ULONG refs;
2494     CLSID clsid;
2495     HeapUnknown *pUnkOuter = HeapAlloc(GetProcessHeap(), 0, sizeof(*pUnkOuter));
2496 
2497     pUnkOuter->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
2498     pUnkOuter->refs = 1;
2499 
2500     hr = CoGetPSClsid(riid, &clsid);
2501     ok_ole_success(hr, CoGetPSClsid);
2502 
2503     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
2504     ok_ole_success(hr, CoGetClassObject);
2505 
2506     hr = IPSFactoryBuffer_CreateProxy(psfb, &pUnkOuter->IUnknown_iface, riid, &proxy, &lpvtbl);
2507     ok_ole_success(hr, IPSFactoryBuffer_CreateProxy);
2508     ok(lpvtbl != NULL, "IPSFactoryBuffer_CreateProxy succeeded, but returned a NULL vtable!\n");
2509 
2510     /* release our reference to the outer unknown object - the PS factory
2511      * buffer will have AddRef's it in the CreateProxy call */
2512     refs = IUnknown_Release(&pUnkOuter->IUnknown_iface);
2513     ok(refs == 1, "Ref count of outer unknown should have been 1 instead of %d\n", refs);
2514 
2515     /* Not checking return, unreliable on native. Maybe it leaks references? */
2516     IPSFactoryBuffer_Release(psfb);
2517 
2518     refs = IUnknown_Release((IUnknown *)lpvtbl);
2519     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2520 
2521     refs = IRpcProxyBuffer_Release(proxy);
2522     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2523 }
2524 
2525 static void test_stubbuffer(REFIID riid)
2526 {
2527     HRESULT hr;
2528     IPSFactoryBuffer *psfb;
2529     IRpcStubBuffer *stub;
2530     ULONG refs;
2531     CLSID clsid;
2532 
2533     cLocks = 0;
2534 
2535     hr = CoGetPSClsid(riid, &clsid);
2536     ok_ole_success(hr, CoGetPSClsid);
2537 
2538     hr = CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (LPVOID*)&psfb);
2539     ok_ole_success(hr, CoGetClassObject);
2540 
2541     hr = IPSFactoryBuffer_CreateStub(psfb, riid, (IUnknown*)&Test_ClassFactory, &stub);
2542     ok_ole_success(hr, IPSFactoryBuffer_CreateStub);
2543 
2544     /* Not checking return, unreliable on native. Maybe it leaks references? */
2545     IPSFactoryBuffer_Release(psfb);
2546 
2547     ok_more_than_one_lock();
2548 
2549     IRpcStubBuffer_Disconnect(stub);
2550 
2551     ok_no_locks();
2552 
2553     refs = IRpcStubBuffer_Release(stub);
2554     ok(refs == 0, "Ref-count leak of %d on IRpcProxyBuffer\n", refs);
2555 }
2556 
2557 static HWND hwnd_app;
2558 
2559 static HRESULT WINAPI TestRE_IClassFactory_CreateInstance(
2560     LPCLASSFACTORY iface,
2561     LPUNKNOWN pUnkOuter,
2562     REFIID riid,
2563     LPVOID *ppvObj)
2564 {
2565     DWORD_PTR res;
2566     if (IsEqualIID(riid, &IID_IWineTest))
2567     {
2568         BOOL ret = SendMessageTimeoutA(hwnd_app, WM_NULL, 0, 0, SMTO_BLOCK, 5000, &res);
2569         ok(ret, "Timed out sending a message to originating window during RPC call\n");
2570     }
2571     *ppvObj = NULL;
2572     return S_FALSE;
2573 }
2574 
2575 static const IClassFactoryVtbl TestREClassFactory_Vtbl =
2576 {
2577     Test_IClassFactory_QueryInterface,
2578     Test_IClassFactory_AddRef,
2579     Test_IClassFactory_Release,
2580     TestRE_IClassFactory_CreateInstance,
2581     Test_IClassFactory_LockServer
2582 };
2583 
2584 static IClassFactory TestRE_ClassFactory = { &TestREClassFactory_Vtbl };
2585 
2586 static LRESULT CALLBACK window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
2587 {
2588     switch (msg)
2589     {
2590     case WM_USER:
2591     {
2592         HRESULT hr;
2593         IStream *pStream = NULL;
2594         IClassFactory *proxy = NULL;
2595         IUnknown *object;
2596         DWORD tid;
2597         HANDLE thread;
2598 
2599         cLocks = 0;
2600 
2601         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2602         ok_ole_success(hr, CreateStreamOnHGlobal);
2603         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2604 
2605         ok_more_than_one_lock();
2606 
2607         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2608         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2609         ok_ole_success(hr, CoReleaseMarshalData);
2610         IStream_Release(pStream);
2611 
2612         ok_more_than_one_lock();
2613 
2614         /* note the use of the magic IID_IWineTest value to tell remote thread
2615          * to try to send a message back to us */
2616         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IWineTest, (void **)&object);
2617         ok(hr == S_FALSE, "expected S_FALSE, got %d\n", hr);
2618 
2619         IClassFactory_Release(proxy);
2620 
2621         ok_no_locks();
2622 
2623         end_host_object(tid, thread);
2624 
2625         PostMessageA(hwnd, WM_QUIT, 0, 0);
2626 
2627         return 0;
2628     }
2629     case WM_USER+1:
2630     {
2631         HRESULT hr;
2632         IStream *pStream = NULL;
2633         IClassFactory *proxy = NULL;
2634         IUnknown *object;
2635         DWORD tid;
2636         HANDLE thread;
2637 
2638         cLocks = 0;
2639 
2640         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2641         ok_ole_success(hr, CreateStreamOnHGlobal);
2642         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestRE_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2643 
2644         ok_more_than_one_lock();
2645 
2646         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2647         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2648         ok_ole_success(hr, CoReleaseMarshalData);
2649         IStream_Release(pStream);
2650 
2651         ok_more_than_one_lock();
2652 
2653         /* post quit message before a doing a COM call to show that a pending
2654         * WM_QUIT message doesn't stop the call from succeeding */
2655         PostMessageA(hwnd, WM_QUIT, 0, 0);
2656         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
2657 	ok(hr == S_FALSE, "IClassFactory_CreateInstance returned 0x%08x, expected S_FALSE\n", hr);
2658 
2659         IClassFactory_Release(proxy);
2660 
2661         ok_no_locks();
2662 
2663         end_host_object(tid, thread);
2664 
2665         return 0;
2666     }
2667     case WM_USER+2:
2668     {
2669         HRESULT hr;
2670         IStream *pStream = NULL;
2671         IClassFactory *proxy = NULL;
2672         IUnknown *object;
2673         DWORD tid;
2674         HANDLE thread;
2675 
2676         hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2677         ok_ole_success(hr, CreateStreamOnHGlobal);
2678         tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2679 
2680         IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2681         hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2682         ok_ole_success(hr, CoReleaseMarshalData);
2683         IStream_Release(pStream);
2684 
2685         /* shows that COM calls executed during the processing of sent
2686          * messages should fail */
2687         hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
2688         ok(hr == RPC_E_CANTCALLOUT_ININPUTSYNCCALL,
2689            "COM call during processing of sent message should return RPC_E_CANTCALLOUT_ININPUTSYNCCALL instead of 0x%08x\n", hr);
2690 
2691         IClassFactory_Release(proxy);
2692 
2693         end_host_object(tid, thread);
2694 
2695         PostQuitMessage(0);
2696 
2697         return 0;
2698     }
2699     default:
2700         return DefWindowProcA(hwnd, msg, wparam, lparam);
2701     }
2702 }
2703 
2704 static void register_test_window(void)
2705 {
2706     WNDCLASSA wndclass;
2707 
2708     memset(&wndclass, 0, sizeof(wndclass));
2709     wndclass.lpfnWndProc = window_proc;
2710     wndclass.lpszClassName = "WineCOMTest";
2711     RegisterClassA(&wndclass);
2712 }
2713 
2714 static void test_message_reentrancy(void)
2715 {
2716     MSG msg;
2717 
2718     hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
2719     ok(hwnd_app != NULL, "Window creation failed\n");
2720 
2721     /* start message re-entrancy test */
2722     PostMessageA(hwnd_app, WM_USER, 0, 0);
2723 
2724     while (GetMessageA(&msg, NULL, 0, 0))
2725     {
2726         TranslateMessage(&msg);
2727         DispatchMessageA(&msg);
2728     }
2729     DestroyWindow(hwnd_app);
2730 }
2731 
2732 static HRESULT WINAPI TestMsg_IClassFactory_CreateInstance(
2733     LPCLASSFACTORY iface,
2734     LPUNKNOWN pUnkOuter,
2735     REFIID riid,
2736     LPVOID *ppvObj)
2737 {
2738     *ppvObj = NULL;
2739     SendMessageA(hwnd_app, WM_USER+2, 0, 0);
2740     return S_OK;
2741 }
2742 
2743 static IClassFactoryVtbl TestMsgClassFactory_Vtbl =
2744 {
2745     Test_IClassFactory_QueryInterface,
2746     Test_IClassFactory_AddRef,
2747     Test_IClassFactory_Release,
2748     TestMsg_IClassFactory_CreateInstance,
2749     Test_IClassFactory_LockServer
2750 };
2751 
2752 static IClassFactory TestMsg_ClassFactory = { &TestMsgClassFactory_Vtbl };
2753 
2754 static void test_call_from_message(void)
2755 {
2756     MSG msg;
2757     IStream *pStream;
2758     HRESULT hr;
2759     IClassFactory *proxy;
2760     DWORD tid;
2761     HANDLE thread;
2762     IUnknown *object;
2763 
2764     hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
2765     ok(hwnd_app != NULL, "Window creation failed\n");
2766 
2767     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2768     ok_ole_success(hr, CreateStreamOnHGlobal);
2769     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&TestMsg_ClassFactory, MSHLFLAGS_NORMAL, &thread);
2770 
2771     ok_more_than_one_lock();
2772 
2773     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
2774     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&proxy);
2775     ok_ole_success(hr, CoReleaseMarshalData);
2776     IStream_Release(pStream);
2777 
2778     ok_more_than_one_lock();
2779 
2780     /* start message re-entrancy test */
2781     hr = IClassFactory_CreateInstance(proxy, NULL, &IID_IUnknown, (void **)&object);
2782     ok_ole_success(hr, IClassFactory_CreateInstance);
2783 
2784     IClassFactory_Release(proxy);
2785 
2786     ok_no_locks();
2787 
2788     end_host_object(tid, thread);
2789 
2790     while (GetMessageA(&msg, NULL, 0, 0))
2791     {
2792         TranslateMessage(&msg);
2793         DispatchMessageA(&msg);
2794     }
2795     DestroyWindow(hwnd_app);
2796 }
2797 
2798 static void test_WM_QUIT_handling(void)
2799 {
2800     MSG msg;
2801 
2802     hwnd_app = CreateWindowA("WineCOMTest", NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, 0);
2803     ok(hwnd_app != NULL, "Window creation failed\n");
2804 
2805     /* start WM_QUIT handling test */
2806     PostMessageA(hwnd_app, WM_USER+1, 0, 0);
2807 
2808     while (GetMessageA(&msg, NULL, 0, 0))
2809     {
2810         TranslateMessage(&msg);
2811         DispatchMessageA(&msg);
2812     }
2813 }
2814 
2815 static SIZE_T round_global_size(SIZE_T size)
2816 {
2817     static SIZE_T global_size_alignment = -1;
2818     if (global_size_alignment == -1)
2819     {
2820         void *p = GlobalAlloc(GMEM_FIXED, 1);
2821         global_size_alignment = GlobalSize(p);
2822         GlobalFree(p);
2823     }
2824 
2825     return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1));
2826 }
2827 
2828 static void test_freethreadedmarshaldata(IStream *pStream, MSHCTX mshctx, void *ptr, DWORD mshlflags)
2829 {
2830     HGLOBAL hglobal;
2831     DWORD size;
2832     char *marshal_data;
2833     HRESULT hr;
2834 
2835     hr = GetHGlobalFromStream(pStream, &hglobal);
2836     ok_ole_success(hr, GetHGlobalFromStream);
2837 
2838     size = GlobalSize(hglobal);
2839 
2840     marshal_data = GlobalLock(hglobal);
2841 
2842     if (mshctx == MSHCTX_INPROC)
2843     {
2844         DWORD expected_size = round_global_size(3*sizeof(DWORD) + sizeof(GUID));
2845         ok(size == expected_size ||
2846            broken(size == (2*sizeof(DWORD))) /* Win9x & NT4 */,
2847            "size should have been %d instead of %d\n", expected_size, size);
2848 
2849         ok(*(DWORD *)marshal_data == mshlflags, "expected 0x%x, but got 0x%x for mshctx\n", mshlflags, *(DWORD *)marshal_data);
2850         marshal_data += sizeof(DWORD);
2851         ok(*(void **)marshal_data == ptr, "expected %p, but got %p for mshctx\n", ptr, *(void **)marshal_data);
2852         marshal_data += sizeof(void *);
2853         if (sizeof(void*) == 4 && size >= 3*sizeof(DWORD))
2854         {
2855             ok(*(DWORD *)marshal_data == 0, "expected 0x0, but got 0x%x\n", *(DWORD *)marshal_data);
2856             marshal_data += sizeof(DWORD);
2857         }
2858         if (size >= 3*sizeof(DWORD) + sizeof(GUID))
2859         {
2860             trace("got guid data: %s\n", wine_dbgstr_guid((GUID *)marshal_data));
2861         }
2862     }
2863     else
2864     {
2865         ok(size > sizeof(DWORD), "size should have been > sizeof(DWORD), not %d\n", size);
2866         ok(*(DWORD *)marshal_data == 0x574f454d /* MEOW */,
2867             "marshal data should be filled by standard marshal and start with MEOW signature\n");
2868     }
2869 
2870     GlobalUnlock(hglobal);
2871 }
2872 
2873 static void test_freethreadedmarshaler(void)
2874 {
2875     HRESULT hr;
2876     IUnknown *pFTUnknown;
2877     IMarshal *pFTMarshal;
2878     IStream *pStream;
2879     IUnknown *pProxy;
2880     static const LARGE_INTEGER llZero;
2881 
2882     cLocks = 0;
2883     hr = CoCreateFreeThreadedMarshaler(NULL, &pFTUnknown);
2884     ok_ole_success(hr, CoCreateFreeThreadedMarshaler);
2885     hr = IUnknown_QueryInterface(pFTUnknown, &IID_IMarshal, (void **)&pFTMarshal);
2886     ok_ole_success(hr, IUnknown_QueryInterface);
2887     IUnknown_Release(pFTUnknown);
2888 
2889     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
2890     ok_ole_success(hr, CreateStreamOnHGlobal);
2891 
2892     /* inproc normal marshaling */
2893 
2894     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
2895         &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2896     ok_ole_success(hr, IMarshal_MarshalInterface);
2897 
2898     ok_more_than_one_lock();
2899 
2900     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_NORMAL);
2901 
2902     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2903     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
2904     ok_ole_success(hr, IMarshal_UnmarshalInterface);
2905 
2906     IUnknown_Release(pProxy);
2907 
2908     ok_no_locks();
2909 
2910 /* native doesn't allow us to unmarshal or release the stream data,
2911  * presumably because it wants us to call CoMarshalInterface instead */
2912     if (0)
2913     {
2914     /* local normal marshaling */
2915 
2916     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2917     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory, &Test_ClassFactory, MSHCTX_LOCAL, NULL, MSHLFLAGS_NORMAL);
2918     ok_ole_success(hr, IMarshal_MarshalInterface);
2919 
2920     ok_more_than_one_lock();
2921 
2922     test_freethreadedmarshaldata(pStream, MSHCTX_LOCAL, &Test_ClassFactory, MSHLFLAGS_NORMAL);
2923 
2924     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2925     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
2926     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
2927 
2928     ok_no_locks();
2929     }
2930 
2931     /* inproc table-strong marshaling */
2932 
2933     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2934     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
2935         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
2936         MSHLFLAGS_TABLESTRONG);
2937     ok_ole_success(hr, IMarshal_MarshalInterface);
2938 
2939     ok_more_than_one_lock();
2940 
2941     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLESTRONG);
2942 
2943     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2944     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
2945     ok_ole_success(hr, IMarshal_UnmarshalInterface);
2946 
2947     IUnknown_Release(pProxy);
2948 
2949     ok_more_than_one_lock();
2950 
2951     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2952     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
2953     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
2954 
2955     ok_no_locks();
2956 
2957     /* inproc table-weak marshaling */
2958 
2959     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2960     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
2961         (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, (void *)0xdeadbeef,
2962         MSHLFLAGS_TABLEWEAK);
2963     ok_ole_success(hr, IMarshal_MarshalInterface);
2964 
2965     ok_no_locks();
2966 
2967     test_freethreadedmarshaldata(pStream, MSHCTX_INPROC, &Test_ClassFactory, MSHLFLAGS_TABLEWEAK);
2968 
2969     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2970     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
2971     ok_ole_success(hr, IMarshal_UnmarshalInterface);
2972 
2973     ok_more_than_one_lock();
2974 
2975     IUnknown_Release(pProxy);
2976 
2977     ok_no_locks();
2978 
2979     /* inproc normal marshaling (for extraordinary cases) */
2980 
2981     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2982     hr = IMarshal_MarshalInterface(pFTMarshal, pStream, &IID_IClassFactory,
2983         &Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
2984     ok_ole_success(hr, IMarshal_MarshalInterface);
2985 
2986     ok_more_than_one_lock();
2987 
2988     /* this call shows that DisconnectObject does nothing */
2989     hr = IMarshal_DisconnectObject(pFTMarshal, 0);
2990     ok_ole_success(hr, IMarshal_DisconnectObject);
2991 
2992     ok_more_than_one_lock();
2993 
2994     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
2995     hr = IMarshal_ReleaseMarshalData(pFTMarshal, pStream);
2996     ok_ole_success(hr, IMarshal_ReleaseMarshalData);
2997 
2998     ok_no_locks();
2999 
3000     /* doesn't enforce marshaling rules here and allows us to unmarshal the
3001      * interface, even though it was freed above */
3002     IStream_Seek(pStream, llZero, STREAM_SEEK_SET, NULL);
3003     hr = IMarshal_UnmarshalInterface(pFTMarshal, pStream, &IID_IUnknown, (void **)&pProxy);
3004     ok_ole_success(hr, IMarshal_UnmarshalInterface);
3005 
3006     ok_no_locks();
3007 
3008     IStream_Release(pStream);
3009     IMarshal_Release(pFTMarshal);
3010 }
3011 
3012 static HRESULT reg_unreg_wine_test_class(BOOL Register)
3013 {
3014     HRESULT hr;
3015     char buffer[256];
3016     LPOLESTR pszClsid;
3017     HKEY hkey;
3018     DWORD dwDisposition;
3019     DWORD error;
3020 
3021     hr = StringFromCLSID(&CLSID_WineTest, &pszClsid);
3022     ok_ole_success(hr, "StringFromCLSID");
3023     strcpy(buffer, "CLSID\\");
3024     WideCharToMultiByte(CP_ACP, 0, pszClsid, -1, buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), NULL, NULL);
3025     CoTaskMemFree(pszClsid);
3026     strcat(buffer, "\\InprocHandler32");
3027     if (Register)
3028     {
3029         error = RegCreateKeyExA(HKEY_CLASSES_ROOT, buffer, 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey, &dwDisposition);
3030         if (error == ERROR_ACCESS_DENIED)
3031         {
3032             skip("Not authorized to modify the Classes key\n");
3033             return E_FAIL;
3034         }
3035         ok(error == ERROR_SUCCESS, "RegCreateKeyEx failed with error %d\n", error);
3036         if (error != ERROR_SUCCESS) hr = E_FAIL;
3037         error = RegSetValueExA(hkey, NULL, 0, REG_SZ, (const unsigned char *)"\"ole32.dll\"", strlen("\"ole32.dll\"") + 1);
3038         ok(error == ERROR_SUCCESS, "RegSetValueEx failed with error %d\n", error);
3039         if (error != ERROR_SUCCESS) hr = E_FAIL;
3040         RegCloseKey(hkey);
3041     }
3042     else
3043     {
3044         RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
3045         *strrchr(buffer, '\\') = '\0';
3046         RegDeleteKeyA(HKEY_CLASSES_ROOT, buffer);
3047     }
3048     return hr;
3049 }
3050 
3051 static void test_inproc_handler(void)
3052 {
3053     HRESULT hr;
3054     IUnknown *pObject;
3055     IUnknown *pObject2;
3056 
3057     if (FAILED(reg_unreg_wine_test_class(TRUE)))
3058         return;
3059 
3060     hr = CoCreateInstance(&CLSID_WineTest, NULL, CLSCTX_INPROC_HANDLER, &IID_IUnknown, (void **)&pObject);
3061     ok_ole_success(hr, "CoCreateInstance");
3062 
3063     if (SUCCEEDED(hr))
3064     {
3065         hr = IUnknown_QueryInterface(pObject, &IID_IWineTest, (void **)&pObject2);
3066         ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface on handler for invalid interface returned 0x%08x instead of E_NOINTERFACE\n", hr);
3067 
3068         /* it's a handler as it supports IOleObject */
3069         hr = IUnknown_QueryInterface(pObject, &IID_IOleObject, (void **)&pObject2);
3070         ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
3071         IUnknown_Release(pObject2);
3072 
3073         IUnknown_Release(pObject);
3074     }
3075 
3076     reg_unreg_wine_test_class(FALSE);
3077 }
3078 
3079 static HRESULT WINAPI Test_SMI_QueryInterface(
3080     IStdMarshalInfo *iface,
3081     REFIID riid,
3082     LPVOID *ppvObj)
3083 {
3084     if (ppvObj == NULL) return E_POINTER;
3085 
3086     if (IsEqualGUID(riid, &IID_IUnknown) ||
3087         IsEqualGUID(riid, &IID_IStdMarshalInfo))
3088     {
3089         *ppvObj = iface;
3090         IStdMarshalInfo_AddRef(iface);
3091         return S_OK;
3092     }
3093 
3094     return E_NOINTERFACE;
3095 }
3096 
3097 static ULONG WINAPI Test_SMI_AddRef(IStdMarshalInfo *iface)
3098 {
3099     LockModule();
3100     return 2; /* non-heap-based object */
3101 }
3102 
3103 static ULONG WINAPI Test_SMI_Release(IStdMarshalInfo *iface)
3104 {
3105     UnlockModule();
3106     return 1; /* non-heap-based object */
3107 }
3108 
3109 static HRESULT WINAPI Test_SMI_GetClassForHandler(
3110     IStdMarshalInfo *iface,
3111     DWORD dwDestContext,
3112     void *pvDestContext,
3113     CLSID *pClsid)
3114 {
3115     *pClsid = CLSID_WineTest;
3116     return S_OK;
3117 }
3118 
3119 static const IStdMarshalInfoVtbl Test_SMI_Vtbl =
3120 {
3121     Test_SMI_QueryInterface,
3122     Test_SMI_AddRef,
3123     Test_SMI_Release,
3124     Test_SMI_GetClassForHandler
3125 };
3126 
3127 static IStdMarshalInfo Test_SMI = {&Test_SMI_Vtbl};
3128 
3129 static void test_handler_marshaling(void)
3130 {
3131     HRESULT hr;
3132     IStream *pStream = NULL;
3133     IUnknown *pProxy = NULL;
3134     IUnknown *pObject;
3135     DWORD tid;
3136     HANDLE thread;
3137     static const LARGE_INTEGER ullZero;
3138 
3139     if (FAILED(reg_unreg_wine_test_class(TRUE)))
3140         return;
3141     cLocks = 0;
3142 
3143     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3144     ok_ole_success(hr, "CreateStreamOnHGlobal");
3145     tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_SMI, MSHLFLAGS_NORMAL, &thread);
3146 
3147     ok_more_than_one_lock();
3148 
3149     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3150     hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
3151     ok_ole_success(hr, "CoUnmarshalInterface");
3152     IStream_Release(pStream);
3153 
3154     if(hr == S_OK)
3155     {
3156         ok_more_than_one_lock();
3157 
3158         hr = IUnknown_QueryInterface(pProxy, &IID_IWineTest, (void **)&pObject);
3159         ok(hr == E_NOINTERFACE, "IUnknown_QueryInterface with unknown IID should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3160 
3161         /* it's a handler as it supports IOleObject */
3162         hr = IUnknown_QueryInterface(pProxy, &IID_IOleObject, (void **)&pObject);
3163         todo_wine
3164         ok_ole_success(hr, "IUnknown_QueryInterface(&IID_IOleObject)");
3165         if (SUCCEEDED(hr)) IUnknown_Release(pObject);
3166 
3167         IUnknown_Release(pProxy);
3168 
3169         ok_no_locks();
3170     }
3171 
3172     end_host_object(tid, thread);
3173     reg_unreg_wine_test_class(FALSE);
3174 
3175     /* FIXME: test IPersist interface has the same effect as IStdMarshalInfo */
3176 }
3177 
3178 
3179 static void test_client_security(void)
3180 {
3181     HRESULT hr;
3182     IStream *pStream = NULL;
3183     IClassFactory *pProxy = NULL;
3184     IUnknown *pProxy2 = NULL;
3185     IUnknown *pUnknown1 = NULL;
3186     IUnknown *pUnknown2 = NULL;
3187     IClientSecurity *pCliSec = NULL;
3188     IMarshal *pMarshal;
3189     DWORD tid;
3190     HANDLE thread;
3191     static const LARGE_INTEGER ullZero;
3192     DWORD dwAuthnSvc;
3193     DWORD dwAuthzSvc;
3194     OLECHAR *pServerPrincName;
3195     DWORD dwAuthnLevel;
3196     DWORD dwImpLevel;
3197     void *pAuthInfo;
3198     DWORD dwCapabilities;
3199     void *pv;
3200 
3201     cLocks = 0;
3202 
3203     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
3204     ok_ole_success(hr, "CreateStreamOnHGlobal");
3205     tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
3206 
3207     IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
3208     hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
3209     ok_ole_success(hr, "CoUnmarshalInterface");
3210     IStream_Release(pStream);
3211 
3212     hr = IClassFactory_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pUnknown1);
3213     ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
3214 
3215     hr = IClassFactory_QueryInterface(pProxy, &IID_IRemUnknown, (LPVOID*)&pProxy2);
3216     ok_ole_success(hr, "IUnknown_QueryInterface IID_IStream");
3217 
3218     hr = IUnknown_QueryInterface(pProxy2, &IID_IUnknown, (LPVOID*)&pUnknown2);
3219     ok_ole_success(hr, "IUnknown_QueryInterface IID_IUnknown");
3220 
3221     ok(pUnknown1 == pUnknown2, "both proxy's IUnknowns should be the same - %p, %p\n", pUnknown1, pUnknown2);
3222 
3223     hr = IClassFactory_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pMarshal);
3224     ok_ole_success(hr, "IUnknown_QueryInterface IID_IMarshal");
3225 
3226     hr = IClassFactory_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pCliSec);
3227     ok_ole_success(hr, "IUnknown_QueryInterface IID_IClientSecurity");
3228 
3229     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3230     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket (all NULLs)");
3231 
3232     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pMarshal, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
3233     todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_QueryBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3234 
3235     hr = IClientSecurity_QueryBlanket(pCliSec, (IUnknown *)pProxy, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
3236     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket");
3237 
3238     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, RPC_C_IMP_LEVEL_IMPERSONATE, pAuthInfo, dwCapabilities);
3239     todo_wine ok_ole_success(hr, "IClientSecurity_SetBlanket");
3240 
3241     hr = IClassFactory_CreateInstance(pProxy, NULL, &IID_IWineTest, &pv);
3242     ok(hr == E_NOINTERFACE, "COM call should have succeeded instead of returning 0x%08x\n", hr);
3243 
3244     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pMarshal, dwAuthnSvc, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
3245     todo_wine ok(hr == E_NOINTERFACE, "IClientSecurity_SetBlanket with local interface should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
3246 
3247     hr = IClientSecurity_SetBlanket(pCliSec, (IUnknown *)pProxy, 0xdeadbeef, dwAuthzSvc, pServerPrincName, dwAuthnLevel, dwImpLevel, pAuthInfo, dwCapabilities);
3248     todo_wine ok(hr == E_INVALIDARG, "IClientSecurity_SetBlanke with invalid dwAuthnSvc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
3249 
3250     CoTaskMemFree(pServerPrincName);
3251 
3252     hr = IClientSecurity_QueryBlanket(pCliSec, pUnknown1, &dwAuthnSvc, &dwAuthzSvc, &pServerPrincName, &dwAuthnLevel, &dwImpLevel, &pAuthInfo, &dwCapabilities);
3253     todo_wine ok_ole_success(hr, "IClientSecurity_QueryBlanket(IUnknown)");
3254 
3255     CoTaskMemFree(pServerPrincName);
3256 
3257     IClassFactory_Release(pProxy);
3258     IUnknown_Release(pProxy2);
3259     IUnknown_Release(pUnknown1);
3260     IUnknown_Release(pUnknown2);
3261     IMarshal_Release(pMarshal);
3262     IClientSecurity_Release(pCliSec);
3263 
3264     end_host_object(tid, thread);
3265 }
3266 
3267 static HANDLE heventShutdown;
3268 
3269 static void LockModuleOOP(void)
3270 {
3271     InterlockedIncrement(&cLocks); /* for test purposes only */
3272     CoAddRefServerProcess();
3273 }
3274 
3275 static void UnlockModuleOOP(void)
3276 {
3277     InterlockedDecrement(&cLocks); /* for test purposes only */
3278     if (!CoReleaseServerProcess())
3279         SetEvent(heventShutdown);
3280 }
3281 
3282 static HWND hwnd_app;
3283 
3284 struct local_server
3285 {
3286     IPersist IPersist_iface; /* a nice short interface */
3287 };
3288 
3289 static HRESULT WINAPI local_server_QueryInterface(IPersist *iface, REFIID iid, void **obj)
3290 {
3291     *obj = NULL;
3292 
3293     if (IsEqualGUID(iid, &IID_IUnknown) ||
3294         IsEqualGUID(iid, &IID_IPersist))
3295         *obj = iface;
3296 
3297     if (*obj)
3298     {
3299         IPersist_AddRef(iface);
3300         return S_OK;
3301     }
3302     return E_NOINTERFACE;
3303 }
3304 
3305 static ULONG WINAPI local_server_AddRef(IPersist *iface)
3306 {
3307     return 2;
3308 }
3309 
3310 static ULONG WINAPI local_server_Release(IPersist *iface)
3311 {
3312     return 1;
3313 }
3314 
3315 static HRESULT WINAPI local_server_GetClassID(IPersist *iface, CLSID *clsid)
3316 {
3317     HRESULT hr;
3318 
3319     *clsid = IID_IUnknown;
3320 
3321     /* Test calling CoDisconnectObject within a COM call */
3322     hr = CoDisconnectObject((IUnknown *)iface, 0);
3323     ok(hr == S_OK, "got %08x\n", hr);
3324 
3325     /* Initialize and uninitialize the apartment to show that we
3326      * remain in the autojoined mta */
3327     hr = pCoInitializeEx( NULL, COINIT_MULTITHREADED );
3328     ok( hr == S_FALSE, "got %08x\n", hr );
3329     CoUninitialize();
3330 
3331     return S_OK;
3332 }
3333 
3334 static const IPersistVtbl local_server_persist_vtbl =
3335 {
3336     local_server_QueryInterface,
3337     local_server_AddRef,
3338     local_server_Release,
3339     local_server_GetClassID
3340 };
3341 
3342 struct local_server local_server_class =
3343 {
3344     {&local_server_persist_vtbl}
3345 };
3346 
3347 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
3348     LPCLASSFACTORY iface,
3349     REFIID riid,
3350     LPVOID *ppvObj)
3351 {
3352     if (ppvObj == NULL) return E_POINTER;
3353 
3354     if (IsEqualGUID(riid, &IID_IUnknown) ||
3355         IsEqualGUID(riid, &IID_IClassFactory))
3356     {
3357         *ppvObj = iface;
3358         IClassFactory_AddRef(iface);
3359         return S_OK;
3360     }
3361 
3362     return E_NOINTERFACE;
3363 }
3364 
3365 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
3366 {
3367     return 2; /* non-heap-based object */
3368 }
3369 
3370 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
3371 {
3372     return 1; /* non-heap-based object */
3373 }
3374 
3375 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
3376     LPCLASSFACTORY iface,
3377     LPUNKNOWN pUnkOuter,
3378     REFIID riid,
3379     LPVOID *ppvObj)
3380 {
3381     IPersist *persist = &local_server_class.IPersist_iface;
3382     HRESULT hr;
3383     IPersist_AddRef( persist );
3384     hr = IPersist_QueryInterface( persist, riid, ppvObj );
3385     IPersist_Release( persist );
3386     return hr;
3387 }
3388 
3389 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
3390     LPCLASSFACTORY iface,
3391     BOOL fLock)
3392 {
3393     if (fLock)
3394         LockModuleOOP();
3395     else
3396         UnlockModuleOOP();
3397     return S_OK;
3398 }
3399 
3400 static const IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
3401 {
3402     TestOOP_IClassFactory_QueryInterface,
3403     TestOOP_IClassFactory_AddRef,
3404     TestOOP_IClassFactory_Release,
3405     TestOOP_IClassFactory_CreateInstance,
3406     TestOOP_IClassFactory_LockServer
3407 };
3408 
3409 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
3410 
3411 static void test_register_local_server(void)
3412 {
3413     DWORD cookie;
3414     HRESULT hr;
3415     HANDLE ready_event;
3416     DWORD wait;
3417     HANDLE handles[2];
3418 
3419     heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
3420     ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
3421     handles[0] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
3422     handles[1] = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event");
3423 
3424 again:
3425     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
3426                                CLSCTX_LOCAL_SERVER, REGCLS_SINGLEUSE, &cookie);
3427     ok_ole_success(hr, CoRegisterClassObject);
3428 
3429     SetEvent(ready_event);
3430 
3431     do
3432     {
3433         wait = MsgWaitForMultipleObjects(2, handles, FALSE, 30000, QS_ALLINPUT);
3434         if (wait == WAIT_OBJECT_0+2)
3435         {
3436             MSG msg;
3437 
3438             if (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
3439             {
3440                 trace("Message 0x%x\n", msg.message);
3441                 TranslateMessage(&msg);
3442                 DispatchMessageA(&msg);
3443             }
3444         }
3445         else if (wait == WAIT_OBJECT_0+1)
3446         {
3447             hr = CoRevokeClassObject(cookie);
3448             ok_ole_success(hr, CoRevokeClassObject);
3449             goto again;
3450         }
3451     }
3452     while (wait == WAIT_OBJECT_0+2);
3453 
3454     ok( wait == WAIT_OBJECT_0, "quit event wait timed out\n" );
3455     hr = CoRevokeClassObject(cookie);
3456     ok_ole_success(hr, CoRevokeClassObject);
3457     CloseHandle(handles[0]);
3458     CloseHandle(handles[1]);
3459 }
3460 
3461 static HANDLE create_target_process(const char *arg)
3462 {
3463     char **argv;
3464     char cmdline[MAX_PATH];
3465     BOOL ret;
3466     PROCESS_INFORMATION pi;
3467     STARTUPINFOA si = { 0 };
3468     si.cb = sizeof(si);
3469 
3470     pi.hThread = NULL;
3471     pi.hProcess = NULL;
3472     winetest_get_mainargs( &argv );
3473     sprintf(cmdline, "\"%s\" %s %s", argv[0], argv[1], arg);
3474     ret = CreateProcessA(argv[0], cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
3475     ok(ret, "CreateProcess failed with error: %u\n", GetLastError());
3476     if (pi.hThread) CloseHandle(pi.hThread);
3477     return pi.hProcess;
3478 }
3479 
3480 /* tests functions commonly used by out of process COM servers */
3481 static void test_local_server(void)
3482 {
3483     DWORD cookie;
3484     HRESULT hr;
3485     IClassFactory * cf;
3486     IPersist *persist;
3487     DWORD ret;
3488     HANDLE process;
3489     HANDLE quit_event;
3490     HANDLE ready_event;
3491     HANDLE repeat_event;
3492     CLSID clsid;
3493 
3494     heventShutdown = CreateEventA(NULL, TRUE, FALSE, NULL);
3495 
3496     cLocks = 0;
3497 
3498     /* Start the object suspended */
3499     hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
3500         CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
3501     ok_ole_success(hr, CoRegisterClassObject);
3502 
3503     /* ... and CoGetClassObject does not find it and fails when it looks for the
3504      * class in the registry */
3505     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
3506         NULL, &IID_IClassFactory, (LPVOID*)&cf);
3507     ok(hr == REGDB_E_CLASSNOTREG || /* NT */
3508        hr == S_OK /* Win9x */,
3509         "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
3510 
3511     /* Resume the object suspended above ... */
3512     hr = CoResumeClassObjects();
3513     ok_ole_success(hr, CoResumeClassObjects);
3514 
3515     /* ... and now it should succeed */
3516     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
3517         NULL, &IID_IClassFactory, (LPVOID*)&cf);
3518     ok_ole_success(hr, CoGetClassObject);
3519 
3520     /* Now check the locking is working */
3521     /* NOTE: we are accessing the class directly, not through a proxy */
3522 
3523     ok_no_locks();
3524 
3525     hr = IClassFactory_LockServer(cf, TRUE);
3526     ok_ole_success(hr, IClassFactory_LockServer);
3527 
3528     ok_more_than_one_lock();
3529 
3530     IClassFactory_LockServer(cf, FALSE);
3531     ok_ole_success(hr, IClassFactory_LockServer);
3532 
3533     ok_no_locks();
3534 
3535     IClassFactory_Release(cf);
3536 
3537     /* wait for shutdown signal */
3538     ret = WaitForSingleObject(heventShutdown, 0);
3539     ok(ret != WAIT_TIMEOUT, "Server didn't shut down\n");
3540 
3541     /* try to connect again after SCM has suspended registered class objects */
3542     hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
3543         &IID_IClassFactory, (LPVOID*)&cf);
3544     ok(hr == CO_E_SERVER_STOPPING || /* NT */
3545        hr == REGDB_E_CLASSNOTREG || /* win2k */
3546        hr == S_OK /* Win9x */,
3547         "CoGetClassObject should have returned CO_E_SERVER_STOPPING or REGDB_E_CLASSNOTREG instead of 0x%08x\n", hr);
3548 
3549     hr = CoRevokeClassObject(cookie);
3550     ok_ole_success(hr, CoRevokeClassObject);
3551 
3552     CloseHandle(heventShutdown);
3553 
3554     process = create_target_process("-Embedding");
3555     ok(process != NULL, "couldn't start local server process, error was %d\n", GetLastError());
3556 
3557     ready_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Ready Event");
3558     ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
3559 
3560     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3561     ok_ole_success(hr, CoCreateInstance);
3562 
3563     IPersist_Release(persist);
3564 
3565     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3566     ok(hr == REGDB_E_CLASSNOTREG, "Second CoCreateInstance on REGCLS_SINGLEUSE object should have failed\n");
3567 
3568     /* Re-register the class and try calling CoDisconnectObject from within a call to that object */
3569     repeat_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Repeat Event");
3570     SetEvent(repeat_event);
3571     CloseHandle(repeat_event);
3572 
3573     ok( !WaitForSingleObject(ready_event, 10000), "wait timed out\n" );
3574     CloseHandle(ready_event);
3575 
3576     hr = CoCreateInstance(&CLSID_WineOOPTest, NULL, CLSCTX_LOCAL_SERVER, &IID_IPersist, (void **)&persist);
3577     ok_ole_success(hr, CoCreateInstance);
3578 
3579     /* GetClassID will call CoDisconnectObject */
3580     IPersist_GetClassID(persist, &clsid);
3581     IPersist_Release(persist);
3582 
3583     quit_event = CreateEventA(NULL, FALSE, FALSE, "Wine COM Test Quit Event");
3584     SetEvent(quit_event);
3585 
3586     winetest_wait_child_process( process );
3587     CloseHandle(quit_event);
3588     CloseHandle(process);
3589 }
3590 
3591 struct git_params
3592 {
3593 	DWORD cookie;
3594 	IGlobalInterfaceTable *git;
3595 };
3596 
3597 static DWORD CALLBACK get_global_interface_proc(LPVOID pv)
3598 {
3599 	HRESULT hr;
3600 	struct git_params *params = pv;
3601 	IClassFactory *cf;
3602 
3603 	hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
3604 	ok(hr == CO_E_NOTINITIALIZED ||
3605 		broken(hr == E_UNEXPECTED) /* win2k */ ||
3606 		broken(hr == S_OK) /* NT 4 */,
3607 		"IGlobalInterfaceTable_GetInterfaceFromGlobal should have failed with error CO_E_NOTINITIALIZED or E_UNEXPECTED instead of 0x%08x\n",
3608 		hr);
3609 	if (hr == S_OK)
3610 		IClassFactory_Release(cf);
3611 
3612 	CoInitialize(NULL);
3613 
3614 	hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(params->git, params->cookie, &IID_IClassFactory, (void **)&cf);
3615 	ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
3616 
3617 	IClassFactory_Release(cf);
3618 
3619 	CoUninitialize();
3620 
3621 	return hr;
3622 }
3623 
3624 static void test_globalinterfacetable(void)
3625 {
3626 	HRESULT hr;
3627 	IGlobalInterfaceTable *git;
3628 	DWORD cookie;
3629 	HANDLE thread;
3630 	DWORD tid;
3631 	struct git_params params;
3632 	DWORD ret;
3633         IUnknown *object;
3634         IClassFactory *cf;
3635         ULONG ref;
3636 
3637         trace("test_globalinterfacetable\n");
3638 	cLocks = 0;
3639 
3640 	hr = pDllGetClassObject(&CLSID_StdGlobalInterfaceTable, &IID_IClassFactory, (void**)&cf);
3641 	ok(hr == S_OK, "got 0x%08x\n", hr);
3642 
3643 	hr = IClassFactory_QueryInterface(cf, &IID_IGlobalInterfaceTable, (void**)&object);
3644 	ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
3645 
3646 	IClassFactory_Release(cf);
3647 
3648 	hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)&git);
3649 	ok_ole_success(hr, CoCreateInstance);
3650 
3651 	ref = IGlobalInterfaceTable_AddRef(git);
3652 	ok(ref == 1, "ref=%d\n", ref);
3653 	ref = IGlobalInterfaceTable_AddRef(git);
3654 	ok(ref == 1, "ref=%d\n", ref);
3655 
3656 	ref = IGlobalInterfaceTable_Release(git);
3657 	ok(ref == 1, "ref=%d\n", ref);
3658 	ref = IGlobalInterfaceTable_Release(git);
3659 	ok(ref == 1, "ref=%d\n", ref);
3660 
3661 	hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&Test_ClassFactory, &IID_IClassFactory, &cookie);
3662 	ok_ole_success(hr, IGlobalInterfaceTable_RegisterInterfaceInGlobal);
3663 
3664 	ok_more_than_one_lock();
3665 
3666 	params.cookie = cookie;
3667 	params.git = git;
3668 	/* note: params is on stack so we MUST wait for get_global_interface_proc
3669 	 * to exit before we can return */
3670 	thread = CreateThread(NULL, 0, get_global_interface_proc, &params, 0, &tid);
3671 
3672 	ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
3673 	while (ret == WAIT_OBJECT_0 + 1)
3674 	{
3675 		MSG msg;
3676 		while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
3677 			DispatchMessageA(&msg);
3678 		ret = MsgWaitForMultipleObjects(1, &thread, FALSE, 10000, QS_ALLINPUT);
3679 	}
3680 
3681 	CloseHandle(thread);
3682 
3683 	/* test getting interface from global with different iid */
3684 	hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, cookie, &IID_IUnknown, (void **)&object);
3685 	ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
3686 	IUnknown_Release(object);
3687 
3688 	/* test getting interface from global with same iid */
3689 	hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, cookie, &IID_IClassFactory, (void **)&object);
3690 	ok_ole_success(hr, IGlobalInterfaceTable_GetInterfaceFromGlobal);
3691 	IUnknown_Release(object);
3692 
3693 	hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, cookie);
3694 	ok_ole_success(hr, IGlobalInterfaceTable_RevokeInterfaceFromGlobal);
3695 
3696 	ok_no_locks();
3697 
3698 	IGlobalInterfaceTable_Release(git);
3699 }
3700 
3701 static void test_manualresetevent(void)
3702 {
3703     ISynchronizeHandle *sync_handle;
3704     ISynchronize *psync1, *psync2;
3705     IUnknown *punk;
3706     HANDLE handle;
3707     LONG ref;
3708     HRESULT hr;
3709 
3710     hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&punk);
3711     ok(hr == S_OK, "Got 0x%08x\n", hr);
3712     ok(!!punk, "Got NULL.\n");
3713     IUnknown_Release(punk);
3714 
3715     hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_ISynchronize, (void**)&psync1);
3716     ok(hr == S_OK, "Got 0x%08x\n", hr);
3717     ok(!!psync1, "Got NULL.\n");
3718 
3719     hr = ISynchronize_Wait(psync1, 0, 5);
3720     ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
3721 
3722     hr = ISynchronize_Reset(psync1);
3723     ok(hr == S_OK, "Got 0x%08x\n", hr);
3724     hr = ISynchronize_Signal(psync1);
3725     ok(hr == S_OK, "Got 0x%08x\n", hr);
3726     hr = ISynchronize_Wait(psync1, 0, 5);
3727     ok(hr == S_OK, "Got 0x%08x\n", hr);
3728     hr = ISynchronize_Wait(psync1, 0, 5);
3729     ok(hr == S_OK, "Got 0x%08x\n", hr);
3730     hr = ISynchronize_Reset(psync1);
3731     ok(hr == S_OK, "Got 0x%08x\n", hr);
3732     hr = ISynchronize_Wait(psync1, 0, 5);
3733     ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
3734 
3735     hr = CoCreateInstance(&CLSID_ManualResetEvent, NULL, CLSCTX_INPROC_SERVER, &IID_ISynchronize, (void**)&psync2);
3736     ok(hr == S_OK, "Got 0x%08x\n", hr);
3737     ok(!!psync2, "Got NULL.\n");
3738     ok(psync1 != psync2, "psync1 == psync2.\n");
3739 
3740     hr = ISynchronize_QueryInterface(psync2, &IID_ISynchronizeHandle, (void**)&sync_handle);
3741     ok(hr == S_OK, "QueryInterface(IID_ISynchronizeHandle) failed: %08x\n", hr);
3742 
3743     handle = NULL;
3744     hr = ISynchronizeHandle_GetHandle(sync_handle, &handle);
3745     ok(hr == S_OK, "GetHandle failed: %08x\n", hr);
3746     ok(handle != NULL && handle != INVALID_HANDLE_VALUE, "handle = %p\n", handle);
3747 
3748     ISynchronizeHandle_Release(sync_handle);
3749 
3750     hr = ISynchronize_Wait(psync2, 0, 5);
3751     ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
3752 
3753     hr = ISynchronize_Reset(psync1);
3754     ok(hr == S_OK, "Got 0x%08x\n", hr);
3755     hr = ISynchronize_Reset(psync2);
3756     ok(hr == S_OK, "Got 0x%08x\n", hr);
3757     hr = ISynchronize_Signal(psync1);
3758     ok(hr == S_OK, "Got 0x%08x\n", hr);
3759     hr = ISynchronize_Wait(psync2, 0, 5);
3760     ok(hr == RPC_S_CALLPENDING, "Got 0x%08x\n", hr);
3761 
3762     ref = ISynchronize_AddRef(psync1);
3763     ok(ref == 2, "Got ref: %d\n", ref);
3764     ref = ISynchronize_AddRef(psync1);
3765     ok(ref == 3, "Got ref: %d\n", ref);
3766     ref = ISynchronize_Release(psync1);
3767     ok(ref == 2, "Got nonzero ref: %d\n", ref);
3768     ref = ISynchronize_Release(psync2);
3769     ok(!ref, "Got nonzero ref: %d\n", ref);
3770     ref = ISynchronize_Release(psync1);
3771     ok(ref == 1, "Got nonzero ref: %d\n", ref);
3772     ref = ISynchronize_Release(psync1);
3773     ok(!ref, "Got nonzero ref: %d\n", ref);
3774 }
3775 
3776 static DWORD CALLBACK implicit_mta_unmarshal_proc(void *param)
3777 {
3778     IStream *stream = param;
3779     IClassFactory *cf;
3780     IUnknown *proxy;
3781     HRESULT hr;
3782 
3783     IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
3784     hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
3785     ok_ole_success(hr, CoUnmarshalInterface);
3786 
3787     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
3788     ok_ole_success(hr, IClassFactory_CreateInstance);
3789 
3790     IUnknown_Release(proxy);
3791 
3792     /* But if we initialize an STA in this apartment, it becomes the wrong one. */
3793     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
3794 
3795     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
3796     ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
3797 
3798     CoUninitialize();
3799 
3800     ok_more_than_one_lock();
3801     ok_non_zero_external_conn();
3802 
3803     IClassFactory_Release(cf);
3804 
3805     ok_no_locks();
3806     ok_zero_external_conn();
3807     ok_last_release_closes(TRUE);
3808     return 0;
3809 }
3810 
3811 static DWORD CALLBACK implicit_mta_use_proc(void *param)
3812 {
3813     IClassFactory *cf = param;
3814     IUnknown *proxy;
3815     HRESULT hr;
3816 
3817     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
3818     ok_ole_success(hr, IClassFactory_CreateInstance);
3819 
3820     IUnknown_Release(proxy);
3821 
3822     /* But if we initialize an STA in this apartment, it becomes the wrong one. */
3823     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
3824 
3825     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
3826     ok(hr == RPC_E_WRONG_THREAD, "got %#x\n", hr);
3827 
3828     CoUninitialize();
3829     return 0;
3830 }
3831 
3832 struct implicit_mta_marshal_data
3833 {
3834     IStream *stream;
3835     HANDLE start;
3836     HANDLE stop;
3837 };
3838 
3839 static DWORD CALLBACK implicit_mta_marshal_proc(void *param)
3840 {
3841     struct implicit_mta_marshal_data *data = param;
3842     HRESULT hr;
3843 
3844     hr = CoMarshalInterface(data->stream, &IID_IClassFactory,
3845         (IUnknown *)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3846     ok_ole_success(hr, CoMarshalInterface);
3847 
3848     SetEvent(data->start);
3849 
3850     ok(!WaitForSingleObject(data->stop, 1000), "wait failed\n");
3851     return 0;
3852 }
3853 
3854 static void test_implicit_mta(void)
3855 {
3856     struct implicit_mta_marshal_data data;
3857     HANDLE host_thread, thread;
3858     IClassFactory *cf;
3859     IUnknown *proxy;
3860     IStream *stream;
3861     HRESULT hr;
3862     DWORD tid;
3863 
3864     cLocks = 0;
3865     external_connections = 0;
3866 
3867     CoInitializeEx(NULL, COINIT_MULTITHREADED);
3868 
3869     /* Firstly: we can unmarshal and use an object while in the implicit MTA. */
3870     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3871     ok_ole_success(hr, CreateStreamOnHGlobal);
3872     tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
3873 
3874     ok_more_than_one_lock();
3875     ok_non_zero_external_conn();
3876 
3877     thread = CreateThread(NULL, 0, implicit_mta_unmarshal_proc, stream, 0, NULL);
3878     ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
3879     CloseHandle(thread);
3880 
3881     IStream_Release(stream);
3882     end_host_object(tid, host_thread);
3883 
3884     /* Secondly: we can unmarshal an object into the real MTA and then use it
3885      * from the implicit MTA. */
3886     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3887     ok_ole_success(hr, CreateStreamOnHGlobal);
3888     tid = start_host_object(stream, &IID_IClassFactory, (IUnknown *)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
3889 
3890     ok_more_than_one_lock();
3891     ok_non_zero_external_conn();
3892 
3893     IStream_Seek(stream, ullZero, STREAM_SEEK_SET, NULL);
3894     hr = CoUnmarshalInterface(stream, &IID_IClassFactory, (void **)&cf);
3895     ok_ole_success(hr, CoUnmarshalInterface);
3896 
3897     thread = CreateThread(NULL, 0, implicit_mta_use_proc, cf, 0, NULL);
3898     ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
3899     CloseHandle(thread);
3900 
3901     IClassFactory_Release(cf);
3902     IStream_Release(stream);
3903 
3904     ok_no_locks();
3905     ok_non_zero_external_conn();
3906     ok_last_release_closes(TRUE);
3907 
3908     end_host_object(tid, host_thread);
3909 
3910     /* Thirdly: we can marshal an object from the implicit MTA and then
3911      * unmarshal it into the real one. */
3912     data.start = CreateEventA(NULL, FALSE, FALSE, NULL);
3913     data.stop  = CreateEventA(NULL, FALSE, FALSE, NULL);
3914 
3915     hr = CreateStreamOnHGlobal(NULL, TRUE, &data.stream);
3916     ok_ole_success(hr, CreateStreamOnHGlobal);
3917 
3918     thread = CreateThread(NULL, 0, implicit_mta_marshal_proc, &data, 0, NULL);
3919     ok(!WaitForSingleObject(data.start, 1000), "wait failed\n");
3920 
3921     IStream_Seek(data.stream, ullZero, STREAM_SEEK_SET, NULL);
3922     hr = CoUnmarshalInterface(data.stream, &IID_IClassFactory, (void **)&cf);
3923     ok_ole_success(hr, CoUnmarshalInterface);
3924 
3925     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void **)&proxy);
3926     ok_ole_success(hr, IClassFactory_CreateInstance);
3927 
3928     IUnknown_Release(proxy);
3929 
3930     SetEvent(data.stop);
3931     ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
3932     CloseHandle(thread);
3933 
3934     IStream_Release(data.stream);
3935 
3936     CoUninitialize();
3937 }
3938 
3939 static const char *debugstr_iid(REFIID riid)
3940 {
3941     static char name[256];
3942     HKEY hkeyInterface;
3943     WCHAR bufferW[39];
3944     char buffer[39];
3945     LONG name_size = sizeof(name);
3946     StringFromGUID2(riid, bufferW, sizeof(bufferW)/sizeof(bufferW[0]));
3947     WideCharToMultiByte(CP_ACP, 0, bufferW, sizeof(bufferW)/sizeof(bufferW[0]), buffer, sizeof(buffer), NULL, NULL);
3948     if (RegOpenKeyExA(HKEY_CLASSES_ROOT, "Interface", 0, KEY_QUERY_VALUE, &hkeyInterface) != ERROR_SUCCESS)
3949     {
3950         memcpy(name, buffer, sizeof(buffer));
3951         goto done;
3952     }
3953     if (RegQueryValueA(hkeyInterface, buffer, name, &name_size) != ERROR_SUCCESS)
3954     {
3955         memcpy(name, buffer, sizeof(buffer));
3956         goto done;
3957     }
3958     RegCloseKey(hkeyInterface);
3959 done:
3960     return name;
3961 }
3962 
3963 static HRESULT WINAPI TestChannelHook_QueryInterface(IChannelHook *iface, REFIID riid, void **ppv)
3964 {
3965     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IChannelHook))
3966     {
3967         *ppv = iface;
3968         IChannelHook_AddRef(iface);
3969         return S_OK;
3970     }
3971 
3972     *ppv = NULL;
3973     return E_NOINTERFACE;
3974 }
3975 
3976 static ULONG WINAPI TestChannelHook_AddRef(IChannelHook *iface)
3977 {
3978     return 2;
3979 }
3980 
3981 static ULONG WINAPI TestChannelHook_Release(IChannelHook *iface)
3982 {
3983     return 1;
3984 }
3985 
3986 static BOOL new_hook_struct;
3987 static int method, server_tid;
3988 static GUID causality;
3989 
3990 struct new_hook_info
3991 {
3992     IID iid;
3993     GUID causality;
3994     DWORD server_pid;
3995     DWORD server_tid;
3996     WORD method;
3997 };
3998 
3999 static void WINAPI TestChannelHook_ClientGetSize(
4000     IChannelHook *iface,
4001     REFGUID uExtent,
4002     REFIID  riid,
4003     ULONG  *pDataSize )
4004 {
4005     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4006     trace("TestChannelHook_ClientGetSize\n");
4007     trace("\t%s\n", debugstr_iid(riid));
4008     if (info->cbSize != sizeof(*info))
4009         new_hook_struct = TRUE;
4010 
4011     if (!new_hook_struct)
4012     {
4013         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4014         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4015         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4016         ok(!info->pObject, "pObject should be NULL\n");
4017         if (method == 3)
4018             causality = info->uCausality;
4019         else
4020             ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4021     }
4022     else
4023     {
4024         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4025         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4026            GetCurrentProcessId());
4027         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4028            server_tid);
4029         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4030         if (method == 3)
4031             causality = new_info->causality;
4032         else
4033             ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4034     }
4035 
4036     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4037 
4038     *pDataSize = 1;
4039 }
4040 
4041 static void WINAPI TestChannelHook_ClientFillBuffer(
4042     IChannelHook *iface,
4043     REFGUID uExtent,
4044     REFIID  riid,
4045     ULONG  *pDataSize,
4046     void   *pDataBuffer )
4047 {
4048     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4049     trace("TestChannelHook_ClientFillBuffer\n");
4050 
4051     if (!new_hook_struct)
4052     {
4053         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4054         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4055         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4056         ok(!info->pObject, "pObject should be NULL\n");
4057         ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4058     }
4059     else
4060     {
4061         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4062         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4063            GetCurrentProcessId());
4064         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4065            server_tid);
4066         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4067         ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4068     }
4069 
4070     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4071 
4072     *(unsigned char *)pDataBuffer = 0xcc;
4073     *pDataSize = 1;
4074 }
4075 
4076 static void WINAPI TestChannelHook_ClientNotify(
4077     IChannelHook *iface,
4078     REFGUID uExtent,
4079     REFIID  riid,
4080     ULONG   cbDataSize,
4081     void   *pDataBuffer,
4082     DWORD   lDataRep,
4083     HRESULT hrFault )
4084 {
4085     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4086     trace("TestChannelHook_ClientNotify hrFault = 0x%08x\n", hrFault);
4087 
4088     if (!new_hook_struct)
4089     {
4090         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4091         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4092         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4093         todo_wine {
4094             ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4095         }
4096         ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4097     }
4098     else
4099     {
4100         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4101         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4102            GetCurrentProcessId());
4103         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4104            server_tid);
4105         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4106         ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4107     }
4108 
4109     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4110 }
4111 
4112 static void WINAPI TestChannelHook_ServerNotify(
4113     IChannelHook *iface,
4114     REFGUID uExtent,
4115     REFIID  riid,
4116     ULONG   cbDataSize,
4117     void   *pDataBuffer,
4118     DWORD   lDataRep )
4119 {
4120     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4121     trace("TestChannelHook_ServerNotify\n");
4122 
4123     if (!new_hook_struct)
4124     {
4125         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4126         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4127         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4128         ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4129         ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4130     }
4131     else
4132     {
4133         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4134         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4135            GetCurrentProcessId());
4136         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4137            server_tid);
4138         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4139         ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4140     }
4141 
4142     ok(cbDataSize == 1, "cbDataSize should have been 1 instead of %d\n", cbDataSize);
4143     ok(*(unsigned char *)pDataBuffer == 0xcc, "pDataBuffer should have contained 0xcc instead of 0x%x\n", *(unsigned char *)pDataBuffer);
4144     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4145 }
4146 
4147 static void WINAPI TestChannelHook_ServerGetSize(
4148     IChannelHook *iface,
4149     REFGUID uExtent,
4150     REFIID  riid,
4151     HRESULT hrFault,
4152     ULONG  *pDataSize )
4153 {
4154     SChannelHookCallInfo *info = (SChannelHookCallInfo *)riid;
4155     trace("TestChannelHook_ServerGetSize\n");
4156     trace("\t%s\n", debugstr_iid(riid));
4157     if (!new_hook_struct)
4158     {
4159         ok(info->cbSize == sizeof(*info), "cbSize was %d instead of %d\n", info->cbSize, (int)sizeof(*info));
4160         ok(info->dwServerPid == GetCurrentProcessId(), "dwServerPid was 0x%x instead of 0x%x\n", info->dwServerPid, GetCurrentProcessId());
4161         ok(info->iMethod == method, "iMethod was %d should be %d\n", info->iMethod, method);
4162         ok(info->pObject != NULL, "pObject shouldn't be NULL\n");
4163         ok(IsEqualGUID(&info->uCausality, &causality), "causality wasn't correct\n");
4164     }
4165     else
4166     {
4167         struct new_hook_info *new_info = (struct new_hook_info *)riid;
4168         ok(new_info->server_pid == GetCurrentProcessId(), "server pid was 0x%x instead of 0x%x\n", new_info->server_pid,
4169            GetCurrentProcessId());
4170         ok(new_info->server_tid == server_tid, "server tid was 0x%x instead of 0x%x\n", new_info->server_tid,
4171            server_tid);
4172         ok(new_info->method == method, "method was %d instead of %d\n", new_info->method, method);
4173         ok(IsEqualGUID(&new_info->causality, &causality), "causality wasn't correct\n");
4174     }
4175 
4176     ok(IsEqualGUID(uExtent, &EXTENTID_WineTest), "uExtent wasn't correct\n");
4177     if (hrFault != S_OK)
4178         trace("\thrFault = 0x%08x\n", hrFault);
4179 
4180     *pDataSize = 0;
4181 }
4182 
4183 static void WINAPI TestChannelHook_ServerFillBuffer(
4184     IChannelHook *iface,
4185     REFGUID uExtent,
4186     REFIID  riid,
4187     ULONG  *pDataSize,
4188     void   *pDataBuffer,
4189     HRESULT hrFault )
4190 {
4191     trace("TestChannelHook_ServerFillBuffer\n");
4192     ok(0, "TestChannelHook_ServerFillBuffer shouldn't be called\n");
4193 }
4194 
4195 static const IChannelHookVtbl TestChannelHookVtbl =
4196 {
4197     TestChannelHook_QueryInterface,
4198     TestChannelHook_AddRef,
4199     TestChannelHook_Release,
4200     TestChannelHook_ClientGetSize,
4201     TestChannelHook_ClientFillBuffer,
4202     TestChannelHook_ClientNotify,
4203     TestChannelHook_ServerNotify,
4204     TestChannelHook_ServerGetSize,
4205     TestChannelHook_ServerFillBuffer,
4206 };
4207 
4208 static IChannelHook TestChannelHook = { &TestChannelHookVtbl };
4209 
4210 static void test_channel_hook(void)
4211 {
4212     IClassFactory *cf = NULL;
4213     DWORD tid;
4214     IUnknown *proxy = NULL;
4215     HANDLE thread;
4216     HRESULT hr;
4217 
4218     struct host_object_data object_data = { NULL, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory,
4219                                             MSHLFLAGS_NORMAL, &MessageFilter };
4220 
4221     hr = CoRegisterChannelHook(&EXTENTID_WineTest, &TestChannelHook);
4222     ok_ole_success(hr, CoRegisterChannelHook);
4223 
4224     hr = CoRegisterMessageFilter(&MessageFilter, NULL);
4225     ok_ole_success(hr, CoRegisterMessageFilter);
4226 
4227     cLocks = 0;
4228 
4229     hr = CreateStreamOnHGlobal(NULL, TRUE, &object_data.stream);
4230     ok_ole_success(hr, CreateStreamOnHGlobal);
4231     tid = start_host_object2(&object_data, &thread);
4232     server_tid = tid;
4233 
4234     ok_more_than_one_lock();
4235 
4236     IStream_Seek(object_data.stream, ullZero, STREAM_SEEK_SET, NULL);
4237     hr = CoUnmarshalInterface(object_data.stream, &IID_IClassFactory, (void **)&cf);
4238     ok_ole_success(hr, CoUnmarshalInterface);
4239     IStream_Release(object_data.stream);
4240 
4241     ok_more_than_one_lock();
4242 
4243     method = 3;
4244     hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&proxy);
4245     ok_ole_success(hr, IClassFactory_CreateInstance);
4246 
4247     method = 5;
4248     IUnknown_Release(proxy);
4249 
4250     IClassFactory_Release(cf);
4251 
4252     ok_no_locks();
4253 
4254     end_host_object(tid, thread);
4255 
4256     hr = CoRegisterMessageFilter(NULL, NULL);
4257     ok_ole_success(hr, CoRegisterMessageFilter);
4258 }
4259 
4260 START_TEST(marshal)
4261 {
4262     HMODULE hOle32 = GetModuleHandleA("ole32");
4263     int argc;
4264     char **argv;
4265 
4266     if (!GetProcAddress(hOle32, "CoRegisterSurrogateEx")) {
4267         win_skip("skipping test on win9x\n");
4268         return;
4269     }
4270 
4271     pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx");
4272     pDllGetClassObject = (void*)GetProcAddress(hOle32, "DllGetClassObject");
4273 
4274     argc = winetest_get_mainargs( &argv );
4275     if (argc > 2 && (!strcmp(argv[2], "-Embedding")))
4276     {
4277         pCoInitializeEx(NULL, COINIT_MULTITHREADED);
4278         test_register_local_server();
4279         CoUninitialize();
4280 
4281         return;
4282     }
4283 
4284     register_test_window();
4285 
4286     test_cocreateinstance_proxy();
4287     test_implicit_mta();
4288 
4289     pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
4290 
4291     /* FIXME: test CoCreateInstanceEx */
4292 
4293     /* lifecycle management and marshaling tests */
4294     do
4295     {
4296         test_no_marshaler();
4297         test_normal_marshal_and_release();
4298         test_normal_marshal_and_unmarshal();
4299         test_marshal_and_unmarshal_invalid();
4300         test_same_apartment_unmarshal_failure();
4301         test_interthread_marshal_and_unmarshal();
4302         test_proxy_marshal_and_unmarshal();
4303         test_proxy_marshal_and_unmarshal2();
4304         test_proxy_marshal_and_unmarshal_weak();
4305         test_proxy_marshal_and_unmarshal_strong();
4306         test_marshal_stub_apartment_shutdown();
4307         test_marshal_proxy_apartment_shutdown();
4308         test_marshal_proxy_mta_apartment_shutdown();
4309         test_no_couninitialize_server();
4310         test_no_couninitialize_client();
4311         test_tableweak_marshal_and_unmarshal_twice();
4312         test_tableweak_marshal_releasedata1();
4313         test_tableweak_marshal_releasedata2();
4314         test_tableweak_and_normal_marshal_and_unmarshal();
4315         test_tableweak_and_normal_marshal_and_releasedata();
4316         test_two_tableweak_marshal_and_releasedata();
4317         test_tablestrong_marshal_and_unmarshal_twice();
4318         test_lock_object_external();
4319         test_disconnect_stub();
4320         test_normal_marshal_and_unmarshal_twice();
4321 
4322         with_external_conn = !with_external_conn;
4323     } while (with_external_conn);
4324 
4325     test_marshal_channel_buffer();
4326     test_hresult_marshaling();
4327     test_proxy_used_in_wrong_thread();
4328     test_message_filter();
4329     test_bad_marshal_stream();
4330     test_proxy_interfaces();
4331     test_stubbuffer(&IID_IClassFactory);
4332     test_proxybuffer(&IID_IClassFactory);
4333     test_message_reentrancy();
4334     test_call_from_message();
4335     test_WM_QUIT_handling();
4336     test_freethreadedmarshaler();
4337     test_inproc_handler();
4338     test_handler_marshaling();
4339     test_client_security();
4340 
4341     test_local_server();
4342 
4343     test_globalinterfacetable();
4344     test_manualresetevent();
4345     test_crash_couninitialize();
4346 
4347     /* must be last test as channel hooks can't be unregistered */
4348     test_channel_hook();
4349 
4350     CoUninitialize();
4351 }
4352