4 * Copyright 2004 Robert Shearman
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/test.h"
32 /* functions that are not present on all versions of Windows */
33 HRESULT (WINAPI * pCoInitializeEx)(LPVOID lpReserved, DWORD dwCoInit);
35 /* helper macros to make tests a bit leaner */
36 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %ld\n", cLocks)
37 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %ld\n", cLocks)
38 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08lx\n", hr)
40 static const LARGE_INTEGER ullZero;
43 static void LockModule()
45 InterlockedIncrement(&cLocks);
48 static void UnlockModule()
50 InterlockedDecrement(&cLocks);
54 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
59 if (ppvObj == NULL) return E_POINTER;
61 if (IsEqualGUID(riid, &IID_IUnknown) ||
62 IsEqualGUID(riid, &IID_IClassFactory))
64 *ppvObj = (LPVOID)iface;
65 IClassFactory_AddRef(iface);
72 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
75 return 2; /* non-heap-based object */
78 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
81 return 1; /* non-heap-based object */
84 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
90 return CLASS_E_CLASSNOTAVAILABLE;
93 static HRESULT WINAPI Test_IClassFactory_LockServer(
100 static IClassFactoryVtbl TestClassFactory_Vtbl =
102 Test_IClassFactory_QueryInterface,
103 Test_IClassFactory_AddRef,
104 Test_IClassFactory_Release,
105 Test_IClassFactory_CreateInstance,
106 Test_IClassFactory_LockServer
109 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
111 #define RELEASEMARSHALDATA WM_USER
113 struct host_object_data
118 MSHLFLAGS marshal_flags;
119 HANDLE marshal_event;
120 IMessageFilter *filter;
123 static DWORD CALLBACK host_object_proc(LPVOID p)
125 struct host_object_data *data = (struct host_object_data *)p;
129 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
133 IMessageFilter * prev_filter = NULL;
134 hr = CoRegisterMessageFilter(data->filter, &prev_filter);
135 if (prev_filter) IMessageFilter_Release(prev_filter);
136 ok_ole_success(hr, CoRegisterMessageFilter);
139 hr = CoMarshalInterface(data->stream, &data->iid, data->object, MSHCTX_INPROC, NULL, data->marshal_flags);
140 ok_ole_success(hr, CoMarshalInterface);
142 SetEvent(data->marshal_event);
144 while (GetMessage(&msg, NULL, 0, 0))
146 if (msg.hwnd == NULL && msg.message == RELEASEMARSHALDATA)
148 trace("releasing marshal data\n");
149 CoReleaseMarshalData(data->stream);
150 SetEvent((HANDLE)msg.lParam);
153 DispatchMessage(&msg);
156 HeapFree(GetProcessHeap(), 0, data);
163 static DWORD start_host_object2(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, IMessageFilter *filter, HANDLE *thread)
166 HANDLE marshal_event = CreateEvent(NULL, FALSE, FALSE, NULL);
167 struct host_object_data *data = (struct host_object_data *)HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
169 data->stream = stream;
171 data->object = object;
172 data->marshal_flags = marshal_flags;
173 data->marshal_event = marshal_event;
174 data->filter = filter;
176 *thread = CreateThread(NULL, 0, host_object_proc, data, 0, &tid);
178 /* wait for marshaling to complete before returning */
179 WaitForSingleObject(marshal_event, INFINITE);
180 CloseHandle(marshal_event);
185 static DWORD start_host_object(IStream *stream, REFIID riid, IUnknown *object, MSHLFLAGS marshal_flags, HANDLE *thread)
187 return start_host_object2(stream, riid, object, marshal_flags, NULL, thread);
190 /* asks thread to release the marshal data because it has to be done by the
191 * same thread that marshaled the interface in the first place. */
192 static void release_host_object(DWORD tid)
194 HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL);
195 PostThreadMessage(tid, RELEASEMARSHALDATA, 0, (LPARAM)event);
196 WaitForSingleObject(event, INFINITE);
200 static void end_host_object(DWORD tid, HANDLE thread)
202 PostThreadMessage(tid, WM_QUIT, 0, 0);
203 /* be careful of races - don't return until hosting thread has terminated */
204 WaitForSingleObject(thread, INFINITE);
208 /* tests normal marshal and then release without unmarshaling */
209 static void test_normal_marshal_and_release()
212 IStream *pStream = NULL;
216 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
217 ok_ole_success(hr, CreateStreamOnHGlobal);
218 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
219 ok_ole_success(hr, CoMarshalInterface);
221 ok_more_than_one_lock();
223 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
224 hr = CoReleaseMarshalData(pStream);
225 ok_ole_success(hr, CoReleaseMarshalData);
226 IStream_Release(pStream);
231 /* tests success case of a same-thread marshal and unmarshal */
232 static void test_normal_marshal_and_unmarshal()
235 IStream *pStream = NULL;
236 IUnknown *pProxy = NULL;
240 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
241 ok_ole_success(hr, CreateStreamOnHGlobal);
242 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
243 ok_ole_success(hr, CoMarshalInterface);
245 ok_more_than_one_lock();
247 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
248 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
249 ok_ole_success(hr, CoUnmarshalInterface);
250 IStream_Release(pStream);
252 ok_more_than_one_lock();
254 IUnknown_Release(pProxy);
259 /* tests success case of an interthread marshal */
260 static void test_interthread_marshal_and_unmarshal()
263 IStream *pStream = NULL;
264 IUnknown *pProxy = NULL;
270 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
271 ok_ole_success(hr, CreateStreamOnHGlobal);
272 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
274 ok_more_than_one_lock();
276 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
277 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
278 ok_ole_success(hr, CoReleaseMarshalData);
279 IStream_Release(pStream);
281 ok_more_than_one_lock();
283 IUnknown_Release(pProxy);
287 end_host_object(tid, thread);
290 /* tests that stubs are released when the containing apartment is destroyed */
291 static void test_marshal_stub_apartment_shutdown()
294 IStream *pStream = NULL;
295 IUnknown *pProxy = NULL;
301 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
302 ok_ole_success(hr, CreateStreamOnHGlobal);
303 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
305 ok_more_than_one_lock();
307 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
308 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
309 ok_ole_success(hr, CoReleaseMarshalData);
310 IStream_Release(pStream);
312 ok_more_than_one_lock();
314 end_host_object(tid, thread);
316 todo_wine { ok_no_locks(); }
318 IUnknown_Release(pProxy);
323 /* tests that proxies are released when the containing apartment is destroyed */
324 static void test_marshal_proxy_apartment_shutdown()
327 IStream *pStream = NULL;
328 IUnknown *pProxy = NULL;
334 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
335 ok_ole_success(hr, CreateStreamOnHGlobal);
336 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
338 ok_more_than_one_lock();
340 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
341 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
342 ok_ole_success(hr, CoReleaseMarshalData);
343 IStream_Release(pStream);
345 ok_more_than_one_lock();
349 /* FIXME: this could be a bit racy - I don't know if there are any
350 * guarantees that the stub will get its disconnection message
352 todo_wine { ok_no_locks(); }
354 IUnknown_Release(pProxy);
358 end_host_object(tid, thread);
360 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
363 /* tests success case of a same-thread table-weak marshal, unmarshal, unmarshal */
364 static void test_tableweak_marshal_and_unmarshal_twice()
367 IStream *pStream = NULL;
368 IUnknown *pProxy1 = NULL;
369 IUnknown *pProxy2 = NULL;
375 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
376 ok_ole_success(hr, CreateStreamOnHGlobal);
377 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLEWEAK, &thread);
379 ok_more_than_one_lock();
381 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
382 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
383 ok_ole_success(hr, CoReleaseMarshalData);
385 ok_more_than_one_lock();
387 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
388 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
389 ok_ole_success(hr, CoUnmarshalInterface);
391 ok_more_than_one_lock();
393 IUnknown_Release(pProxy1);
394 IUnknown_Release(pProxy2);
396 /* this line is shows the difference between weak and strong table marshaling:
397 * weak has cLocks == 0
398 * strong has cLocks > 0 */
399 todo_wine { ok_no_locks(); }
401 end_host_object(tid, thread);
404 /* tests success case of a same-thread table-strong marshal, unmarshal, unmarshal */
405 static void test_tablestrong_marshal_and_unmarshal_twice()
408 IStream *pStream = NULL;
409 IUnknown *pProxy1 = NULL;
410 IUnknown *pProxy2 = NULL;
416 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
417 ok_ole_success(hr, CreateStreamOnHGlobal);
418 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_TABLESTRONG, &thread);
420 ok_more_than_one_lock();
422 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
423 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
424 ok_ole_success(hr, CoReleaseMarshalData);
426 ok_more_than_one_lock();
428 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
429 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
430 ok_ole_success(hr, CoUnmarshalInterface);
432 ok_more_than_one_lock();
434 if (pProxy1) IUnknown_Release(pProxy1);
435 if (pProxy2) IUnknown_Release(pProxy2);
437 /* this line is shows the difference between weak and strong table marshaling:
438 * weak has cLocks == 0
439 * strong has cLocks > 0 */
440 ok_more_than_one_lock();
442 /* release the remaining reference on the object by calling
443 * CoReleaseMarshalData in the hosting thread */
444 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
445 release_host_object(tid);
446 IStream_Release(pStream);
448 todo_wine { ok_no_locks(); }
450 end_host_object(tid, thread);
453 /* tests CoLockObjectExternal */
454 static void test_lock_object_external()
457 IStream *pStream = NULL;
461 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
462 ok_ole_success(hr, CreateStreamOnHGlobal);
463 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
464 ok_ole_success(hr, CoMarshalInterface);
466 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
468 ok_more_than_one_lock();
470 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
471 hr = CoReleaseMarshalData(pStream);
472 ok_ole_success(hr, CoReleaseMarshalData);
473 IStream_Release(pStream);
475 ok_more_than_one_lock();
477 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, FALSE, TRUE);
482 /* tests disconnecting stubs */
483 static void test_disconnect_stub()
486 IStream *pStream = NULL;
490 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
491 ok_ole_success(hr, CreateStreamOnHGlobal);
492 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
493 ok_ole_success(hr, CoMarshalInterface);
495 CoLockObjectExternal((IUnknown*)&Test_ClassFactory, TRUE, TRUE);
497 ok_more_than_one_lock();
499 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
500 hr = CoReleaseMarshalData(pStream);
501 ok_ole_success(hr, CoReleaseMarshalData);
502 IStream_Release(pStream);
504 ok_more_than_one_lock();
506 CoDisconnectObject((IUnknown*)&Test_ClassFactory, 0);
508 todo_wine { ok_no_locks(); }
511 /* tests failure case of a same-thread marshal and unmarshal twice */
512 static void test_normal_marshal_and_unmarshal_twice()
515 IStream *pStream = NULL;
516 IUnknown *pProxy1 = NULL;
517 IUnknown *pProxy2 = NULL;
521 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
522 ok_ole_success(hr, CreateStreamOnHGlobal);
523 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
524 ok_ole_success(hr, CoMarshalInterface);
526 ok_more_than_one_lock();
528 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
529 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy1);
530 ok_ole_success(hr, CoUnmarshalInterface);
532 ok_more_than_one_lock();
534 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
535 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
537 ok(hr == CO_E_OBJNOTCONNECTED,
538 "CoUnmarshalInterface should have failed with error CO_E_OBJNOTCONNECTED for double unmarshal, instead of 0x%08lx\n", hr);
541 IStream_Release(pStream);
543 ok_more_than_one_lock();
545 IUnknown_Release(pProxy1);
550 /* tests success case of marshaling and unmarshaling an HRESULT */
551 static void test_hresult_marshaling()
554 HRESULT hr_marshaled = 0;
555 IStream *pStream = NULL;
556 static const HRESULT E_DEADBEEF = 0xdeadbeef;
558 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
559 ok_ole_success(hr, CreateStreamOnHGlobal);
561 hr = CoMarshalHresult(pStream, E_DEADBEEF);
562 ok_ole_success(hr, CoMarshalHresult);
564 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
565 hr = IStream_Read(pStream, &hr_marshaled, sizeof(HRESULT), NULL);
566 ok_ole_success(hr, IStream_Read);
568 ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
571 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
572 hr = CoUnmarshalHresult(pStream, &hr_marshaled);
573 ok_ole_success(hr, CoUnmarshalHresult);
575 ok(hr_marshaled == E_DEADBEEF, "Didn't marshal HRESULT as expected: got value 0x%08lx instead\n", hr_marshaled);
577 IStream_Release(pStream);
581 /* helper for test_proxy_used_in_wrong_thread */
582 static DWORD CALLBACK bad_thread_proc(LPVOID p)
584 IClassFactory * cf = (IClassFactory *)p;
588 CoInitializeEx(NULL, COINIT_MULTITHREADED);
590 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&dummy);
593 ok(hr == RPC_E_WRONG_THREAD,
594 "COM should have failed with RPC_E_WRONG_THREAD on using proxy from wrong apartment, but instead returned 0x%08lx\n",
603 /* tests failure case of a using a proxy in the wrong apartment */
604 static void test_proxy_used_in_wrong_thread()
607 IStream *pStream = NULL;
608 IUnknown *pProxy = NULL;
615 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
616 ok_ole_success(hr, CreateStreamOnHGlobal);
617 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &host_thread);
619 ok_more_than_one_lock();
621 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
622 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
623 ok_ole_success(hr, CoReleaseMarshalData);
624 IStream_Release(pStream);
626 ok_more_than_one_lock();
628 /* create a thread that we can misbehave in */
629 thread = CreateThread(NULL, 0, bad_thread_proc, (LPVOID)pProxy, 0, &tid2);
631 WaitForSingleObject(thread, INFINITE);
634 IUnknown_Release(pProxy);
638 end_host_object(tid, host_thread);
641 static HRESULT WINAPI MessageFilter_QueryInterface(IMessageFilter *iface, REFIID riid, void ** ppvObj)
643 if (ppvObj == NULL) return E_POINTER;
645 if (IsEqualGUID(riid, &IID_IUnknown) ||
646 IsEqualGUID(riid, &IID_IClassFactory))
648 *ppvObj = (LPVOID)iface;
649 IClassFactory_AddRef(iface);
653 return E_NOINTERFACE;
656 static ULONG WINAPI MessageFilter_AddRef(IMessageFilter *iface)
658 return 2; /* non-heap object */
661 static ULONG WINAPI MessageFilter_Release(IMessageFilter *iface)
663 return 1; /* non-heap object */
666 static DWORD WINAPI MessageFilter_HandleInComingCall(
667 IMessageFilter *iface,
669 HTASK threadIDCaller,
671 LPINTERFACEINFO lpInterfaceInfo)
673 static int callcount = 0;
675 trace("HandleInComingCall\n");
679 ret = SERVERCALL_REJECTED;
682 ret = SERVERCALL_RETRYLATER;
685 ret = SERVERCALL_ISHANDLED;
692 static DWORD WINAPI MessageFilter_RetryRejectedCall(
693 IMessageFilter *iface,
694 HTASK threadIDCallee,
698 trace("RetryRejectedCall\n");
702 static DWORD WINAPI MessageFilter_MessagePending(
703 IMessageFilter *iface,
704 HTASK threadIDCallee,
708 trace("MessagePending\n");
709 return PENDINGMSG_WAITNOPROCESS;
712 static IMessageFilterVtbl MessageFilter_Vtbl =
714 MessageFilter_QueryInterface,
715 MessageFilter_AddRef,
716 MessageFilter_Release,
717 MessageFilter_HandleInComingCall,
718 MessageFilter_RetryRejectedCall,
719 MessageFilter_MessagePending
722 static IMessageFilter MessageFilter = { &MessageFilter_Vtbl };
724 static void test_message_filter()
727 IStream *pStream = NULL;
728 IClassFactory *cf = NULL;
731 IMessageFilter *prev_filter = NULL;
736 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
737 ok_ole_success(hr, CreateStreamOnHGlobal);
738 tid = start_host_object2(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &MessageFilter, &thread);
740 ok_more_than_one_lock();
742 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
743 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&cf);
744 ok_ole_success(hr, CoReleaseMarshalData);
745 IStream_Release(pStream);
747 ok_more_than_one_lock();
749 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&dummy);
750 todo_wine { ok(hr == RPC_E_CALL_REJECTED, "Call should have returned RPC_E_CALL_REJECTED, but return 0x%08lx instead\n", hr); }
752 hr = CoRegisterMessageFilter(&MessageFilter, &prev_filter);
753 ok_ole_success(hr, CoRegisterMessageFilter);
754 if (prev_filter) IMessageFilter_Release(prev_filter);
756 hr = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (LPVOID*)&dummy);
757 ok(hr == CLASS_E_CLASSNOTAVAILABLE, "Call didn't wasn't accepted. hr = 0x%08lx\n", hr);
759 IClassFactory_Release(cf);
763 end_host_object(tid, thread);
766 /* test failure case of trying to unmarshal from bad stream */
767 static void test_bad_marshal_stream()
770 IStream *pStream = NULL;
772 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
773 ok_ole_success(hr, CreateStreamOnHGlobal);
774 hr = CoMarshalInterface(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
775 ok_ole_success(hr, CoMarshalInterface);
777 ok_more_than_one_lock();
779 /* try to read beyond end of stream */
780 hr = CoReleaseMarshalData(pStream);
781 ok(hr == STG_E_READFAULT, "Should have failed with STG_E_READFAULT, but returned 0x%08lx instead\n", hr);
783 /* now release for real */
784 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
785 hr = CoReleaseMarshalData(pStream);
786 ok_ole_success(hr, CoReleaseMarshalData);
788 IStream_Release(pStream);
791 /* tests that proxies implement certain interfaces */
792 static void test_proxy_interfaces()
795 IStream *pStream = NULL;
796 IUnknown *pProxy = NULL;
797 IUnknown *pOtherUnknown = NULL;
800 static const IID IID_IMarshal2 =
805 { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 }
810 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
811 ok_ole_success(hr, CreateStreamOnHGlobal);
812 tid = start_host_object(pStream, &IID_IClassFactory, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
814 ok_more_than_one_lock();
816 IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
817 hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy);
818 ok_ole_success(hr, CoReleaseMarshalData);
819 IStream_Release(pStream);
821 ok_more_than_one_lock();
823 hr = IUnknown_QueryInterface(pProxy, &IID_IUnknown, (LPVOID*)&pOtherUnknown);
824 ok_ole_success(hr, IUnknown_QueryInterface IID_IUnknown);
825 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
827 hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (LPVOID*)&pOtherUnknown);
828 todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IClientSecurity); }
829 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
831 hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown);
832 todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI); }
833 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
835 hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);
836 todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal); }
837 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
839 hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal2, (LPVOID*)&pOtherUnknown);
840 todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IMarshal2); }
841 if (hr == S_OK) IUnknown_Release(pOtherUnknown);
843 IUnknown_Release(pProxy);
847 end_host_object(tid, thread);
851 /* doesn't pass with Win9x COM DLLs (even though Essential COM says it should) */
854 static HANDLE heventShutdown;
856 static void LockModuleOOP()
858 InterlockedIncrement(&cLocks); /* for test purposes only */
859 CoAddRefServerProcess();
862 static void UnlockModuleOOP()
864 InterlockedDecrement(&cLocks); /* for test purposes only */
865 if (!CoReleaseServerProcess())
866 SetEvent(heventShutdown);
870 static HRESULT WINAPI TestOOP_IClassFactory_QueryInterface(
871 LPCLASSFACTORY iface,
875 if (ppvObj == NULL) return E_POINTER;
877 if (IsEqualGUID(riid, &IID_IUnknown) ||
878 IsEqualGUID(riid, &IID_IClassFactory))
880 *ppvObj = (LPVOID)iface;
881 IClassFactory_AddRef(iface);
885 return E_NOINTERFACE;
888 static ULONG WINAPI TestOOP_IClassFactory_AddRef(LPCLASSFACTORY iface)
890 return 2; /* non-heap-based object */
893 static ULONG WINAPI TestOOP_IClassFactory_Release(LPCLASSFACTORY iface)
895 return 1; /* non-heap-based object */
898 static HRESULT WINAPI TestOOP_IClassFactory_CreateInstance(
899 LPCLASSFACTORY iface,
904 return CLASS_E_CLASSNOTAVAILABLE;
907 static HRESULT WINAPI TestOOP_IClassFactory_LockServer(
908 LPCLASSFACTORY iface,
918 static IClassFactoryVtbl TestClassFactoryOOP_Vtbl =
920 TestOOP_IClassFactory_QueryInterface,
921 TestOOP_IClassFactory_AddRef,
922 TestOOP_IClassFactory_Release,
923 TestOOP_IClassFactory_CreateInstance,
924 TestOOP_IClassFactory_LockServer
927 static IClassFactory TestOOP_ClassFactory = { &TestClassFactoryOOP_Vtbl };
929 /* tests functions commonly used by out of process COM servers */
930 static void test_out_of_process_com()
932 static const CLSID CLSID_WineOOPTest = {
936 {0xa1, 0xa2, 0x5d, 0x5a, 0x36, 0x54, 0xd3, 0xbd}
937 }; /* 5201163f-8164-4fd0-a1a2-5d5a3654d3bd */
943 heventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
947 /* Start the object suspended */
948 hr = CoRegisterClassObject(&CLSID_WineOOPTest, (IUnknown *)&TestOOP_ClassFactory,
949 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &cookie);
950 ok_ole_success(hr, CoRegisterClassObject);
952 /* ... and CoGetClassObject does not find it and fails when it looks for the
953 * class in the registry */
954 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
955 NULL, &IID_IClassFactory, (LPVOID*)&cf);
957 ok(hr == REGDB_E_CLASSNOTREG,
958 "CoGetClassObject should have returned REGDB_E_CLASSNOTREG instead of 0x%08lx\n", hr);
961 /* Resume the object suspended above ... */
962 hr = CoResumeClassObjects();
963 ok_ole_success(hr, CoResumeClassObjects);
965 /* ... and now it should succeed */
966 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER,
967 NULL, &IID_IClassFactory, (LPVOID*)&cf);
968 ok_ole_success(hr, CoGetClassObject);
970 /* Now check the locking is working */
971 /* NOTE: we are accessing the class directly, not through a proxy */
975 hr = IClassFactory_LockServer(cf, TRUE);
976 trace("IClassFactory_LockServer returned 0x%08lx\n", hr);
978 ok_more_than_one_lock();
980 IClassFactory_LockServer(cf, FALSE);
984 IClassFactory_Release(cf);
986 /* wait for shutdown signal */
987 ret = WaitForSingleObject(heventShutdown, 5000);
988 todo_wine { ok(ret != WAIT_TIMEOUT, "Server didn't shut down or machine is under very heavy load\n"); }
990 /* try to connect again after SCM has suspended registered class objects */
991 hr = CoGetClassObject(&CLSID_WineOOPTest, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, NULL,
992 &IID_IClassFactory, (LPVOID*)&cf);
994 ok(hr == CO_E_SERVER_STOPPING,
995 "CoGetClassObject should have returned CO_E_SERVER_STOPPING instead of 0x%08lx\n", hr);
998 hr = CoRevokeClassObject(cookie);
999 ok_ole_success(hr, CoRevokeClassObject);
1001 CloseHandle(heventShutdown);
1007 HMODULE hOle32 = GetModuleHandle("ole32");
1008 if (!(pCoInitializeEx = (void*)GetProcAddress(hOle32, "CoInitializeEx"))) goto no_test;
1010 pCoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1012 /* FIXME: test CoCreateInstanceEx */
1014 /* lifecycle management and marshaling tests */
1015 test_normal_marshal_and_release();
1016 test_normal_marshal_and_unmarshal();
1017 test_interthread_marshal_and_unmarshal();
1018 test_marshal_stub_apartment_shutdown();
1019 test_marshal_proxy_apartment_shutdown();
1020 test_tableweak_marshal_and_unmarshal_twice();
1021 test_tablestrong_marshal_and_unmarshal_twice();
1022 test_lock_object_external();
1023 test_disconnect_stub();
1024 test_normal_marshal_and_unmarshal_twice();
1025 test_hresult_marshaling();
1026 test_proxy_used_in_wrong_thread();
1027 test_message_filter();
1028 test_bad_marshal_stream();
1029 test_proxy_interfaces();
1030 /* FIXME: test custom marshaling */
1031 /* FIXME: test GIT */
1032 /* FIXME: test COM re-entrancy */
1034 /* test_out_of_process_com(); */
1039 trace("You need DCOM95 installed to run this test\n");