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