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