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