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