1 /* 2 * Moniker 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 "ocidl.h" 32 #include "initguid.h" 33 #include "comcat.h" 34 #include "olectl.h" 35 36 #include "wine/test.h" 37 38 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks) 39 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks) 40 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr) 41 #define COUNTOF(x) (sizeof(x) / sizeof(x[0])) 42 43 #define CHECK_EXPECTED_METHOD(method_name) \ 44 do { \ 45 trace("%s\n", method_name); \ 46 ok(*expected_method_list != NULL, "Extra method %s called\n", method_name); \ 47 if (*expected_method_list) \ 48 { \ 49 ok(!strcmp(*expected_method_list, method_name), "Expected %s to be called instead of %s\n", \ 50 *expected_method_list, method_name); \ 51 expected_method_list++; \ 52 } \ 53 } while(0) 54 55 static char const * const *expected_method_list; 56 static const WCHAR wszFileName1[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','1','.','d','o','c',0}; 57 static const WCHAR wszFileName2[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','2','.','d','o','c',0}; 58 59 static const CLSID CLSID_TestMoniker = 60 { /* b306bfbc-496e-4f53-b93e-2ff9c83223d7 */ 61 0xb306bfbc, 62 0x496e, 63 0x4f53, 64 {0xb9, 0x3e, 0x2f, 0xf9, 0xc8, 0x32, 0x23, 0xd7} 65 }; 66 67 static LONG cLocks; 68 69 static void LockModule(void) 70 { 71 InterlockedIncrement(&cLocks); 72 } 73 74 static void UnlockModule(void) 75 { 76 InterlockedDecrement(&cLocks); 77 } 78 79 static SIZE_T round_global_size(SIZE_T size) 80 { 81 static SIZE_T global_size_alignment = -1; 82 if (global_size_alignment == -1) 83 { 84 void *p = GlobalAlloc(GMEM_FIXED, 1); 85 global_size_alignment = GlobalSize(p); 86 GlobalFree(p); 87 } 88 89 return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1)); 90 } 91 92 static DWORD external_connections; 93 94 static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv) 95 { 96 ok(0, "unexpected call\n"); 97 *ppv = NULL; 98 return E_NOINTERFACE; 99 } 100 101 static ULONG WINAPI ExternalConnection_AddRef(IExternalConnection *iface) 102 { 103 return 2; 104 } 105 106 static ULONG WINAPI ExternalConnection_Release(IExternalConnection *iface) 107 { 108 return 1; 109 } 110 111 static DWORD WINAPI ExternalConnection_AddConnection(IExternalConnection *iface, DWORD extconn, DWORD reserved) 112 { 113 trace("add connection\n"); 114 115 ok(extconn == EXTCONN_STRONG, "extconn = %d\n", extconn); 116 ok(!reserved, "reserved = %x\n", reserved); 117 return ++external_connections; 118 } 119 120 static DWORD WINAPI ExternalConnection_ReleaseConnection(IExternalConnection *iface, DWORD extconn, 121 DWORD reserved, BOOL fLastReleaseCloses) 122 { 123 trace("release connection\n"); 124 125 ok(extconn == EXTCONN_STRONG, "extconn = %d\n", extconn); 126 ok(!reserved, "reserved = %x\n", reserved); 127 128 return --external_connections; 129 } 130 131 static const IExternalConnectionVtbl ExternalConnectionVtbl = { 132 ExternalConnection_QueryInterface, 133 ExternalConnection_AddRef, 134 ExternalConnection_Release, 135 ExternalConnection_AddConnection, 136 ExternalConnection_ReleaseConnection 137 }; 138 139 static IExternalConnection ExternalConnection = { &ExternalConnectionVtbl }; 140 141 static HRESULT WINAPI Test_IClassFactory_QueryInterface( 142 LPCLASSFACTORY iface, 143 REFIID riid, 144 LPVOID *ppvObj) 145 { 146 if (ppvObj == NULL) return E_POINTER; 147 148 if (IsEqualGUID(riid, &IID_IUnknown) || 149 IsEqualGUID(riid, &IID_IClassFactory)) 150 { 151 *ppvObj = iface; 152 IClassFactory_AddRef(iface); 153 return S_OK; 154 } 155 156 if(IsEqualGUID(riid, &IID_IExternalConnection)) { 157 *ppvObj = &ExternalConnection; 158 return S_OK; 159 } 160 161 *ppvObj = NULL; 162 return E_NOINTERFACE; 163 } 164 165 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface) 166 { 167 LockModule(); 168 return 2; /* non-heap-based object */ 169 } 170 171 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface) 172 { 173 UnlockModule(); 174 return 1; /* non-heap-based object */ 175 } 176 177 static HRESULT WINAPI Test_IClassFactory_CreateInstance( 178 LPCLASSFACTORY iface, 179 LPUNKNOWN pUnkOuter, 180 REFIID riid, 181 LPVOID *ppvObj) 182 { 183 return E_NOTIMPL; 184 } 185 186 static HRESULT WINAPI Test_IClassFactory_LockServer( 187 LPCLASSFACTORY iface, 188 BOOL fLock) 189 { 190 return S_OK; 191 } 192 193 static const IClassFactoryVtbl TestClassFactory_Vtbl = 194 { 195 Test_IClassFactory_QueryInterface, 196 Test_IClassFactory_AddRef, 197 Test_IClassFactory_Release, 198 Test_IClassFactory_CreateInstance, 199 Test_IClassFactory_LockServer 200 }; 201 202 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl }; 203 204 typedef struct 205 { 206 IUnknown IUnknown_iface; 207 ULONG refs; 208 } HeapUnknown; 209 210 static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface) 211 { 212 return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface); 213 } 214 215 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 216 { 217 if (IsEqualIID(riid, &IID_IUnknown)) 218 { 219 IUnknown_AddRef(iface); 220 *ppv = iface; 221 return S_OK; 222 } 223 *ppv = NULL; 224 return E_NOINTERFACE; 225 } 226 227 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface) 228 { 229 HeapUnknown *This = impl_from_IUnknown(iface); 230 return InterlockedIncrement((LONG*)&This->refs); 231 } 232 233 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface) 234 { 235 HeapUnknown *This = impl_from_IUnknown(iface); 236 ULONG refs = InterlockedDecrement((LONG*)&This->refs); 237 if (!refs) HeapFree(GetProcessHeap(), 0, This); 238 return refs; 239 } 240 241 static const IUnknownVtbl HeapUnknown_Vtbl = 242 { 243 HeapUnknown_QueryInterface, 244 HeapUnknown_AddRef, 245 HeapUnknown_Release 246 }; 247 248 static HRESULT WINAPI 249 MonikerNoROTData_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) 250 { 251 if (!ppvObject) 252 return E_INVALIDARG; 253 254 *ppvObject = 0; 255 256 if (IsEqualIID(&IID_IUnknown, riid) || 257 IsEqualIID(&IID_IPersist, riid) || 258 IsEqualIID(&IID_IPersistStream,riid) || 259 IsEqualIID(&IID_IMoniker, riid)) 260 *ppvObject = iface; 261 if (IsEqualIID(&IID_IROTData, riid)) 262 CHECK_EXPECTED_METHOD("Moniker_QueryInterface(IID_IROTData)"); 263 264 if ((*ppvObject)==0) 265 return E_NOINTERFACE; 266 267 IMoniker_AddRef(iface); 268 269 return S_OK; 270 } 271 272 static ULONG WINAPI 273 Moniker_AddRef(IMoniker* iface) 274 { 275 return 2; 276 } 277 278 static ULONG WINAPI 279 Moniker_Release(IMoniker* iface) 280 { 281 return 1; 282 } 283 284 static HRESULT WINAPI 285 Moniker_GetClassID(IMoniker* iface, CLSID *pClassID) 286 { 287 CHECK_EXPECTED_METHOD("Moniker_GetClassID"); 288 289 *pClassID = CLSID_TestMoniker; 290 291 return S_OK; 292 } 293 294 static HRESULT WINAPI 295 Moniker_IsDirty(IMoniker* iface) 296 { 297 CHECK_EXPECTED_METHOD("Moniker_IsDirty"); 298 299 return S_FALSE; 300 } 301 302 static HRESULT WINAPI 303 Moniker_Load(IMoniker* iface, IStream* pStm) 304 { 305 CHECK_EXPECTED_METHOD("Moniker_Load"); 306 return E_NOTIMPL; 307 } 308 309 static HRESULT WINAPI 310 Moniker_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty) 311 { 312 CHECK_EXPECTED_METHOD("Moniker_Save"); 313 return E_NOTIMPL; 314 } 315 316 static HRESULT WINAPI 317 Moniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize) 318 { 319 CHECK_EXPECTED_METHOD("Moniker_GetSizeMax"); 320 return E_NOTIMPL; 321 } 322 323 static HRESULT WINAPI 324 Moniker_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, 325 REFIID riid, VOID** ppvResult) 326 { 327 CHECK_EXPECTED_METHOD("Moniker_BindToObject"); 328 return E_NOTIMPL; 329 } 330 331 static HRESULT WINAPI 332 Moniker_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, 333 REFIID riid, VOID** ppvObject) 334 { 335 CHECK_EXPECTED_METHOD("Moniker_BindToStorage"); 336 return E_NOTIMPL; 337 } 338 339 static HRESULT WINAPI 340 Moniker_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, 341 IMoniker** ppmkToLeft, IMoniker** ppmkReduced) 342 { 343 CHECK_EXPECTED_METHOD("Moniker_Reduce"); 344 345 if (ppmkReduced==NULL) 346 return E_POINTER; 347 348 IMoniker_AddRef(iface); 349 350 *ppmkReduced=iface; 351 352 return MK_S_REDUCED_TO_SELF; 353 } 354 355 static HRESULT WINAPI 356 Moniker_ComposeWith(IMoniker* iface, IMoniker* pmkRight, 357 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite) 358 { 359 CHECK_EXPECTED_METHOD("Moniker_ComposeWith"); 360 return E_NOTIMPL; 361 } 362 363 static HRESULT WINAPI 364 Moniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) 365 { 366 CHECK_EXPECTED_METHOD("Moniker_Enum"); 367 368 if (ppenumMoniker == NULL) 369 return E_POINTER; 370 371 *ppenumMoniker = NULL; 372 373 return S_OK; 374 } 375 376 static HRESULT WINAPI 377 Moniker_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) 378 { 379 CHECK_EXPECTED_METHOD("Moniker_IsEqual"); 380 return E_NOTIMPL; 381 } 382 383 static HRESULT WINAPI 384 Moniker_Hash(IMoniker* iface,DWORD* pdwHash) 385 { 386 CHECK_EXPECTED_METHOD("Moniker_Hash"); 387 return E_NOTIMPL; 388 } 389 390 static HRESULT WINAPI 391 Moniker_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, 392 IMoniker* pmkNewlyRunning) 393 { 394 CHECK_EXPECTED_METHOD("Moniker_IsRunning"); 395 return E_NOTIMPL; 396 } 397 398 static HRESULT WINAPI 399 Moniker_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, 400 IMoniker* pmkToLeft, FILETIME* pFileTime) 401 { 402 CHECK_EXPECTED_METHOD("Moniker_GetTimeOfLastChange"); 403 return E_NOTIMPL; 404 } 405 406 static HRESULT WINAPI 407 Moniker_Inverse(IMoniker* iface,IMoniker** ppmk) 408 { 409 CHECK_EXPECTED_METHOD("Moniker_Inverse"); 410 return E_NOTIMPL; 411 } 412 413 static HRESULT WINAPI 414 Moniker_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) 415 { 416 CHECK_EXPECTED_METHOD("Moniker_CommonPrefixWith"); 417 return E_NOTIMPL; 418 } 419 420 static HRESULT WINAPI 421 Moniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) 422 { 423 CHECK_EXPECTED_METHOD("Moniker_RelativePathTo"); 424 return E_NOTIMPL; 425 } 426 427 static HRESULT WINAPI 428 Moniker_GetDisplayName(IMoniker* iface, IBindCtx* pbc, 429 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName) 430 { 431 static const WCHAR wszDisplayName[] = {'*','*','G','e','m','m','a',0}; 432 CHECK_EXPECTED_METHOD("Moniker_GetDisplayName"); 433 *ppszDisplayName = CoTaskMemAlloc(sizeof(wszDisplayName)); 434 memcpy(*ppszDisplayName, wszDisplayName, sizeof(wszDisplayName)); 435 return S_OK; 436 } 437 438 static HRESULT WINAPI 439 Moniker_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, 440 LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut) 441 { 442 CHECK_EXPECTED_METHOD("Moniker_ParseDisplayName"); 443 return E_NOTIMPL; 444 } 445 446 static HRESULT WINAPI 447 Moniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) 448 { 449 CHECK_EXPECTED_METHOD("Moniker_IsSystemMoniker"); 450 451 if (!pwdMksys) 452 return E_POINTER; 453 454 (*pwdMksys)=MKSYS_NONE; 455 456 return S_FALSE; 457 } 458 459 static const IMonikerVtbl MonikerNoROTDataVtbl = 460 { 461 MonikerNoROTData_QueryInterface, 462 Moniker_AddRef, 463 Moniker_Release, 464 Moniker_GetClassID, 465 Moniker_IsDirty, 466 Moniker_Load, 467 Moniker_Save, 468 Moniker_GetSizeMax, 469 Moniker_BindToObject, 470 Moniker_BindToStorage, 471 Moniker_Reduce, 472 Moniker_ComposeWith, 473 Moniker_Enum, 474 Moniker_IsEqual, 475 Moniker_Hash, 476 Moniker_IsRunning, 477 Moniker_GetTimeOfLastChange, 478 Moniker_Inverse, 479 Moniker_CommonPrefixWith, 480 Moniker_RelativePathTo, 481 Moniker_GetDisplayName, 482 Moniker_ParseDisplayName, 483 Moniker_IsSystemMoniker 484 }; 485 486 static IMoniker MonikerNoROTData = { &MonikerNoROTDataVtbl }; 487 488 static IMoniker Moniker; 489 490 static HRESULT WINAPI 491 ROTData_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) 492 { 493 return IMoniker_QueryInterface(&Moniker, riid, ppvObject); 494 } 495 496 static ULONG WINAPI 497 ROTData_AddRef(IROTData *iface) 498 { 499 return 2; 500 } 501 502 static ULONG WINAPI 503 ROTData_Release(IROTData* iface) 504 { 505 return 1; 506 } 507 508 static HRESULT WINAPI 509 ROTData_GetComparisonData(IROTData* iface, BYTE* pbData, 510 ULONG cbMax, ULONG* pcbData) 511 { 512 CHECK_EXPECTED_METHOD("ROTData_GetComparisonData"); 513 514 *pcbData = 1; 515 if (cbMax < *pcbData) 516 return E_OUTOFMEMORY; 517 518 *pbData = 0xde; 519 520 return S_OK; 521 } 522 523 static IROTDataVtbl ROTDataVtbl = 524 { 525 ROTData_QueryInterface, 526 ROTData_AddRef, 527 ROTData_Release, 528 ROTData_GetComparisonData 529 }; 530 531 static IROTData ROTData = { &ROTDataVtbl }; 532 533 static HRESULT WINAPI 534 Moniker_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) 535 { 536 if (!ppvObject) 537 return E_INVALIDARG; 538 539 *ppvObject = 0; 540 541 if (IsEqualIID(&IID_IUnknown, riid) || 542 IsEqualIID(&IID_IPersist, riid) || 543 IsEqualIID(&IID_IPersistStream,riid) || 544 IsEqualIID(&IID_IMoniker, riid)) 545 *ppvObject = iface; 546 if (IsEqualIID(&IID_IROTData, riid)) 547 { 548 CHECK_EXPECTED_METHOD("Moniker_QueryInterface(IID_IROTData)"); 549 *ppvObject = &ROTData; 550 } 551 552 if ((*ppvObject)==0) 553 return E_NOINTERFACE; 554 555 IMoniker_AddRef(iface); 556 557 return S_OK; 558 } 559 560 static const IMonikerVtbl MonikerVtbl = 561 { 562 Moniker_QueryInterface, 563 Moniker_AddRef, 564 Moniker_Release, 565 Moniker_GetClassID, 566 Moniker_IsDirty, 567 Moniker_Load, 568 Moniker_Save, 569 Moniker_GetSizeMax, 570 Moniker_BindToObject, 571 Moniker_BindToStorage, 572 Moniker_Reduce, 573 Moniker_ComposeWith, 574 Moniker_Enum, 575 Moniker_IsEqual, 576 Moniker_Hash, 577 Moniker_IsRunning, 578 Moniker_GetTimeOfLastChange, 579 Moniker_Inverse, 580 Moniker_CommonPrefixWith, 581 Moniker_RelativePathTo, 582 Moniker_GetDisplayName, 583 Moniker_ParseDisplayName, 584 Moniker_IsSystemMoniker 585 }; 586 587 static IMoniker Moniker = { &MonikerVtbl }; 588 589 static void test_ROT(void) 590 { 591 static const WCHAR wszFileName[] = {'B','E','2','0','E','2','F','5','-', 592 '1','9','0','3','-','4','A','A','E','-','B','1','A','F','-', 593 '2','0','4','6','E','5','8','6','C','9','2','5',0}; 594 HRESULT hr; 595 IMoniker *pMoniker = NULL; 596 IRunningObjectTable *pROT = NULL; 597 DWORD dwCookie; 598 static const char *methods_register_no_ROTData[] = 599 { 600 "Moniker_Reduce", 601 "Moniker_GetTimeOfLastChange", 602 "Moniker_QueryInterface(IID_IROTData)", 603 "Moniker_GetDisplayName", 604 "Moniker_GetClassID", 605 NULL 606 }; 607 static const char *methods_register[] = 608 { 609 "Moniker_Reduce", 610 "Moniker_GetTimeOfLastChange", 611 "Moniker_QueryInterface(IID_IROTData)", 612 "ROTData_GetComparisonData", 613 NULL 614 }; 615 static const char *methods_isrunning_no_ROTData[] = 616 { 617 "Moniker_Reduce", 618 "Moniker_QueryInterface(IID_IROTData)", 619 "Moniker_GetDisplayName", 620 "Moniker_GetClassID", 621 NULL 622 }; 623 static const char *methods_isrunning[] = 624 { 625 "Moniker_Reduce", 626 "Moniker_QueryInterface(IID_IROTData)", 627 "ROTData_GetComparisonData", 628 NULL 629 }; 630 631 cLocks = 0; 632 633 hr = GetRunningObjectTable(0, &pROT); 634 ok_ole_success(hr, GetRunningObjectTable); 635 636 expected_method_list = methods_register_no_ROTData; 637 external_connections = 0; 638 /* try with our own moniker that doesn't support IROTData */ 639 hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, 640 (IUnknown*)&Test_ClassFactory, &MonikerNoROTData, &dwCookie); 641 ok_ole_success(hr, IRunningObjectTable_Register); 642 ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); 643 ok(external_connections == 1, "external_connections = %d\n", external_connections); 644 645 ok_more_than_one_lock(); 646 647 expected_method_list = methods_isrunning_no_ROTData; 648 hr = IRunningObjectTable_IsRunning(pROT, &MonikerNoROTData); 649 ok_ole_success(hr, IRunningObjectTable_IsRunning); 650 ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); 651 652 hr = IRunningObjectTable_Revoke(pROT, dwCookie); 653 ok_ole_success(hr, IRunningObjectTable_Revoke); 654 ok(external_connections == 0, "external_connections = %d\n", external_connections); 655 656 ok_no_locks(); 657 658 expected_method_list = methods_register; 659 /* try with our own moniker */ 660 hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, 661 (IUnknown*)&Test_ClassFactory, &Moniker, &dwCookie); 662 ok_ole_success(hr, IRunningObjectTable_Register); 663 ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); 664 665 ok_more_than_one_lock(); 666 667 expected_method_list = methods_isrunning; 668 hr = IRunningObjectTable_IsRunning(pROT, &Moniker); 669 ok_ole_success(hr, IRunningObjectTable_IsRunning); 670 ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list); 671 672 hr = IRunningObjectTable_Revoke(pROT, dwCookie); 673 ok_ole_success(hr, IRunningObjectTable_Revoke); 674 675 ok_no_locks(); 676 677 hr = CreateFileMoniker(wszFileName, &pMoniker); 678 ok_ole_success(hr, CreateClassMoniker); 679 680 /* test flags: 0 */ 681 external_connections = 0; 682 hr = IRunningObjectTable_Register(pROT, 0, (IUnknown*)&Test_ClassFactory, 683 pMoniker, &dwCookie); 684 ok_ole_success(hr, IRunningObjectTable_Register); 685 ok(external_connections == 0, "external_connections = %d\n", external_connections); 686 687 ok_more_than_one_lock(); 688 689 hr = IRunningObjectTable_Revoke(pROT, dwCookie); 690 ok_ole_success(hr, IRunningObjectTable_Revoke); 691 692 ok_no_locks(); 693 694 /* test flags: ROTFLAGS_REGISTRATIONKEEPSALIVE */ 695 hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, 696 (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie); 697 ok_ole_success(hr, IRunningObjectTable_Register); 698 699 ok_more_than_one_lock(); 700 701 hr = IRunningObjectTable_Revoke(pROT, dwCookie); 702 ok_ole_success(hr, IRunningObjectTable_Revoke); 703 704 ok_no_locks(); 705 706 /* test flags: ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT */ 707 /* only succeeds when process is started by SCM and has LocalService 708 * or RunAs AppId values */ 709 hr = IRunningObjectTable_Register(pROT, 710 ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT, 711 (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie); 712 todo_wine { 713 ok(hr == CO_E_WRONG_SERVER_IDENTITY || 714 broken(hr == S_OK) /* Win9x */, 715 "IRunningObjectTable_Register should have returned CO_E_WRONG_SERVER_IDENTITY instead of 0x%08x\n", hr); 716 } 717 if (hr == S_OK) IRunningObjectTable_Revoke(pROT, dwCookie); 718 719 hr = IRunningObjectTable_Register(pROT, 0xdeadbeef, 720 (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie); 721 ok(hr == E_INVALIDARG, "IRunningObjectTable_Register should have returned E_INVALIDARG instead of 0x%08x\n", hr); 722 723 IMoniker_Release(pMoniker); 724 725 IRunningObjectTable_Release(pROT); 726 } 727 728 static void test_ROT_multiple_entries(void) 729 { 730 HRESULT hr; 731 IMoniker *pMoniker = NULL; 732 IRunningObjectTable *pROT = NULL; 733 DWORD dwCookie1, dwCookie2; 734 IUnknown *pObject = NULL; 735 static const WCHAR moniker_path[] = 736 {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0}; 737 738 hr = GetRunningObjectTable(0, &pROT); 739 ok_ole_success(hr, GetRunningObjectTable); 740 741 hr = CreateFileMoniker(moniker_path, &pMoniker); 742 ok_ole_success(hr, CreateFileMoniker); 743 744 hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&Test_ClassFactory, pMoniker, &dwCookie1); 745 ok_ole_success(hr, IRunningObjectTable_Register); 746 747 hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&Test_ClassFactory, pMoniker, &dwCookie2); 748 ok(hr == MK_S_MONIKERALREADYREGISTERED, "IRunningObjectTable_Register should have returned MK_S_MONIKERALREADYREGISTERED instead of 0x%08x\n", hr); 749 750 ok(dwCookie1 != dwCookie2, "cookie returned for registering duplicate object shouldn't match cookie of original object (0x%x)\n", dwCookie1); 751 752 hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject); 753 ok_ole_success(hr, IRunningObjectTable_GetObject); 754 IUnknown_Release(pObject); 755 756 hr = IRunningObjectTable_Revoke(pROT, dwCookie1); 757 ok_ole_success(hr, IRunningObjectTable_Revoke); 758 759 hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject); 760 ok_ole_success(hr, IRunningObjectTable_GetObject); 761 IUnknown_Release(pObject); 762 763 hr = IRunningObjectTable_Revoke(pROT, dwCookie2); 764 ok_ole_success(hr, IRunningObjectTable_Revoke); 765 766 IMoniker_Release(pMoniker); 767 768 IRunningObjectTable_Release(pROT); 769 } 770 771 static HRESULT WINAPI ParseDisplayName_QueryInterface(IParseDisplayName *iface, REFIID riid, void **ppv) 772 { 773 if (IsEqualIID(riid, &IID_IUnknown) || 774 IsEqualIID(riid, &IID_IParseDisplayName)) 775 { 776 *ppv = iface; 777 IParseDisplayName_AddRef(iface); 778 return S_OK; 779 } 780 *ppv = NULL; 781 return E_NOINTERFACE; 782 } 783 784 static ULONG WINAPI ParseDisplayName_AddRef(IParseDisplayName *iface) 785 { 786 return 2; 787 } 788 789 static ULONG WINAPI ParseDisplayName_Release(IParseDisplayName *iface) 790 { 791 return 1; 792 } 793 794 static LPCWSTR expected_display_name; 795 796 static HRESULT WINAPI ParseDisplayName_ParseDisplayName(IParseDisplayName *iface, 797 IBindCtx *pbc, 798 LPOLESTR pszDisplayName, 799 ULONG *pchEaten, 800 IMoniker **ppmkOut) 801 { 802 char display_nameA[256]; 803 WideCharToMultiByte(CP_ACP, 0, pszDisplayName, -1, display_nameA, sizeof(display_nameA), NULL, NULL); 804 ok(!lstrcmpW(pszDisplayName, expected_display_name), "unexpected display name \"%s\"\n", display_nameA); 805 ok(pszDisplayName == expected_display_name, "pszDisplayName should be the same pointer as passed into MkParseDisplayName\n"); 806 *pchEaten = lstrlenW(pszDisplayName); 807 return CreateAntiMoniker(ppmkOut); 808 } 809 810 static const IParseDisplayNameVtbl ParseDisplayName_Vtbl = 811 { 812 ParseDisplayName_QueryInterface, 813 ParseDisplayName_AddRef, 814 ParseDisplayName_Release, 815 ParseDisplayName_ParseDisplayName 816 }; 817 818 static IParseDisplayName ParseDisplayName = { &ParseDisplayName_Vtbl }; 819 820 static int count_moniker_matches(IBindCtx * pbc, IEnumMoniker * spEM) 821 { 822 IMoniker * spMoniker; 823 int monCnt=0, matchCnt=0; 824 825 while ((IEnumMoniker_Next(spEM, 1, &spMoniker, NULL)==S_OK)) 826 { 827 HRESULT hr; 828 WCHAR * szDisplayn; 829 monCnt++; 830 hr=IMoniker_GetDisplayName(spMoniker, pbc, NULL, &szDisplayn); 831 if (SUCCEEDED(hr)) 832 { 833 if (!lstrcmpiW(szDisplayn, wszFileName1) || !lstrcmpiW(szDisplayn, wszFileName2)) 834 matchCnt++; 835 CoTaskMemFree(szDisplayn); 836 } 837 } 838 trace("Total number of monikers is %i\n", monCnt); 839 return matchCnt; 840 } 841 842 static void test_MkParseDisplayName(void) 843 { 844 IBindCtx * pbc = NULL; 845 HRESULT hr; 846 IMoniker * pmk = NULL; 847 IMoniker * pmk1 = NULL; 848 IMoniker * pmk2 = NULL; 849 ULONG eaten; 850 int matchCnt; 851 IUnknown * object = NULL; 852 853 IUnknown *lpEM1; 854 855 IEnumMoniker *spEM1 = NULL; 856 IEnumMoniker *spEM2 = NULL; 857 IEnumMoniker *spEM3 = NULL; 858 859 DWORD pdwReg1=0; 860 DWORD grflags=0; 861 DWORD pdwReg2=0; 862 DWORD moniker_type; 863 IRunningObjectTable * pprot=NULL; 864 865 /* CLSID of My Computer */ 866 static const WCHAR wszDisplayName[] = {'c','l','s','i','d',':', 867 '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D',':',0}; 868 static const WCHAR wszDisplayNameClsid[] = {'c','l','s','i','d',':',0}; 869 static const WCHAR wszNonExistentProgId[] = {'N','o','n','E','x','i','s','t','e','n','t','P','r','o','g','I','d',':',0}; 870 static const WCHAR wszDisplayNameRunning[] = {'W','i','n','e','T','e','s','t','R','u','n','n','i','n','g',0}; 871 static const WCHAR wszDisplayNameProgId1[] = {'S','t','d','F','o','n','t',':',0}; 872 static const WCHAR wszDisplayNameProgId2[] = {'@','S','t','d','F','o','n','t',0}; 873 static const WCHAR wszDisplayNameProgIdFail[] = {'S','t','d','F','o','n','t',0}; 874 static const WCHAR wszEmpty[] = {0}; 875 char szDisplayNameFile[256]; 876 WCHAR wszDisplayNameFile[256]; 877 int i, len; 878 879 const struct 880 { 881 LPBC *ppbc; 882 LPCOLESTR szDisplayName; 883 LPDWORD pchEaten; 884 LPMONIKER *ppmk; 885 } invalid_parameters[] = 886 { 887 {NULL, NULL, NULL, NULL}, 888 {NULL, NULL, NULL, &pmk}, 889 {NULL, NULL, &eaten, NULL}, 890 {NULL, NULL, &eaten, &pmk}, 891 {NULL, wszEmpty, NULL, NULL}, 892 {NULL, wszEmpty, NULL, &pmk}, 893 {NULL, wszEmpty, &eaten, NULL}, 894 {NULL, wszEmpty, &eaten, &pmk}, 895 {&pbc, NULL, NULL, NULL}, 896 {&pbc, NULL, NULL, &pmk}, 897 {&pbc, NULL, &eaten, NULL}, 898 {&pbc, NULL, &eaten, &pmk}, 899 {&pbc, wszEmpty, NULL, NULL}, 900 {&pbc, wszEmpty, NULL, &pmk}, 901 {&pbc, wszEmpty, &eaten, NULL}, 902 {&pbc, wszEmpty, &eaten, &pmk}, 903 }; 904 905 hr = CreateBindCtx(0, &pbc); 906 ok_ole_success(hr, CreateBindCtx); 907 908 for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++) 909 { 910 eaten = 0xdeadbeef; 911 pmk = (IMoniker *)0xdeadbeef; 912 hr = MkParseDisplayName(invalid_parameters[i].ppbc ? *invalid_parameters[i].ppbc : NULL, 913 invalid_parameters[i].szDisplayName, 914 invalid_parameters[i].pchEaten, 915 invalid_parameters[i].ppmk); 916 ok(hr == E_INVALIDARG, "[%d] MkParseDisplayName should have failed with E_INVALIDARG instead of 0x%08x\n", i, hr); 917 ok(eaten == 0xdeadbeef, "[%d] Processed character count should have been 0xdeadbeef instead of %u\n", i, eaten); 918 ok(pmk == (IMoniker *)0xdeadbeef, "[%d] Output moniker pointer should have been 0xdeadbeef instead of %p\n", i, pmk); 919 } 920 921 eaten = 0xdeadbeef; 922 pmk = (IMoniker *)0xdeadbeef; 923 hr = MkParseDisplayName(pbc, wszNonExistentProgId, &eaten, &pmk); 924 ok(hr == MK_E_SYNTAX || hr == MK_E_CANTOPENFILE /* Win9x */, 925 "MkParseDisplayName should have failed with MK_E_SYNTAX or MK_E_CANTOPENFILE instead of 0x%08x\n", hr); 926 ok(eaten == 0, "Processed character count should have been 0 instead of %u\n", eaten); 927 ok(pmk == NULL, "Output moniker pointer should have been NULL instead of %p\n", pmk); 928 929 /* no special handling of "clsid:" without the string form of the clsid 930 * following */ 931 eaten = 0xdeadbeef; 932 pmk = (IMoniker *)0xdeadbeef; 933 hr = MkParseDisplayName(pbc, wszDisplayNameClsid, &eaten, &pmk); 934 ok(hr == MK_E_SYNTAX || hr == MK_E_CANTOPENFILE /* Win9x */, 935 "MkParseDisplayName should have failed with MK_E_SYNTAX or MK_E_CANTOPENFILE instead of 0x%08x\n", hr); 936 ok(eaten == 0, "Processed character count should have been 0 instead of %u\n", eaten); 937 ok(pmk == NULL, "Output moniker pointer should have been NULL instead of %p\n", pmk); 938 939 /* shows clsid has higher precedence than a running object */ 940 hr = CreateFileMoniker(wszDisplayName, &pmk); 941 ok_ole_success(hr, CreateFileMoniker); 942 hr = IBindCtx_GetRunningObjectTable(pbc, &pprot); 943 ok_ole_success(hr, IBindCtx_GetRunningObjectTable); 944 hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&Test_ClassFactory, pmk, &pdwReg1); 945 ok_ole_success(hr, IRunningObjectTable_Register); 946 IMoniker_Release(pmk); 947 pmk = NULL; 948 hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk); 949 ok_ole_success(hr, MkParseDisplayName); 950 ok(eaten == sizeof(wszDisplayName)/sizeof(WCHAR) - 1, 951 "Processed character count should have been 43 instead of %u\n", eaten); 952 if (pmk) 953 { 954 IMoniker_IsSystemMoniker(pmk, &moniker_type); 955 ok(moniker_type == MKSYS_CLASSMONIKER, "moniker_type was %d instead of MKSYS_CLASSMONIKER\n", moniker_type); 956 IMoniker_Release(pmk); 957 } 958 hr = IRunningObjectTable_Revoke(pprot, pdwReg1); 959 ok_ole_success(hr, IRunningObjectTable_Revoke); 960 IRunningObjectTable_Release(pprot); 961 962 hr = CreateFileMoniker(wszDisplayNameRunning, &pmk); 963 ok_ole_success(hr, CreateFileMoniker); 964 hr = IBindCtx_GetRunningObjectTable(pbc, &pprot); 965 ok_ole_success(hr, IBindCtx_GetRunningObjectTable); 966 hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&Test_ClassFactory, pmk, &pdwReg1); 967 ok_ole_success(hr, IRunningObjectTable_Register); 968 IMoniker_Release(pmk); 969 pmk = NULL; 970 hr = MkParseDisplayName(pbc, wszDisplayNameRunning, &eaten, &pmk); 971 ok_ole_success(hr, MkParseDisplayName); 972 ok(eaten == sizeof(wszDisplayNameRunning)/sizeof(WCHAR) - 1, 973 "Processed character count should have been 15 instead of %u\n", eaten); 974 if (pmk) 975 { 976 IMoniker_IsSystemMoniker(pmk, &moniker_type); 977 ok(moniker_type == MKSYS_FILEMONIKER, "moniker_type was %d instead of MKSYS_FILEMONIKER\n", moniker_type); 978 IMoniker_Release(pmk); 979 } 980 hr = IRunningObjectTable_Revoke(pprot, pdwReg1); 981 ok_ole_success(hr, IRunningObjectTable_Revoke); 982 IRunningObjectTable_Release(pprot); 983 984 hr = CoRegisterClassObject(&CLSID_StdFont, (IUnknown *)&ParseDisplayName, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &pdwReg1); 985 ok_ole_success(hr, CoRegisterClassObject); 986 987 expected_display_name = wszDisplayNameProgId1; 988 hr = MkParseDisplayName(pbc, wszDisplayNameProgId1, &eaten, &pmk); 989 ok_ole_success(hr, MkParseDisplayName); 990 ok(eaten == sizeof(wszDisplayNameProgId1)/sizeof(WCHAR) - 1, 991 "Processed character count should have been 8 instead of %u\n", eaten); 992 if (pmk) 993 { 994 IMoniker_IsSystemMoniker(pmk, &moniker_type); 995 ok(moniker_type == MKSYS_ANTIMONIKER, "moniker_type was %d instead of MKSYS_ANTIMONIKER\n", moniker_type); 996 IMoniker_Release(pmk); 997 } 998 999 expected_display_name = wszDisplayNameProgId2; 1000 hr = MkParseDisplayName(pbc, wszDisplayNameProgId2, &eaten, &pmk); 1001 ok_ole_success(hr, MkParseDisplayName); 1002 ok(eaten == sizeof(wszDisplayNameProgId2)/sizeof(WCHAR) - 1, 1003 "Processed character count should have been 8 instead of %u\n", eaten); 1004 if (pmk) 1005 { 1006 IMoniker_IsSystemMoniker(pmk, &moniker_type); 1007 ok(moniker_type == MKSYS_ANTIMONIKER, "moniker_type was %d instead of MKSYS_ANTIMONIKER\n", moniker_type); 1008 IMoniker_Release(pmk); 1009 } 1010 1011 eaten = 0xdeadbeef; 1012 pmk = (IMoniker *)0xdeadbeef; 1013 hr = MkParseDisplayName(pbc, wszDisplayNameProgIdFail, &eaten, &pmk); 1014 ok(hr == MK_E_SYNTAX || hr == MK_E_CANTOPENFILE /* Win9x */, 1015 "MkParseDisplayName with ProgId without marker should fail with MK_E_SYNTAX or MK_E_CANTOPENFILE instead of 0x%08x\n", hr); 1016 ok(eaten == 0, "Processed character count should have been 0 instead of %u\n", eaten); 1017 ok(pmk == NULL, "Output moniker pointer should have been NULL instead of %p\n", pmk); 1018 1019 hr = CoRevokeClassObject(pdwReg1); 1020 ok_ole_success(hr, CoRevokeClassObject); 1021 1022 GetSystemDirectoryA(szDisplayNameFile, sizeof(szDisplayNameFile)); 1023 strcat(szDisplayNameFile, "\\kernel32.dll"); 1024 len = MultiByteToWideChar(CP_ACP, 0, szDisplayNameFile, -1, wszDisplayNameFile, sizeof(wszDisplayNameFile)/sizeof(wszDisplayNameFile[0])); 1025 hr = MkParseDisplayName(pbc, wszDisplayNameFile, &eaten, &pmk); 1026 ok_ole_success(hr, MkParseDisplayName); 1027 ok(eaten == len - 1, "Processed character count should have been %d instead of %u\n", len - 1, eaten); 1028 if (pmk) 1029 { 1030 IMoniker_IsSystemMoniker(pmk, &moniker_type); 1031 ok(moniker_type == MKSYS_FILEMONIKER, "moniker_type was %d instead of MKSYS_FILEMONIKER\n", moniker_type); 1032 IMoniker_Release(pmk); 1033 } 1034 1035 hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk); 1036 ok_ole_success(hr, MkParseDisplayName); 1037 ok(eaten == sizeof(wszDisplayName)/sizeof(WCHAR) - 1, "Processed character count should have been 43 instead of %u\n", eaten); 1038 1039 if (pmk) 1040 { 1041 hr = IMoniker_BindToObject(pmk, pbc, NULL, &IID_IUnknown, (LPVOID*)&object); 1042 ok_ole_success(hr, IMoniker_BindToObject); 1043 1044 if (SUCCEEDED(hr)) 1045 IUnknown_Release(object); 1046 IMoniker_Release(pmk); 1047 } 1048 IBindCtx_Release(pbc); 1049 1050 /* Test the EnumMoniker interface */ 1051 hr = CreateBindCtx(0, &pbc); 1052 ok_ole_success(hr, CreateBindCtx); 1053 1054 hr = CreateFileMoniker(wszFileName1, &pmk1); 1055 ok(hr==0, "CreateFileMoniker for file hr=%08x\n", hr); 1056 hr = CreateFileMoniker(wszFileName2, &pmk2); 1057 ok(hr==0, "CreateFileMoniker for file hr=%08x\n", hr); 1058 hr = IBindCtx_GetRunningObjectTable(pbc, &pprot); 1059 ok(hr==0, "IBindCtx_GetRunningObjectTable hr=%08x\n", hr); 1060 1061 /* Check EnumMoniker before registering */ 1062 hr = IRunningObjectTable_EnumRunning(pprot, &spEM1); 1063 ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr); 1064 hr = IEnumMoniker_QueryInterface(spEM1, &IID_IUnknown, (void*) &lpEM1); 1065 /* Register a couple of Monikers and check is ok */ 1066 ok(hr==0, "IEnumMoniker_QueryInterface hr %08x %p\n", hr, lpEM1); 1067 1068 matchCnt = count_moniker_matches(pbc, spEM1); 1069 trace("Number of matches is %i\n", matchCnt); 1070 1071 grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE; 1072 hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk1, &pdwReg1); 1073 ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n", 1074 hr, pprot, grflags, lpEM1, pmk1, pdwReg1); 1075 1076 trace("IROT::Register\n"); 1077 grflags=0; 1078 grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE; 1079 hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk2, &pdwReg2); 1080 ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n", hr, 1081 pprot, grflags, lpEM1, pmk2, pdwReg2); 1082 1083 hr = IRunningObjectTable_EnumRunning(pprot, &spEM2); 1084 ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr); 1085 1086 matchCnt = count_moniker_matches(pbc, spEM2); 1087 ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt); 1088 1089 trace("IEnumMoniker::Clone\n"); 1090 IEnumMoniker_Clone(spEM2, &spEM3); 1091 1092 matchCnt = count_moniker_matches(pbc, spEM3); 1093 ok(matchCnt==0, "Number of matches should be equal to 0 not %i\n", matchCnt); 1094 trace("IEnumMoniker::Reset\n"); 1095 IEnumMoniker_Reset(spEM3); 1096 1097 matchCnt = count_moniker_matches(pbc, spEM3); 1098 ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt); 1099 1100 IRunningObjectTable_Revoke(pprot,pdwReg1); 1101 IRunningObjectTable_Revoke(pprot,pdwReg2); 1102 IUnknown_Release(lpEM1); 1103 IEnumMoniker_Release(spEM1); 1104 IEnumMoniker_Release(spEM2); 1105 IEnumMoniker_Release(spEM3); 1106 IMoniker_Release(pmk1); 1107 IMoniker_Release(pmk2); 1108 IRunningObjectTable_Release(pprot); 1109 1110 IBindCtx_Release(pbc); 1111 } 1112 1113 static const LARGE_INTEGER llZero; 1114 1115 static const BYTE expected_class_moniker_marshal_data[] = 1116 { 1117 0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00, 1118 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1119 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1120 0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1121 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1122 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00, 1123 0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00, 1124 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1125 0x00,0x00,0x00,0x00, 1126 }; 1127 1128 static const BYTE expected_class_moniker_saved_data[] = 1129 { 1130 0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00, 1131 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1132 0x00,0x00,0x00,0x00, 1133 }; 1134 1135 static const BYTE expected_class_moniker_comparison_data[] = 1136 { 1137 0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1138 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1139 0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00, 1140 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1141 }; 1142 1143 static const WCHAR expected_class_moniker_display_name[] = 1144 { 1145 'c','l','s','i','d',':','0','0','0','2','E','0','0','5','-','0','0','0', 1146 '0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0', 1147 '0','0','0','0','4','6',':',0 1148 }; 1149 1150 static const BYTE expected_item_moniker_comparison_data[] = 1151 { 1152 0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1153 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1154 0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00, 1155 0x54,0x00,0x00,0x00, 1156 }; 1157 1158 static const BYTE expected_item_moniker_saved_data[] = 1159 { 1160 0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00, 1161 0x00,0x00,0x54,0x65,0x73,0x74,0x00, 1162 }; 1163 1164 static const BYTE expected_item_moniker_marshal_data[] = 1165 { 1166 0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00, 1167 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1168 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1169 0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1170 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1171 0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00, 1172 0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00, 1173 0x00,0x00,0x54,0x65,0x73,0x74,0x00, 1174 }; 1175 1176 static const BYTE expected_anti_moniker_marshal_data[] = 1177 { 1178 0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00, 1179 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1180 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1181 0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1182 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1183 0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00, 1184 0x01,0x00,0x00,0x00, 1185 }; 1186 1187 static const BYTE expected_anti_moniker_saved_data[] = 1188 { 1189 0x01,0x00,0x00,0x00, 1190 }; 1191 1192 static const BYTE expected_anti_moniker_comparison_data[] = 1193 { 1194 0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1195 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1196 0x01,0x00,0x00,0x00, 1197 }; 1198 1199 static const BYTE expected_gc_moniker_marshal_data[] = 1200 { 1201 0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00, 1202 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1203 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1204 0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1205 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1206 0x00,0x00,0x00,0x00,0x2c,0x01,0x00,0x00, 1207 0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00, 1208 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 1209 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1210 0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1211 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1212 0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00, 1213 0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00, 1214 0x00,0x00,0x54,0x65,0x73,0x74,0x00,0x4d, 1215 0x45,0x4f,0x57,0x04,0x00,0x00,0x00,0x0f, 1216 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 1217 0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x04, 1218 0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xc0, 1219 0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00, 1220 0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x02, 1221 0x00,0x00,0x00,0x23,0x00,0x05,0x00,0x00, 1222 0x00,0x57,0x69,0x6e,0x65,0x00, 1223 }; 1224 1225 static const BYTE expected_gc_moniker_saved_data[] = 1226 { 1227 0x02,0x00,0x00,0x00,0x04,0x03,0x00,0x00, 1228 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 1229 0x00,0x00,0x00,0x46,0x02,0x00,0x00,0x00, 1230 0x21,0x00,0x05,0x00,0x00,0x00,0x54,0x65, 1231 0x73,0x74,0x00,0x04,0x03,0x00,0x00,0x00, 1232 0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00, 1233 0x00,0x00,0x46,0x02,0x00,0x00,0x00,0x23, 1234 0x00,0x05,0x00,0x00,0x00,0x57,0x69,0x6e, 1235 0x65,0x00, 1236 }; 1237 1238 static const BYTE expected_gc_moniker_comparison_data[] = 1239 { 1240 0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1241 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1242 0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00, 1243 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46, 1244 0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00, 1245 0x54,0x00,0x00,0x00,0x04,0x03,0x00,0x00, 1246 0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00, 1247 0x00,0x00,0x00,0x46,0x23,0x00,0x57,0x00, 1248 0x49,0x00,0x4e,0x00,0x45,0x00,0x00,0x00, 1249 }; 1250 1251 static void test_moniker( 1252 const char *testname, IMoniker *moniker, 1253 const BYTE *expected_moniker_marshal_data, unsigned int sizeof_expected_moniker_marshal_data, 1254 const BYTE *expected_moniker_saved_data, unsigned int sizeof_expected_moniker_saved_data, 1255 const BYTE *expected_moniker_comparison_data, unsigned int sizeof_expected_moniker_comparison_data, 1256 LPCWSTR expected_display_name) 1257 { 1258 IStream * stream; 1259 IROTData * rotdata; 1260 HRESULT hr; 1261 HGLOBAL hglobal; 1262 LPBYTE moniker_data; 1263 DWORD moniker_size; 1264 DWORD i; 1265 BOOL same; 1266 BYTE buffer[128]; 1267 IMoniker * moniker_proxy; 1268 LPOLESTR display_name; 1269 IBindCtx *bindctx; 1270 1271 hr = IMoniker_IsDirty(moniker); 1272 ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr); 1273 1274 /* Display Name */ 1275 1276 hr = CreateBindCtx(0, &bindctx); 1277 ok_ole_success(hr, CreateBindCtx); 1278 1279 hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name); 1280 ok_ole_success(hr, IMoniker_GetDisplayName); 1281 ok(!lstrcmpW(display_name, expected_display_name), "%s: display name wasn't what was expected\n", testname); 1282 1283 CoTaskMemFree(display_name); 1284 IBindCtx_Release(bindctx); 1285 1286 hr = IMoniker_IsDirty(moniker); 1287 ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr); 1288 1289 /* IROTData::GetComparisonData test */ 1290 1291 hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata); 1292 ok_ole_success(hr, IMoniker_QueryInterface_IID_IROTData); 1293 1294 hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &moniker_size); 1295 ok_ole_success(hr, IROTData_GetComparisonData); 1296 1297 if (hr != S_OK) moniker_size = 0; 1298 1299 /* first check we have the right amount of data */ 1300 ok(moniker_size == sizeof_expected_moniker_comparison_data, 1301 "%s: Size of comparison data differs (expected %d, actual %d)\n", 1302 testname, sizeof_expected_moniker_comparison_data, moniker_size); 1303 1304 /* then do a byte-by-byte comparison */ 1305 same = TRUE; 1306 for (i = 0; i < min(moniker_size, sizeof_expected_moniker_comparison_data); i++) 1307 { 1308 if (expected_moniker_comparison_data[i] != buffer[i]) 1309 { 1310 same = FALSE; 1311 break; 1312 } 1313 } 1314 1315 ok(same, "%s: Comparison data differs\n", testname); 1316 if (!same) 1317 { 1318 for (i = 0; i < moniker_size; i++) 1319 { 1320 if (i % 8 == 0) printf(" "); 1321 printf("0x%02x,", buffer[i]); 1322 if (i % 8 == 7) printf("\n"); 1323 } 1324 printf("\n"); 1325 } 1326 1327 IROTData_Release(rotdata); 1328 1329 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 1330 ok_ole_success(hr, CreateStreamOnHGlobal); 1331 1332 /* Saving */ 1333 1334 hr = IMoniker_Save(moniker, stream, TRUE); 1335 ok_ole_success(hr, IMoniker_Save); 1336 1337 hr = GetHGlobalFromStream(stream, &hglobal); 1338 ok_ole_success(hr, GetHGlobalFromStream); 1339 1340 moniker_size = GlobalSize(hglobal); 1341 1342 moniker_data = GlobalLock(hglobal); 1343 1344 /* first check we have the right amount of data */ 1345 ok(moniker_size == round_global_size(sizeof_expected_moniker_saved_data), 1346 "%s: Size of saved data differs (expected %d, actual %d)\n", 1347 testname, (DWORD)round_global_size(sizeof_expected_moniker_saved_data), moniker_size); 1348 1349 /* then do a byte-by-byte comparison */ 1350 same = TRUE; 1351 for (i = 0; i < min(moniker_size, round_global_size(sizeof_expected_moniker_saved_data)); i++) 1352 { 1353 if (expected_moniker_saved_data[i] != moniker_data[i]) 1354 { 1355 same = FALSE; 1356 break; 1357 } 1358 } 1359 1360 ok(same, "%s: Saved data differs\n", testname); 1361 if (!same) 1362 { 1363 for (i = 0; i < moniker_size; i++) 1364 { 1365 if (i % 8 == 0) printf(" "); 1366 printf("0x%02x,", moniker_data[i]); 1367 if (i % 8 == 7) printf("\n"); 1368 } 1369 printf("\n"); 1370 } 1371 1372 GlobalUnlock(hglobal); 1373 1374 IStream_Release(stream); 1375 1376 /* Marshaling tests */ 1377 1378 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 1379 ok_ole_success(hr, CreateStreamOnHGlobal); 1380 1381 hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); 1382 ok_ole_success(hr, CoMarshalInterface); 1383 1384 hr = GetHGlobalFromStream(stream, &hglobal); 1385 ok_ole_success(hr, GetHGlobalFromStream); 1386 1387 moniker_size = GlobalSize(hglobal); 1388 1389 moniker_data = GlobalLock(hglobal); 1390 1391 /* first check we have the right amount of data */ 1392 ok(moniker_size == round_global_size(sizeof_expected_moniker_marshal_data), 1393 "%s: Size of marshaled data differs (expected %d, actual %d)\n", 1394 testname, (DWORD)round_global_size(sizeof_expected_moniker_marshal_data), moniker_size); 1395 1396 /* then do a byte-by-byte comparison */ 1397 same = TRUE; 1398 if (expected_moniker_marshal_data) 1399 { 1400 for (i = 0; i < min(moniker_size, round_global_size(sizeof_expected_moniker_marshal_data)); i++) 1401 { 1402 if (expected_moniker_marshal_data[i] != moniker_data[i]) 1403 { 1404 same = FALSE; 1405 break; 1406 } 1407 } 1408 } 1409 1410 ok(same, "%s: Marshaled data differs\n", testname); 1411 if (!same) 1412 { 1413 for (i = 0; i < moniker_size; i++) 1414 { 1415 if (i % 8 == 0) printf(" "); 1416 printf("0x%02x,", moniker_data[i]); 1417 if (i % 8 == 7) printf("\n"); 1418 } 1419 printf("\n"); 1420 } 1421 1422 GlobalUnlock(hglobal); 1423 1424 IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL); 1425 hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker_proxy); 1426 ok_ole_success(hr, CoUnmarshalInterface); 1427 1428 IStream_Release(stream); 1429 IMoniker_Release(moniker_proxy); 1430 } 1431 1432 static void test_class_moniker(void) 1433 { 1434 HRESULT hr; 1435 IMoniker *moniker; 1436 DWORD moniker_type; 1437 DWORD hash; 1438 IBindCtx *bindctx; 1439 IMoniker *inverse; 1440 IUnknown *unknown; 1441 FILETIME filetime; 1442 1443 hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker); 1444 ok_ole_success(hr, CreateClassMoniker); 1445 if (!moniker) return; 1446 1447 test_moniker("class moniker", moniker, 1448 expected_class_moniker_marshal_data, sizeof(expected_class_moniker_marshal_data), 1449 expected_class_moniker_saved_data, sizeof(expected_class_moniker_saved_data), 1450 expected_class_moniker_comparison_data, sizeof(expected_class_moniker_comparison_data), 1451 expected_class_moniker_display_name); 1452 1453 /* Hashing */ 1454 1455 hr = IMoniker_Hash(moniker, &hash); 1456 ok_ole_success(hr, IMoniker_Hash); 1457 1458 ok(hash == CLSID_StdComponentCategoriesMgr.Data1, 1459 "Hash value != Data1 field of clsid, instead was 0x%08x\n", 1460 hash); 1461 1462 /* IsSystemMoniker test */ 1463 1464 hr = IMoniker_IsSystemMoniker(moniker, &moniker_type); 1465 ok_ole_success(hr, IMoniker_IsSystemMoniker); 1466 1467 ok(moniker_type == MKSYS_CLASSMONIKER, 1468 "dwMkSys != MKSYS_CLASSMONIKER, instead was 0x%08x\n", 1469 moniker_type); 1470 1471 hr = CreateBindCtx(0, &bindctx); 1472 ok_ole_success(hr, CreateBindCtx); 1473 1474 /* IsRunning test */ 1475 hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL); 1476 ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08x\n", hr); 1477 1478 hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL); 1479 ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08x\n", hr); 1480 1481 hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime); 1482 ok(hr == MK_E_UNAVAILABLE, "IMoniker_GetTimeOfLastChange should return MK_E_UNAVAILABLE, not 0x%08x\n", hr); 1483 1484 hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1485 ok_ole_success(hr, IMoniker_BindToObject); 1486 IUnknown_Release(unknown); 1487 1488 hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1489 ok_ole_success(hr, IMoniker_BindToStorage); 1490 IUnknown_Release(unknown); 1491 1492 IBindCtx_Release(bindctx); 1493 1494 hr = IMoniker_Inverse(moniker, &inverse); 1495 ok_ole_success(hr, IMoniker_Inverse); 1496 IMoniker_Release(inverse); 1497 1498 IMoniker_Release(moniker); 1499 } 1500 1501 static void test_file_moniker(WCHAR* path) 1502 { 1503 IStream *stream; 1504 IMoniker *moniker1 = NULL, *moniker2 = NULL; 1505 HRESULT hr; 1506 1507 hr = CreateFileMoniker(path, &moniker1); 1508 ok_ole_success(hr, CreateFileMoniker); 1509 1510 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 1511 ok_ole_success(hr, CreateStreamOnHGlobal); 1512 1513 /* Marshal */ 1514 hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker1, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); 1515 ok_ole_success(hr, CoMarshalInterface); 1516 1517 /* Rewind */ 1518 hr = IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL); 1519 ok_ole_success(hr, IStream_Seek); 1520 1521 /* Unmarshal */ 1522 hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void**)&moniker2); 1523 ok_ole_success(hr, CoUnmarshalInterface); 1524 1525 hr = IMoniker_IsEqual(moniker1, moniker2); 1526 ok_ole_success(hr, IsEqual); 1527 1528 IStream_Release(stream); 1529 if (moniker1) 1530 IMoniker_Release(moniker1); 1531 if (moniker2) 1532 IMoniker_Release(moniker2); 1533 } 1534 1535 static void test_file_monikers(void) 1536 { 1537 static WCHAR wszFile[][30] = { 1538 {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0}, 1539 {'\\', 'a','b','c','d','e','f','g','\\','h','i','j','k','l','\\','m','n','o','p','q','r','s','t','u','.','m','n','o',0}, 1540 /* These map to themselves in Windows-1252 & 932 (Shift-JIS) */ 1541 {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0}, 1542 /* U+2020 = DAGGER = 0x86 (1252) = 0x813f (932) 1543 * U+20AC = EURO SIGN = 0x80 (1252) = undef (932) 1544 * U+0100 .. = Latin extended-A 1545 */ 1546 {0x20ac, 0x2020, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c, 0}, 1547 }; 1548 1549 int i; 1550 1551 trace("ACP is %u\n", GetACP()); 1552 1553 for (i = 0; i < COUNTOF(wszFile); ++i) 1554 { 1555 int j ; 1556 if (i == 2) 1557 { 1558 BOOL used; 1559 WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, wszFile[i], -1, NULL, 0, NULL, &used ); 1560 if (used) 1561 { 1562 skip("string 2 doesn't round trip in codepage %u\n", GetACP() ); 1563 continue; 1564 } 1565 } 1566 for (j = lstrlenW(wszFile[i]); j > 0; --j) 1567 { 1568 wszFile[i][j] = 0; 1569 test_file_moniker(wszFile[i]); 1570 } 1571 } 1572 } 1573 1574 static void test_item_moniker(void) 1575 { 1576 HRESULT hr; 1577 IMoniker *moniker; 1578 DWORD moniker_type; 1579 DWORD hash; 1580 IBindCtx *bindctx; 1581 IMoniker *inverse; 1582 IUnknown *unknown; 1583 static const WCHAR wszDelimiter[] = {'!',0}; 1584 static const WCHAR wszObjectName[] = {'T','e','s','t',0}; 1585 static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 }; 1586 1587 hr = CreateItemMoniker(wszDelimiter, wszObjectName, &moniker); 1588 ok_ole_success(hr, CreateItemMoniker); 1589 1590 test_moniker("item moniker", moniker, 1591 expected_item_moniker_marshal_data, sizeof(expected_item_moniker_marshal_data), 1592 expected_item_moniker_saved_data, sizeof(expected_item_moniker_saved_data), 1593 expected_item_moniker_comparison_data, sizeof(expected_item_moniker_comparison_data), 1594 expected_display_name); 1595 1596 /* Hashing */ 1597 1598 hr = IMoniker_Hash(moniker, &hash); 1599 ok_ole_success(hr, IMoniker_Hash); 1600 1601 ok(hash == 0x73c, 1602 "Hash value != 0x73c, instead was 0x%08x\n", 1603 hash); 1604 1605 /* IsSystemMoniker test */ 1606 1607 hr = IMoniker_IsSystemMoniker(moniker, &moniker_type); 1608 ok_ole_success(hr, IMoniker_IsSystemMoniker); 1609 1610 ok(moniker_type == MKSYS_ITEMMONIKER, 1611 "dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n", 1612 moniker_type); 1613 1614 hr = CreateBindCtx(0, &bindctx); 1615 ok_ole_success(hr, CreateBindCtx); 1616 1617 /* IsRunning test */ 1618 hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL); 1619 ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr); 1620 1621 hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL); 1622 ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr); 1623 1624 hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1625 ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr); 1626 1627 hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1628 ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr); 1629 1630 IBindCtx_Release(bindctx); 1631 1632 hr = IMoniker_Inverse(moniker, &inverse); 1633 ok_ole_success(hr, IMoniker_Inverse); 1634 IMoniker_Release(inverse); 1635 1636 IMoniker_Release(moniker); 1637 } 1638 1639 static void test_anti_moniker(void) 1640 { 1641 HRESULT hr; 1642 IMoniker *moniker; 1643 DWORD moniker_type; 1644 DWORD hash; 1645 IBindCtx *bindctx; 1646 FILETIME filetime; 1647 IMoniker *inverse; 1648 IUnknown *unknown; 1649 static const WCHAR expected_display_name[] = { '\\','.','.',0 }; 1650 1651 hr = CreateAntiMoniker(&moniker); 1652 ok_ole_success(hr, CreateAntiMoniker); 1653 if (!moniker) return; 1654 1655 test_moniker("anti moniker", moniker, 1656 expected_anti_moniker_marshal_data, sizeof(expected_anti_moniker_marshal_data), 1657 expected_anti_moniker_saved_data, sizeof(expected_anti_moniker_saved_data), 1658 expected_anti_moniker_comparison_data, sizeof(expected_anti_moniker_comparison_data), 1659 expected_display_name); 1660 1661 /* Hashing */ 1662 hr = IMoniker_Hash(moniker, &hash); 1663 ok_ole_success(hr, IMoniker_Hash); 1664 ok(hash == 0x80000001, 1665 "Hash value != 0x80000001, instead was 0x%08x\n", 1666 hash); 1667 1668 /* IsSystemMoniker test */ 1669 hr = IMoniker_IsSystemMoniker(moniker, &moniker_type); 1670 ok_ole_success(hr, IMoniker_IsSystemMoniker); 1671 ok(moniker_type == MKSYS_ANTIMONIKER, 1672 "dwMkSys != MKSYS_ANTIMONIKER, instead was 0x%08x\n", 1673 moniker_type); 1674 1675 hr = IMoniker_Inverse(moniker, &inverse); 1676 ok(hr == MK_E_NOINVERSE, "IMoniker_Inverse should have returned MK_E_NOINVERSE instead of 0x%08x\n", hr); 1677 ok(inverse == NULL, "inverse should have been set to NULL instead of %p\n", inverse); 1678 1679 hr = CreateBindCtx(0, &bindctx); 1680 ok_ole_success(hr, CreateBindCtx); 1681 1682 /* IsRunning test */ 1683 hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL); 1684 ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr); 1685 1686 hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime); 1687 ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr); 1688 1689 hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1690 ok(hr == E_NOTIMPL, "IMoniker_BindToObject should return E_NOTIMPL, not 0x%08x\n", hr); 1691 1692 hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1693 ok(hr == E_NOTIMPL, "IMoniker_BindToStorage should return E_NOTIMPL, not 0x%08x\n", hr); 1694 1695 IBindCtx_Release(bindctx); 1696 1697 IMoniker_Release(moniker); 1698 } 1699 1700 static void test_generic_composite_moniker(void) 1701 { 1702 HRESULT hr; 1703 IMoniker *moniker; 1704 IMoniker *moniker1; 1705 IMoniker *moniker2; 1706 DWORD moniker_type; 1707 DWORD hash; 1708 IBindCtx *bindctx; 1709 FILETIME filetime; 1710 IMoniker *inverse; 1711 IUnknown *unknown; 1712 static const WCHAR wszDelimiter1[] = {'!',0}; 1713 static const WCHAR wszObjectName1[] = {'T','e','s','t',0}; 1714 static const WCHAR wszDelimiter2[] = {'#',0}; 1715 static const WCHAR wszObjectName2[] = {'W','i','n','e',0}; 1716 static const WCHAR expected_display_name[] = { '!','T','e','s','t','#','W','i','n','e',0 }; 1717 1718 hr = CreateItemMoniker(wszDelimiter1, wszObjectName1, &moniker1); 1719 ok_ole_success(hr, CreateItemMoniker); 1720 hr = CreateItemMoniker(wszDelimiter2, wszObjectName2, &moniker2); 1721 ok_ole_success(hr, CreateItemMoniker); 1722 hr = CreateGenericComposite(moniker1, moniker2, &moniker); 1723 ok_ole_success(hr, CreateGenericComposite); 1724 1725 test_moniker("generic composite moniker", moniker, 1726 expected_gc_moniker_marshal_data, sizeof(expected_gc_moniker_marshal_data), 1727 expected_gc_moniker_saved_data, sizeof(expected_gc_moniker_saved_data), 1728 expected_gc_moniker_comparison_data, sizeof(expected_gc_moniker_comparison_data), 1729 expected_display_name); 1730 1731 /* Hashing */ 1732 1733 hr = IMoniker_Hash(moniker, &hash); 1734 ok_ole_success(hr, IMoniker_Hash); 1735 1736 ok(hash == 0xd87, 1737 "Hash value != 0xd87, instead was 0x%08x\n", 1738 hash); 1739 1740 /* IsSystemMoniker test */ 1741 1742 hr = IMoniker_IsSystemMoniker(moniker, &moniker_type); 1743 ok_ole_success(hr, IMoniker_IsSystemMoniker); 1744 1745 ok(moniker_type == MKSYS_GENERICCOMPOSITE, 1746 "dwMkSys != MKSYS_GENERICCOMPOSITE, instead was 0x%08x\n", 1747 moniker_type); 1748 1749 hr = CreateBindCtx(0, &bindctx); 1750 ok_ole_success(hr, CreateBindCtx); 1751 1752 /* IsRunning test */ 1753 hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL); 1754 ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr); 1755 1756 hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL); 1757 todo_wine 1758 ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr); 1759 1760 hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime); 1761 ok(hr == MK_E_NOTBINDABLE, "IMoniker_GetTimeOfLastChange should return MK_E_NOTBINDABLE, not 0x%08x\n", hr); 1762 1763 hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1764 todo_wine 1765 ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr); 1766 1767 hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1768 ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr); 1769 1770 IBindCtx_Release(bindctx); 1771 1772 hr = IMoniker_Inverse(moniker, &inverse); 1773 ok_ole_success(hr, IMoniker_Inverse); 1774 IMoniker_Release(inverse); 1775 1776 IMoniker_Release(moniker); 1777 } 1778 1779 static void test_pointer_moniker(void) 1780 { 1781 HRESULT hr; 1782 IMoniker *moniker; 1783 DWORD moniker_type; 1784 DWORD hash; 1785 IBindCtx *bindctx; 1786 FILETIME filetime; 1787 IMoniker *inverse; 1788 IUnknown *unknown; 1789 IStream *stream; 1790 IROTData *rotdata; 1791 LPOLESTR display_name; 1792 1793 cLocks = 0; 1794 1795 hr = CreatePointerMoniker((IUnknown *)&Test_ClassFactory, NULL); 1796 ok(hr == E_INVALIDARG, "CreatePointerMoniker(x, NULL) should have returned E_INVALIDARG instead of 0x%08x\n", hr); 1797 1798 hr = CreatePointerMoniker((IUnknown *)&Test_ClassFactory, &moniker); 1799 ok_ole_success(hr, CreatePointerMoniker); 1800 if (!moniker) return; 1801 1802 ok_more_than_one_lock(); 1803 1804 /* Display Name */ 1805 1806 hr = CreateBindCtx(0, &bindctx); 1807 ok_ole_success(hr, CreateBindCtx); 1808 1809 hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name); 1810 ok(hr == E_NOTIMPL, "IMoniker_GetDisplayName should have returned E_NOTIMPL instead of 0x%08x\n", hr); 1811 1812 IBindCtx_Release(bindctx); 1813 1814 hr = IMoniker_IsDirty(moniker); 1815 ok(hr == S_FALSE, "IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", hr); 1816 1817 /* IROTData::GetComparisonData test */ 1818 1819 hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata); 1820 ok(hr == E_NOINTERFACE, "IMoniker_QueryInterface(IID_IROTData) should have returned E_NOINTERFACE instead of 0x%08x\n", hr); 1821 1822 /* Saving */ 1823 1824 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); 1825 ok_ole_success(hr, CreateStreamOnHGlobal); 1826 1827 hr = IMoniker_Save(moniker, stream, TRUE); 1828 ok(hr == E_NOTIMPL, "IMoniker_Save should have returned E_NOTIMPL instead of 0x%08x\n", hr); 1829 1830 IStream_Release(stream); 1831 1832 /* Hashing */ 1833 hr = IMoniker_Hash(moniker, &hash); 1834 ok_ole_success(hr, IMoniker_Hash); 1835 ok(hash == PtrToUlong(&Test_ClassFactory), 1836 "Hash value should have been 0x%08x, instead of 0x%08x\n", 1837 PtrToUlong(&Test_ClassFactory), hash); 1838 1839 /* IsSystemMoniker test */ 1840 hr = IMoniker_IsSystemMoniker(moniker, &moniker_type); 1841 ok_ole_success(hr, IMoniker_IsSystemMoniker); 1842 ok(moniker_type == MKSYS_POINTERMONIKER, 1843 "dwMkSys != MKSYS_POINTERMONIKER, instead was 0x%08x\n", 1844 moniker_type); 1845 1846 hr = IMoniker_Inverse(moniker, &inverse); 1847 ok_ole_success(hr, IMoniker_Inverse); 1848 IMoniker_Release(inverse); 1849 1850 hr = CreateBindCtx(0, &bindctx); 1851 ok_ole_success(hr, CreateBindCtx); 1852 1853 /* IsRunning test */ 1854 hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL); 1855 ok(hr == S_OK, "IMoniker_IsRunning should return S_OK, not 0x%08x\n", hr); 1856 1857 hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime); 1858 ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr); 1859 1860 hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1861 ok_ole_success(hr, IMoniker_BindToObject); 1862 IUnknown_Release(unknown); 1863 1864 hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1865 ok_ole_success(hr, IMoniker_BindToStorage); 1866 IUnknown_Release(unknown); 1867 1868 IMoniker_Release(moniker); 1869 1870 ok_no_locks(); 1871 1872 hr = CreatePointerMoniker(NULL, &moniker); 1873 ok_ole_success(hr, CreatePointerMoniker); 1874 1875 hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1876 ok(hr == E_UNEXPECTED, "IMoniker_BindToObject should have returned E_UNEXPECTED instead of 0x%08x\n", hr); 1877 1878 hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown); 1879 ok(hr == E_UNEXPECTED, "IMoniker_BindToStorage should have returned E_UNEXPECTED instead of 0x%08x\n", hr); 1880 1881 IBindCtx_Release(bindctx); 1882 1883 IMoniker_Release(moniker); 1884 } 1885 1886 static void test_bind_context(void) 1887 { 1888 HRESULT hr; 1889 IBindCtx *pBindCtx; 1890 IEnumString *pEnumString; 1891 BIND_OPTS2 bind_opts; 1892 HeapUnknown *unknown; 1893 HeapUnknown *unknown2; 1894 IUnknown *param_obj; 1895 ULONG refs; 1896 static const WCHAR wszParamName[] = {'G','e','m','m','a',0}; 1897 static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0}; 1898 1899 hr = CreateBindCtx(0, NULL); 1900 ok(hr == E_INVALIDARG, "CreateBindCtx with NULL ppbc should have returned E_INVALIDARG instead of 0x%08x\n", hr); 1901 1902 hr = CreateBindCtx(0xdeadbeef, &pBindCtx); 1903 ok(hr == E_INVALIDARG, "CreateBindCtx with reserved value non-zero should have returned E_INVALIDARG instead of 0x%08x\n", hr); 1904 1905 hr = CreateBindCtx(0, &pBindCtx); 1906 ok_ole_success(hr, "CreateBindCtx"); 1907 1908 bind_opts.cbStruct = -1; 1909 hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts); 1910 ok_ole_success(hr, "IBindCtx_GetBindOptions"); 1911 ok(bind_opts.cbStruct == sizeof(bind_opts) || 1912 bind_opts.cbStruct == sizeof(bind_opts) + sizeof(void*), /* Vista */ 1913 "bind_opts.cbStruct was %d\n", bind_opts.cbStruct); 1914 1915 bind_opts.cbStruct = sizeof(BIND_OPTS); 1916 hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts); 1917 ok_ole_success(hr, "IBindCtx_GetBindOptions"); 1918 ok(bind_opts.cbStruct == sizeof(BIND_OPTS), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct); 1919 1920 bind_opts.cbStruct = sizeof(bind_opts); 1921 hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts); 1922 ok_ole_success(hr, "IBindCtx_GetBindOptions"); 1923 ok(bind_opts.cbStruct == sizeof(bind_opts), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct); 1924 ok(bind_opts.grfFlags == 0, "bind_opts.grfFlags was 0x%x instead of 0\n", bind_opts.grfFlags); 1925 ok(bind_opts.grfMode == STGM_READWRITE, "bind_opts.grfMode was 0x%x instead of STGM_READWRITE\n", bind_opts.grfMode); 1926 ok(bind_opts.dwTickCountDeadline == 0, "bind_opts.dwTickCountDeadline was %d instead of 0\n", bind_opts.dwTickCountDeadline); 1927 ok(bind_opts.dwTrackFlags == 0, "bind_opts.dwTrackFlags was 0x%x instead of 0\n", bind_opts.dwTrackFlags); 1928 ok(bind_opts.dwClassContext == (CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER), 1929 "bind_opts.dwClassContext should have been 0x15 instead of 0x%x\n", bind_opts.dwClassContext); 1930 ok(bind_opts.locale == GetThreadLocale(), "bind_opts.locale should have been 0x%x instead of 0x%x\n", GetThreadLocale(), bind_opts.locale); 1931 ok(bind_opts.pServerInfo == NULL, "bind_opts.pServerInfo should have been NULL instead of %p\n", bind_opts.pServerInfo); 1932 1933 bind_opts.cbStruct = -1; 1934 hr = IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts); 1935 ok(hr == E_INVALIDARG, "IBindCtx_SetBindOptions with bad cbStruct should have returned E_INVALIDARG instead of 0x%08x\n", hr); 1936 1937 hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, NULL); 1938 ok(hr == E_INVALIDARG, "IBindCtx_RegisterObjectParam should have returned E_INVALIDARG instead of 0x%08x\n", hr); 1939 1940 unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown)); 1941 unknown->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl; 1942 unknown->refs = 1; 1943 hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, &unknown->IUnknown_iface); 1944 ok_ole_success(hr, "IBindCtx_RegisterObjectParam"); 1945 1946 hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszParamName, ¶m_obj); 1947 ok_ole_success(hr, "IBindCtx_GetObjectParam"); 1948 IUnknown_Release(param_obj); 1949 1950 hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszNonExistent, ¶m_obj); 1951 ok(hr == E_FAIL, "IBindCtx_GetObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08x\n", hr); 1952 ok(param_obj == NULL, "IBindCtx_GetObjectParam with nonexistent key should have set output parameter to NULL instead of %p\n", param_obj); 1953 1954 hr = IBindCtx_RevokeObjectParam(pBindCtx, (WCHAR *)wszNonExistent); 1955 ok(hr == E_FAIL, "IBindCtx_RevokeObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08x\n", hr); 1956 1957 hr = IBindCtx_EnumObjectParam(pBindCtx, &pEnumString); 1958 ok(hr == E_NOTIMPL, "IBindCtx_EnumObjectParam should have returned E_NOTIMPL instead of 0x%08x\n", hr); 1959 ok(!pEnumString, "pEnumString should be NULL\n"); 1960 1961 hr = IBindCtx_RegisterObjectBound(pBindCtx, NULL); 1962 ok_ole_success(hr, "IBindCtx_RegisterObjectBound(NULL)"); 1963 1964 hr = IBindCtx_RevokeObjectBound(pBindCtx, NULL); 1965 ok(hr == E_INVALIDARG, "IBindCtx_RevokeObjectBound(NULL) should have return E_INVALIDARG instead of 0x%08x\n", hr); 1966 1967 unknown2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown)); 1968 unknown2->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl; 1969 unknown2->refs = 1; 1970 hr = IBindCtx_RegisterObjectBound(pBindCtx, &unknown2->IUnknown_iface); 1971 ok_ole_success(hr, "IBindCtx_RegisterObjectBound"); 1972 1973 hr = IBindCtx_RevokeObjectBound(pBindCtx, &unknown2->IUnknown_iface); 1974 ok_ole_success(hr, "IBindCtx_RevokeObjectBound"); 1975 1976 hr = IBindCtx_RevokeObjectBound(pBindCtx, &unknown2->IUnknown_iface); 1977 ok(hr == MK_E_NOTBOUND, "IBindCtx_RevokeObjectBound with not bound object should have returned MK_E_NOTBOUND instead of 0x%08x\n", hr); 1978 1979 IBindCtx_Release(pBindCtx); 1980 1981 refs = IUnknown_Release(&unknown->IUnknown_iface); 1982 ok(!refs, "object param should have been destroyed, instead of having %d refs\n", refs); 1983 1984 refs = IUnknown_Release(&unknown2->IUnknown_iface); 1985 ok(!refs, "bound object should have been destroyed, instead of having %d refs\n", refs); 1986 } 1987 1988 static void test_save_load_filemoniker(void) 1989 { 1990 IMoniker* pMk; 1991 IStream* pStm; 1992 HRESULT hr; 1993 ULARGE_INTEGER size; 1994 LARGE_INTEGER zero_pos, dead_pos, nulls_pos; 1995 DWORD some_val = 0xFEDCBA98; 1996 int i; 1997 1998 /* see FileMonikerImpl_Save docs */ 1999 zero_pos.QuadPart = 0; 2000 dead_pos.QuadPart = sizeof(WORD) + sizeof(DWORD) + (lstrlenW(wszFileName1) + 1) + sizeof(WORD); 2001 nulls_pos.QuadPart = dead_pos.QuadPart + sizeof(WORD); 2002 2003 /* create the stream we're going to write to */ 2004 hr = CreateStreamOnHGlobal(NULL, TRUE, &pStm); 2005 ok_ole_success(hr, "CreateStreamOnHGlobal"); 2006 2007 size.u.LowPart = 128; 2008 hr = IStream_SetSize(pStm, size); 2009 ok_ole_success(hr, "IStream_SetSize"); 2010 2011 /* create and save a moniker */ 2012 hr = CreateFileMoniker(wszFileName1, &pMk); 2013 ok_ole_success(hr, "CreateFileMoniker"); 2014 2015 hr = IMoniker_Save(pMk, pStm, TRUE); 2016 ok_ole_success(hr, "IMoniker_Save"); 2017 IMoniker_Release(pMk); 2018 2019 /* overwrite the constants with various values */ 2020 hr = IStream_Seek(pStm, zero_pos, STREAM_SEEK_SET, NULL); 2021 ok_ole_success(hr, "IStream_Seek"); 2022 hr = IStream_Write(pStm, &some_val, sizeof(WORD), NULL); 2023 ok_ole_success(hr, "IStream_Write"); 2024 2025 hr = IStream_Seek(pStm, dead_pos, STREAM_SEEK_SET, NULL); 2026 ok_ole_success(hr, "IStream_Seek"); 2027 hr = IStream_Write(pStm, &some_val, sizeof(WORD), NULL); 2028 ok_ole_success(hr, "IStream_Write"); 2029 2030 hr = IStream_Seek(pStm, nulls_pos, STREAM_SEEK_SET, NULL); 2031 ok_ole_success(hr, "IStream_Seek"); 2032 for(i = 0; i < 5; ++i){ 2033 hr = IStream_Write(pStm, &some_val, sizeof(DWORD), NULL); 2034 ok_ole_success(hr, "IStream_Write"); 2035 } 2036 2037 /* go back to the start of the stream */ 2038 hr = IStream_Seek(pStm, zero_pos, STREAM_SEEK_SET, NULL); 2039 ok_ole_success(hr, "IStream_Seek"); 2040 2041 /* create a new moniker and load into it */ 2042 hr = CreateFileMoniker(wszFileName1, &pMk); 2043 ok_ole_success(hr, "CreateFileMoniker"); 2044 2045 hr = IMoniker_Load(pMk, pStm); 2046 ok_ole_success(hr, "IMoniker_Load"); 2047 2048 IMoniker_Release(pMk); 2049 IStream_Release(pStm); 2050 } 2051 2052 START_TEST(moniker) 2053 { 2054 if (!GetProcAddress(GetModuleHandleA("ole32.dll"), "CoRegisterSurrogateEx")) { 2055 win_skip("skipping test on win9x\n"); 2056 return; 2057 } 2058 2059 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 2060 2061 test_ROT(); 2062 test_ROT_multiple_entries(); 2063 test_MkParseDisplayName(); 2064 test_class_moniker(); 2065 test_file_monikers(); 2066 test_item_moniker(); 2067 test_anti_moniker(); 2068 test_generic_composite_moniker(); 2069 test_pointer_moniker(); 2070 test_save_load_filemoniker(); 2071 2072 /* FIXME: test moniker creation funcs and parsing other moniker formats */ 2073 2074 test_bind_context(); 2075 2076 CoUninitialize(); 2077 } 2078