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