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