moniker.c 162 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Moniker Tests
 *
 * Copyright 2004 Robert Shearman
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22
 */

#define _WIN32_DCOM
#define COBJMACROS
23
#define CONST_VTABLE
24 25

#include <stdarg.h>
26
#include <stdio.h>
27 28 29 30

#include "windef.h"
#include "winbase.h"
#include "objbase.h"
31
#include "ocidl.h"
Robert Shearman's avatar
Robert Shearman committed
32
#include "comcat.h"
33
#include "olectl.h"
34
#include "initguid.h"
35 36

#include "wine/test.h"
37
#include "wine/heap.h"
38

39 40 41 42 43 44 45 46 47 48
#define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOOL supported)
{
    IUnknown *iface = iface_ptr;
    HRESULT hr, expected_hr;
    IUnknown *unk;

    expected_hr = supported ? S_OK : E_NOINTERFACE;

    hr = IUnknown_QueryInterface(iface, iid, (void **)&unk);
49
    ok_(__FILE__, line)(hr == expected_hr, "Got hr %#lx, expected %#lx.\n", hr, expected_hr);
50 51 52 53
    if (SUCCEEDED(hr))
        IUnknown_Release(unk);
}

54
#define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error %#08lx\n", hr)
55

56
static char const * const *expected_method_list;
57 58 59 60 61 62 63 64 65 66 67 68 69 70

#define CHECK_EXPECTED_METHOD(method_name) check_expected_method_(__LINE__, method_name)
static void check_expected_method_(unsigned int line, const char *method_name)
{
    if (!expected_method_list) return;
    ok(*expected_method_list != NULL, "Extra method %s called\n", method_name);
    if (*expected_method_list)
    {
        ok(!strcmp(*expected_method_list, method_name), "Expected %s to be called instead of %s\n",
                *expected_method_list, method_name);
        expected_method_list++;
    }
}

71 72 73
static const WCHAR wszFileName1[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','1','.','d','o','c',0};
static const WCHAR wszFileName2[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','2','.','d','o','c',0};

74 75 76 77 78 79 80 81
static const CLSID CLSID_TestMoniker =
{ /* b306bfbc-496e-4f53-b93e-2ff9c83223d7 */
    0xb306bfbc,
    0x496e,
    0x4f53,
    {0xb9, 0x3e, 0x2f, 0xf9, 0xc8, 0x32, 0x23, 0xd7}
};

82 83 84
DEFINE_OLEGUID(CLSID_FileMoniker,      0x303, 0, 0);
DEFINE_OLEGUID(CLSID_ItemMoniker,      0x304, 0, 0);
DEFINE_OLEGUID(CLSID_AntiMoniker,      0x305, 0, 0);
85
DEFINE_OLEGUID(CLSID_PointerMoniker,   0x306, 0, 0);
86 87
DEFINE_OLEGUID(CLSID_CompositeMoniker, 0x309, 0, 0);
DEFINE_OLEGUID(CLSID_ClassMoniker,     0x31a, 0, 0);
88
DEFINE_OLEGUID(CLSID_ObjrefMoniker,    0x327, 0, 0);
89

90 91 92 93 94 95 96 97
#define TEST_MONIKER_TYPE_TODO(m,t) _test_moniker_type(m, t, TRUE, __LINE__)
#define TEST_MONIKER_TYPE(m,t) _test_moniker_type(m, t, FALSE, __LINE__)
static void _test_moniker_type(IMoniker *moniker, DWORD type, BOOL todo, int line)
{
    DWORD type2;
    HRESULT hr;

    hr = IMoniker_IsSystemMoniker(moniker, &type2);
98
    ok_(__FILE__, line)(hr == S_OK, "Unexpected hr %#lx.\n", hr);
99
    todo_wine_if(todo)
100
    ok_(__FILE__, line)(type2 == type, "Unexpected moniker type %ld.\n", type2);
101 102
}

103 104 105 106 107 108 109 110
#define TEST_DISPLAY_NAME(m,name) _test_moniker_name(m, name, __LINE__)
static void _test_moniker_name(IMoniker *moniker, const WCHAR *name, int line)
{
    WCHAR *display_name;
    IBindCtx *pbc;
    HRESULT hr;

    hr = CreateBindCtx(0, &pbc);
111
    ok_(__FILE__, line)(hr == S_OK, "Failed to create bind context, hr %#lx.\n", hr);
112 113

    hr = IMoniker_GetDisplayName(moniker, pbc, NULL, &display_name);
114
    ok_(__FILE__, line)(hr == S_OK, "Failed to get display name, hr %#lx.\n", hr);
115 116 117 118 119 120
    ok_(__FILE__, line)(!lstrcmpW(display_name, name), "Unexpected display name %s.\n", wine_dbgstr_w(display_name));

    CoTaskMemFree(display_name);
    IBindCtx_Release(pbc);
}

121 122 123 124 125 126 127 128
static IMoniker *create_antimoniker(DWORD level)
{
    LARGE_INTEGER pos;
    IMoniker *moniker;
    IStream *stream;
    HRESULT hr;

    hr = CreateAntiMoniker(&moniker);
129
    ok(hr == S_OK, "Failed to create antimoniker, hr %#lx.\n", hr);
130 131

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
132
    ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
133 134

    hr = IStream_Write(stream, &level, sizeof(level), NULL);
135
    ok(hr == S_OK, "Failed to write contents, hr %#lx.\n", hr);
136 137 138

    pos.QuadPart = 0;
    hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
139
    ok(hr == S_OK, "Failed to rewind, hr %#lx.\n", hr);
140 141

    hr = IMoniker_Load(moniker, stream);
142
    ok(hr == S_OK, "Failed to load, hr %#lx.\n", hr);
143 144 145 146 147 148

    IStream_Release(stream);

    return moniker;
}

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
static HRESULT WINAPI pointer_moniker_obj_QueryInterface(IUnknown *iface,
        REFIID riid, void **obj)
{
    if (IsEqualIID(riid, &IID_IUnknown))
    {
        *obj = iface;
        return S_OK;
    }

    *obj = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI pointer_moniker_obj_AddRef(IUnknown *iface)
{
    return 2;
}

static ULONG WINAPI pointer_moniker_obj_Release(IUnknown *iface)
{
    return 1;
}

static const IUnknownVtbl pointer_moniker_obj_vtbl =
{
    pointer_moniker_obj_QueryInterface,
    pointer_moniker_obj_AddRef,
    pointer_moniker_obj_Release,
};

static IUnknown pm_obj = { &pointer_moniker_obj_vtbl };

181
static HRESULT create_moniker_parse_desc(const char *desc, unsigned int *eaten,
182 183
        IMoniker **moniker)
{
184 185
    unsigned int comp_len = 0;
    WCHAR itemnameW[3] = L"Ix";
186 187 188 189 190 191
    IMoniker *left, *right;
    HRESULT hr;

    switch (*desc)
    {
        case 'I':
192 193 194
            itemnameW[1] = desc[1];
            *eaten = 2;
            return CreateItemMoniker(L"!", itemnameW, moniker);
195
        case 'A':
196
            *eaten = 2;
197 198
            *moniker = create_antimoniker(desc[1] - '0');
            return S_OK;
199 200 201
        case 'P':
            *eaten = 1;
            return CreatePointerMoniker(&pm_obj, moniker);
202
        case 'C':
203 204 205 206 207
            *eaten = 1;
            desc++;

            comp_len = 0;
            hr = create_moniker_parse_desc(desc, &comp_len, &left);
208
            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
209 210 211 212 213 214

            *eaten += comp_len;
            desc += comp_len;

            comp_len = 0;
            hr = create_moniker_parse_desc(desc, &comp_len, &right);
215
            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
216 217 218

            *eaten += comp_len;

219 220 221 222 223 224 225 226 227 228
            hr = CreateGenericComposite(left, right, moniker);
            IMoniker_Release(left);
            IMoniker_Release(right);
            return hr;
        default:
            ok(0, "Unexpected description %s.\n", desc);
            return E_NOTIMPL;
    }
}

229 230 231 232 233 234
static HRESULT create_moniker_from_desc(const char *desc, IMoniker **moniker)
{
    unsigned int eaten = 0;
    return create_moniker_parse_desc(desc, &eaten, moniker);
}

235
static SIZE_T round_global_size(SIZE_T size)
236
{
237 238
    static SIZE_T global_size_alignment = -1;
    if (global_size_alignment == -1)
239
    {
240 241 242
        void *p = GlobalAlloc(GMEM_FIXED, 1);
        global_size_alignment = GlobalSize(p);
        GlobalFree(p);
243 244
    }

245
    return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1));
246 247
}

248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
struct test_factory
{
    IClassFactory IClassFactory_iface;
    IExternalConnection IExternalConnection_iface;
    LONG refcount;
    unsigned int external_connections;
};

static struct test_factory *impl_from_IClassFactory(IClassFactory *iface)
{
    return CONTAINING_RECORD(iface, struct test_factory, IClassFactory_iface);
}

static struct test_factory *impl_from_IExternalConnection(IExternalConnection *iface)
{
    return CONTAINING_RECORD(iface, struct test_factory, IExternalConnection_iface);
}
265 266 267

static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv)
{
268
    ok(0, "unexpected call\n");
269 270 271 272 273 274
    *ppv = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI ExternalConnection_AddRef(IExternalConnection *iface)
{
275 276
    struct test_factory *factory = impl_from_IExternalConnection(iface);
    return IClassFactory_AddRef(&factory->IClassFactory_iface);
277 278 279 280
}

static ULONG WINAPI ExternalConnection_Release(IExternalConnection *iface)
{
281 282
    struct test_factory *factory = impl_from_IExternalConnection(iface);
    return IClassFactory_Release(&factory->IClassFactory_iface);
283 284 285 286
}

static DWORD WINAPI ExternalConnection_AddConnection(IExternalConnection *iface, DWORD extconn, DWORD reserved)
{
287
    struct test_factory *factory = impl_from_IExternalConnection(iface);
288 289
    ok(extconn == EXTCONN_STRONG, "Unexpected connection type %ld\n", extconn);
    ok(!reserved, "reserved = %lx\n", reserved);
290
    return ++factory->external_connections;
291 292 293 294 295
}

static DWORD WINAPI ExternalConnection_ReleaseConnection(IExternalConnection *iface, DWORD extconn,
        DWORD reserved, BOOL fLastReleaseCloses)
{
296
    struct test_factory *factory = impl_from_IExternalConnection(iface);
297 298
    ok(extconn == EXTCONN_STRONG, "Unexpected connection type %ld\n", extconn);
    ok(!reserved, "reserved = %lx\n", reserved);
299
    return --factory->external_connections;
300 301 302 303 304 305 306 307 308 309
}

static const IExternalConnectionVtbl ExternalConnectionVtbl = {
    ExternalConnection_QueryInterface,
    ExternalConnection_AddRef,
    ExternalConnection_Release,
    ExternalConnection_AddConnection,
    ExternalConnection_ReleaseConnection
};

310
static HRESULT WINAPI test_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
311
{
312 313 314
    struct test_factory *factory = impl_from_IClassFactory(iface);

    if (!obj) return E_POINTER;
315 316 317 318

    if (IsEqualGUID(riid, &IID_IUnknown) ||
        IsEqualGUID(riid, &IID_IClassFactory))
    {
319
        *obj = iface;
320
    }
321 322 323 324 325 326 327 328
    else if (IsEqualGUID(riid, &IID_IExternalConnection))
    {
        *obj = &factory->IExternalConnection_iface;
    }
    else
    {
        *obj = NULL;
        return E_NOINTERFACE;
329 330
    }

331 332
    IUnknown_AddRef((IUnknown *)*obj);
    return S_OK;
333 334
}

335
static ULONG WINAPI test_factory_AddRef(IClassFactory *iface)
336
{
337 338
    struct test_factory *factory = impl_from_IClassFactory(iface);
    return InterlockedIncrement(&factory->refcount);
339 340
}

341
static ULONG WINAPI test_factory_Release(IClassFactory *iface)
342
{
343 344
    struct test_factory *factory = impl_from_IClassFactory(iface);
    return InterlockedDecrement(&factory->refcount);
345 346
}

347 348
static HRESULT WINAPI test_factory_CreateInstance(IClassFactory *iface, IUnknown *outer,
        REFIID riid, void **obj)
349 350 351 352
{
    return E_NOTIMPL;
}

353
static HRESULT WINAPI test_factory_LockServer(IClassFactory *iface, BOOL lock)
354 355 356 357
{
    return S_OK;
}

358
static const IClassFactoryVtbl test_factory_vtbl =
359
{
360 361 362 363 364
    test_factory_QueryInterface,
    test_factory_AddRef,
    test_factory_Release,
    test_factory_CreateInstance,
    test_factory_LockServer
365 366
};

367 368 369 370 371 372 373
static void test_factory_init(struct test_factory *factory)
{
    factory->IClassFactory_iface.lpVtbl = &test_factory_vtbl;
    factory->IExternalConnection_iface.lpVtbl = &ExternalConnectionVtbl;
    factory->refcount = 1;
    factory->external_connections = 0;
}
374

375 376
typedef struct
{
377
    IUnknown IUnknown_iface;
378 379 380
    ULONG refs;
} HeapUnknown;

381 382 383 384 385
static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
{
    return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
}

386 387 388 389 390
static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, &IID_IUnknown))
    {
        IUnknown_AddRef(iface);
391
        *ppv = iface;
392 393 394 395 396 397 398 399
        return S_OK;
    }
    *ppv = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
{
400
    HeapUnknown *This = impl_from_IUnknown(iface);
401 402 403 404 405
    return InterlockedIncrement((LONG*)&This->refs);
}

static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
{
406
    HeapUnknown *This = impl_from_IUnknown(iface);
407 408 409 410 411 412 413 414 415 416 417 418
    ULONG refs = InterlockedDecrement((LONG*)&This->refs);
    if (!refs) HeapFree(GetProcessHeap(), 0, This);
    return refs;
}

static const IUnknownVtbl HeapUnknown_Vtbl =
{
    HeapUnknown_QueryInterface,
    HeapUnknown_AddRef,
    HeapUnknown_Release
};

419 420 421 422
struct test_moniker
{
    IMoniker IMoniker_iface;
    IROTData IROTData_iface;
423
    IOleItemContainer IOleItemContainer_iface;
424
    IParseDisplayName IParseDisplayName_iface;
425
    LONG refcount;
426
    const char *inverse;
427 428 429 430 431 432 433 434 435 436 437 438 439 440

    BOOL no_IROTData;
};

static struct test_moniker *impl_from_IMoniker(IMoniker *iface)
{
    return CONTAINING_RECORD(iface, struct test_moniker, IMoniker_iface);
}

static struct test_moniker *impl_from_IROTData(IROTData *iface)
{
    return CONTAINING_RECORD(iface, struct test_moniker, IROTData_iface);
}

441 442 443 444 445
static struct test_moniker *impl_from_IOleItemContainer(IOleItemContainer *iface)
{
    return CONTAINING_RECORD(iface, struct test_moniker, IOleItemContainer_iface);
}

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
static struct test_moniker *impl_from_IParseDisplayName(IParseDisplayName *iface)
{
    return CONTAINING_RECORD(iface, struct test_moniker, IParseDisplayName_iface);
}

static HRESULT WINAPI test_moniker_parse_QueryInterface(IParseDisplayName *iface, REFIID riid, void **obj)
{
    if (IsEqualIID(riid, &IID_IUnknown) ||
            IsEqualIID(riid, &IID_IParseDisplayName))
    {
        *obj = iface;
        IParseDisplayName_AddRef(iface);
        return S_OK;
    }

    *obj = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI test_moniker_parse_AddRef(IParseDisplayName *iface)
{
    struct test_moniker *moniker = impl_from_IParseDisplayName(iface);
    return IMoniker_AddRef(&moniker->IMoniker_iface);
}

static ULONG WINAPI test_moniker_parse_Release(IParseDisplayName *iface)
{
    struct test_moniker *moniker = impl_from_IParseDisplayName(iface);
    return IMoniker_Release(&moniker->IMoniker_iface);
}

static HRESULT WINAPI test_moniker_parse_ParseDisplayName(IParseDisplayName *iface,
        IBindCtx *pbc, LPOLESTR displayname, ULONG *eaten, IMoniker **out)
{
    return E_NOTIMPL;
}

static const IParseDisplayNameVtbl test_moniker_parse_vtbl =
{
    test_moniker_parse_QueryInterface,
    test_moniker_parse_AddRef,
    test_moniker_parse_Release,
    test_moniker_parse_ParseDisplayName,
};

491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
static HRESULT WINAPI test_item_container_QueryInterface(IOleItemContainer *iface, REFIID riid, void **obj)
{
    if (IsEqualIID(riid, &IID_IOleItemContainer) ||
            IsEqualIID(riid, &IID_IOleContainer) ||
            IsEqualIID(riid, &IID_IParseDisplayName) ||
            IsEqualIID(riid, &IID_IUnknown))
    {
        *obj = iface;
        IOleItemContainer_AddRef(iface);
        return S_OK;
    }

    *obj = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI test_item_container_AddRef(IOleItemContainer *iface)
{
    struct test_moniker *moniker = impl_from_IOleItemContainer(iface);
    return IMoniker_AddRef(&moniker->IMoniker_iface);
}

static ULONG WINAPI test_item_container_Release(IOleItemContainer *iface)
{
    struct test_moniker *moniker = impl_from_IOleItemContainer(iface);
    return IMoniker_Release(&moniker->IMoniker_iface);
}

static HRESULT WINAPI test_item_container_ParseDisplayName(IOleItemContainer *iface,
        IBindCtx *pbc, LPOLESTR displayname, ULONG *eaten, IMoniker **out)
{
    return E_NOTIMPL;
}

static HRESULT WINAPI test_item_container_EnumObjects(IOleItemContainer *iface, DWORD flags,
        IEnumUnknown **ppenum)
{
    return E_NOTIMPL;
}

static HRESULT WINAPI test_item_container_LockContainer(IOleItemContainer *iface, BOOL lock)
{
533
    return S_OK;
534 535 536 537 538
}

static HRESULT WINAPI test_item_container_GetObject(IOleItemContainer *iface, LPOLESTR item,
        DWORD bind_speed, IBindCtx *pbc, REFIID riid, void **obj)
{
539 540 541 542 543 544 545 546
    struct test_moniker *moniker = impl_from_IOleItemContainer(iface);

    if (IsEqualIID(riid, &IID_IParseDisplayName))
    {
        *obj = &moniker->IParseDisplayName_iface;
        IOleItemContainer_AddRef(iface);
    }

547 548 549 550 551 552
    return 0x8bee0000 | bind_speed;
}

static HRESULT WINAPI test_item_container_GetObjectStorage(IOleItemContainer *iface, LPOLESTR item,
        IBindCtx *pbc, REFIID riid, void **obj)
{
553
    return 0x8bee0001;
554 555 556 557
}

static HRESULT WINAPI test_item_container_IsRunning(IOleItemContainer *iface, LPOLESTR item)
{
558
    ok(0, "Unexpected call.\n");
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
    return E_NOTIMPL;
}

static const IOleItemContainerVtbl test_item_container_vtbl =
{
    test_item_container_QueryInterface,
    test_item_container_AddRef,
    test_item_container_Release,
    test_item_container_ParseDisplayName,
    test_item_container_EnumObjects,
    test_item_container_LockContainer,
    test_item_container_GetObject,
    test_item_container_GetObjectStorage,
    test_item_container_IsRunning,
};

575
static HRESULT WINAPI
576
Moniker_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
577
{
578 579
    struct test_moniker *moniker = impl_from_IMoniker(iface);

580 581 582 583 584 585 586 587 588 589 590
    if (!ppvObject)
        return E_INVALIDARG;

    *ppvObject = 0;

    if (IsEqualIID(&IID_IUnknown, riid)      ||
        IsEqualIID(&IID_IPersist, riid)      ||
        IsEqualIID(&IID_IPersistStream,riid) ||
        IsEqualIID(&IID_IMoniker, riid))
        *ppvObject = iface;
    if (IsEqualIID(&IID_IROTData, riid))
591
    {
592
        CHECK_EXPECTED_METHOD("Moniker_QueryInterface(IID_IROTData)");
593 594 595
        if (!moniker->no_IROTData)
            *ppvObject = &moniker->IROTData_iface;
    }
596 597 598 599 600 601 602 603 604 605 606 607

    if ((*ppvObject)==0)
        return E_NOINTERFACE;

    IMoniker_AddRef(iface);

    return S_OK;
}

static ULONG WINAPI
Moniker_AddRef(IMoniker* iface)
{
608 609
    struct test_moniker *moniker = impl_from_IMoniker(iface);
    return InterlockedIncrement(&moniker->refcount);
610 611 612 613 614
}

static ULONG WINAPI
Moniker_Release(IMoniker* iface)
{
615 616 617 618 619 620 621
    struct test_moniker *moniker = impl_from_IMoniker(iface);
    ULONG refcount = InterlockedDecrement(&moniker->refcount);

    if (!refcount)
        heap_free(moniker);

    return refcount;
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
}

static HRESULT WINAPI
Moniker_GetClassID(IMoniker* iface, CLSID *pClassID)
{
    CHECK_EXPECTED_METHOD("Moniker_GetClassID");

    *pClassID = CLSID_TestMoniker;

    return S_OK;
}

static HRESULT WINAPI
Moniker_IsDirty(IMoniker* iface)
{
    CHECK_EXPECTED_METHOD("Moniker_IsDirty");

    return S_FALSE;
}

static HRESULT WINAPI
Moniker_Load(IMoniker* iface, IStream* pStm)
{
    CHECK_EXPECTED_METHOD("Moniker_Load");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
{
    CHECK_EXPECTED_METHOD("Moniker_Save");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
{
    CHECK_EXPECTED_METHOD("Moniker_GetSizeMax");
    return E_NOTIMPL;
}

663 664
static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riid,
        void **obj)
665
{
666 667 668 669 670 671 672 673 674
    struct test_moniker *moniker = impl_from_IMoniker(iface);

    if (IsEqualIID(riid, &IID_IOleItemContainer))
    {
        *obj = &moniker->IOleItemContainer_iface;
        IMoniker_AddRef(iface);
        return S_OK;
    }

675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
    CHECK_EXPECTED_METHOD("Moniker_BindToObject");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
                              REFIID riid, VOID** ppvObject)
{
    CHECK_EXPECTED_METHOD("Moniker_BindToStorage");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
                       IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
{
    CHECK_EXPECTED_METHOD("Moniker_Reduce");

    if (ppmkReduced==NULL)
        return E_POINTER;

    IMoniker_AddRef(iface);

    *ppmkReduced=iface;

    return MK_S_REDUCED_TO_SELF;
}

static HRESULT WINAPI
Moniker_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
                            BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
{
    CHECK_EXPECTED_METHOD("Moniker_ComposeWith");
708
    return MK_E_NEEDGENERIC;
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
}

static HRESULT WINAPI
Moniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
{
    CHECK_EXPECTED_METHOD("Moniker_Enum");

    if (ppenumMoniker == NULL)
        return E_POINTER;

    *ppenumMoniker = NULL;

    return S_OK;
}

static HRESULT WINAPI
Moniker_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
{
    CHECK_EXPECTED_METHOD("Moniker_IsEqual");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_Hash(IMoniker* iface,DWORD* pdwHash)
{
    CHECK_EXPECTED_METHOD("Moniker_Hash");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
                          IMoniker* pmkNewlyRunning)
{
    CHECK_EXPECTED_METHOD("Moniker_IsRunning");
743
    return 0x8beef000;
744 745 746 747 748 749 750 751 752 753 754 755 756
}

static HRESULT WINAPI
Moniker_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
                                    IMoniker* pmkToLeft, FILETIME* pFileTime)
{
    CHECK_EXPECTED_METHOD("Moniker_GetTimeOfLastChange");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_Inverse(IMoniker* iface,IMoniker** ppmk)
{
757
    struct test_moniker *moniker = impl_from_IMoniker(iface);
758
    CHECK_EXPECTED_METHOD("Moniker_Inverse");
759
    return create_moniker_from_desc(moniker->inverse, ppmk);
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
}

static HRESULT WINAPI
Moniker_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
{
    CHECK_EXPECTED_METHOD("Moniker_CommonPrefixWith");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
{
    CHECK_EXPECTED_METHOD("Moniker_RelativePathTo");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
                               IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
{
    static const WCHAR wszDisplayName[] = {'*','*','G','e','m','m','a',0};
    CHECK_EXPECTED_METHOD("Moniker_GetDisplayName");
782
    *ppszDisplayName = CoTaskMemAlloc(sizeof(wszDisplayName));
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
    memcpy(*ppszDisplayName, wszDisplayName, sizeof(wszDisplayName));
    return S_OK;
}

static HRESULT WINAPI
Moniker_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
                     LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
{
    CHECK_EXPECTED_METHOD("Moniker_ParseDisplayName");
    return E_NOTIMPL;
}

static HRESULT WINAPI
Moniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
{
    CHECK_EXPECTED_METHOD("Moniker_IsSystemMoniker");

    if (!pwdMksys)
        return E_POINTER;

    (*pwdMksys)=MKSYS_NONE;

    return S_FALSE;
}

static HRESULT WINAPI
ROTData_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
{
811 812
    struct test_moniker *moniker = impl_from_IROTData(iface);
    return IMoniker_QueryInterface(&moniker->IMoniker_iface, riid, ppvObject);
813 814 815 816 817
}

static ULONG WINAPI
ROTData_AddRef(IROTData *iface)
{
818 819
    struct test_moniker *moniker = impl_from_IROTData(iface);
    return IMoniker_AddRef(&moniker->IMoniker_iface);
820 821 822 823 824
}

static ULONG WINAPI
ROTData_Release(IROTData* iface)
{
825 826
    struct test_moniker *moniker = impl_from_IROTData(iface);
    return IMoniker_Release(&moniker->IMoniker_iface);
827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
}

static HRESULT WINAPI
ROTData_GetComparisonData(IROTData* iface, BYTE* pbData,
                                          ULONG cbMax, ULONG* pcbData)
{
    CHECK_EXPECTED_METHOD("ROTData_GetComparisonData");

    *pcbData = 1;
    if (cbMax < *pcbData)
        return E_OUTOFMEMORY;

    *pbData = 0xde;

    return S_OK;
}

static IROTDataVtbl ROTDataVtbl =
{
    ROTData_QueryInterface,
    ROTData_AddRef,
    ROTData_Release,
    ROTData_GetComparisonData
};

static const IMonikerVtbl MonikerVtbl =
{
    Moniker_QueryInterface,
    Moniker_AddRef,
    Moniker_Release,
    Moniker_GetClassID,
    Moniker_IsDirty,
    Moniker_Load,
    Moniker_Save,
    Moniker_GetSizeMax,
    Moniker_BindToObject,
    Moniker_BindToStorage,
    Moniker_Reduce,
    Moniker_ComposeWith,
    Moniker_Enum,
    Moniker_IsEqual,
    Moniker_Hash,
    Moniker_IsRunning,
    Moniker_GetTimeOfLastChange,
    Moniker_Inverse,
    Moniker_CommonPrefixWith,
    Moniker_RelativePathTo,
    Moniker_GetDisplayName,
    Moniker_ParseDisplayName,
    Moniker_IsSystemMoniker
};

879 880 881 882 883 884 885
static struct test_moniker *create_test_moniker(void)
{
    struct test_moniker *obj;

    obj = heap_alloc_zero(sizeof(*obj));
    obj->IMoniker_iface.lpVtbl = &MonikerVtbl;
    obj->IROTData_iface.lpVtbl = &ROTDataVtbl;
886
    obj->IOleItemContainer_iface.lpVtbl = &test_item_container_vtbl;
887
    obj->IParseDisplayName_iface.lpVtbl = &test_moniker_parse_vtbl;
888 889 890 891
    obj->refcount = 1;

    return obj;
}
892 893 894 895 896 897 898

static void test_ROT(void)
{
    static const WCHAR wszFileName[] = {'B','E','2','0','E','2','F','5','-',
        '1','9','0','3','-','4','A','A','E','-','B','1','A','F','-',
        '2','0','4','6','E','5','8','6','C','9','2','5',0};
    HRESULT hr;
899
    IMoniker *pMoniker = NULL, *moniker;
900
    struct test_moniker *test_moniker;
901
    IRunningObjectTable *pROT = NULL;
902
    struct test_factory factory;
903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936
    DWORD dwCookie;
    static const char *methods_register_no_ROTData[] =
    {
        "Moniker_Reduce",
        "Moniker_GetTimeOfLastChange",
        "Moniker_QueryInterface(IID_IROTData)",
        "Moniker_GetDisplayName",
        "Moniker_GetClassID",
        NULL
    };
    static const char *methods_register[] =
    {
        "Moniker_Reduce",
        "Moniker_GetTimeOfLastChange",
        "Moniker_QueryInterface(IID_IROTData)",
        "ROTData_GetComparisonData",
        NULL
    };
    static const char *methods_isrunning_no_ROTData[] =
    {
        "Moniker_Reduce",
        "Moniker_QueryInterface(IID_IROTData)",
        "Moniker_GetDisplayName",
        "Moniker_GetClassID",
        NULL
    };
    static const char *methods_isrunning[] =
    {
        "Moniker_Reduce",
        "Moniker_QueryInterface(IID_IROTData)",
        "ROTData_GetComparisonData",
        NULL
    };

937
    test_factory_init(&factory);
938 939 940 941

    hr = GetRunningObjectTable(0, &pROT);
    ok_ole_success(hr, GetRunningObjectTable);

942 943 944
    test_moniker = create_test_moniker();
    test_moniker->no_IROTData = TRUE;

945 946
    expected_method_list = methods_register_no_ROTData;
    /* try with our own moniker that doesn't support IROTData */
947
    hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)&factory.IClassFactory_iface,
948
            &test_moniker->IMoniker_iface, &dwCookie);
949
    ok(hr == S_OK, "Failed to register interface, hr %#lx.\n", hr);
950
    ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
951
    ok(factory.external_connections == 1, "external_connections = %d\n", factory.external_connections);
952
    ok(factory.refcount > 1, "Unexpected factory refcount %lu.\n", factory.refcount);
953 954

    expected_method_list = methods_isrunning_no_ROTData;
955
    hr = IRunningObjectTable_IsRunning(pROT, &test_moniker->IMoniker_iface);
956 957 958 959 960
    ok_ole_success(hr, IRunningObjectTable_IsRunning);
    ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);

    hr = IRunningObjectTable_Revoke(pROT, dwCookie);
    ok_ole_success(hr, IRunningObjectTable_Revoke);
961
    ok(!factory.external_connections, "external_connections = %d\n", factory.external_connections);
962
    ok(factory.refcount == 1, "Unexpected factory refcount %lu.\n", factory.refcount);
963 964 965

    expected_method_list = methods_register;
    /* try with our own moniker */
966
    test_moniker->no_IROTData = FALSE;
967 968
    hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)&factory.IClassFactory_iface,
            &test_moniker->IMoniker_iface, &dwCookie);
969 970
    ok_ole_success(hr, IRunningObjectTable_Register);
    ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
971
    ok(factory.refcount > 1, "Unexpected factory refcount %lu.\n", factory.refcount);
972 973

    expected_method_list = methods_isrunning;
974
    hr = IRunningObjectTable_IsRunning(pROT, &test_moniker->IMoniker_iface);
975 976
    ok_ole_success(hr, IRunningObjectTable_IsRunning);
    ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
977
    expected_method_list = NULL;
978 979 980

    hr = IRunningObjectTable_Revoke(pROT, dwCookie);
    ok_ole_success(hr, IRunningObjectTable_Revoke);
981
    ok(factory.refcount == 1, "Unexpected factory refcount %lu.\n", factory.refcount);
982 983 984 985

    hr = CreateFileMoniker(wszFileName, &pMoniker);
    ok_ole_success(hr, CreateClassMoniker);

986
    /* test flags: 0 */
987 988
    factory.external_connections = 0;
    hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&factory.IClassFactory_iface, pMoniker, &dwCookie);
989
    ok_ole_success(hr, IRunningObjectTable_Register);
990
    ok(!factory.external_connections, "external_connections = %d\n", factory.external_connections);
991
    ok(factory.refcount > 1, "Unexpected factory refcount %lu.\n", factory.refcount);
992 993 994

    hr = IRunningObjectTable_Revoke(pROT, dwCookie);
    ok_ole_success(hr, IRunningObjectTable_Revoke);
995
    ok(factory.refcount == 1, "Unexpected factory refcount %lu.\n", factory.refcount);
996 997

    /* test flags: ROTFLAGS_REGISTRATIONKEEPSALIVE */
998 999
    hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)&factory.IClassFactory_iface,
            pMoniker, &dwCookie);
1000
    ok_ole_success(hr, IRunningObjectTable_Register);
1001
    ok(factory.refcount > 1, "Unexpected factory refcount %lu.\n", factory.refcount);
1002 1003 1004

    hr = IRunningObjectTable_Revoke(pROT, dwCookie);
    ok_ole_success(hr, IRunningObjectTable_Revoke);
1005
    ok(factory.refcount == 1, "Unexpected factory refcount %lu.\n", factory.refcount);
1006

1007
    /* test flags: ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT */
1008 1009
    /* only succeeds when process is started by SCM and has LocalService
     * or RunAs AppId values */
1010 1011
    hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE | ROTFLAGS_ALLOWANYCLIENT,
            (IUnknown *)&factory.IClassFactory_iface, pMoniker, &dwCookie);
1012
    todo_wine {
1013
    ok(hr == CO_E_WRONG_SERVER_IDENTITY, "Unexpected hr %#lx.\n", hr);
1014
    }
1015 1016 1017
    if (SUCCEEDED(hr))
    {
        hr = IRunningObjectTable_Revoke(pROT, dwCookie);
1018
        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1019
    }
1020

1021
    hr = IRunningObjectTable_Register(pROT, 0xdeadbeef, (IUnknown *)&factory.IClassFactory_iface, pMoniker, &dwCookie);
1022
    ok(hr == E_INVALIDARG, "IRunningObjectTable_Register should have returned E_INVALIDARG instead of 0x%08lx\n", hr);
1023 1024

    IMoniker_Release(pMoniker);
1025
    IMoniker_Release(&test_moniker->IMoniker_iface);
1026

1027 1028
    /* Pointer moniker does not implement IROTData or display name */
    hr = CreatePointerMoniker(NULL, &pMoniker);
1029
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1030 1031
    hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)&factory.IClassFactory_iface,
            pMoniker, &dwCookie);
1032
    todo_wine
1033
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1034 1035 1036
    IMoniker_Release(pMoniker);

    hr = create_moniker_from_desc("I1", &moniker);
1037
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1038
    hr = CreatePointerMoniker((IUnknown *)moniker, &pMoniker);
1039
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1040 1041
    hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)&factory.IClassFactory_iface,
            pMoniker, &dwCookie);
1042
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
1043 1044 1045
    IMoniker_Release(pMoniker);
    IMoniker_Release(moniker);

1046 1047 1048
    IRunningObjectTable_Release(pROT);
}

1049 1050 1051 1052 1053 1054 1055 1056 1057
static void test_ROT_multiple_entries(void)
{
    HRESULT hr;
    IMoniker *pMoniker = NULL;
    IRunningObjectTable *pROT = NULL;
    DWORD dwCookie1, dwCookie2;
    IUnknown *pObject = NULL;
    static const WCHAR moniker_path[] =
        {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0};
1058 1059 1060
    struct test_factory factory;

    test_factory_init(&factory);
1061 1062 1063 1064 1065 1066 1067

    hr = GetRunningObjectTable(0, &pROT);
    ok_ole_success(hr, GetRunningObjectTable);

    hr = CreateFileMoniker(moniker_path, &pMoniker);
    ok_ole_success(hr, CreateFileMoniker);

1068
    hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&factory.IClassFactory_iface, pMoniker, &dwCookie1);
1069 1070
    ok_ole_success(hr, IRunningObjectTable_Register);

1071
    hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&factory.IClassFactory_iface, pMoniker, &dwCookie2);
1072
    ok(hr == MK_S_MONIKERALREADYREGISTERED, "IRunningObjectTable_Register should have returned MK_S_MONIKERALREADYREGISTERED instead of 0x%08lx\n", hr);
1073

1074
    ok(dwCookie1 != dwCookie2, "cookie returned for registering duplicate object shouldn't match cookie of original object (0x%lx)\n", dwCookie1);
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084

    hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject);
    ok_ole_success(hr, IRunningObjectTable_GetObject);
    IUnknown_Release(pObject);

    hr = IRunningObjectTable_Revoke(pROT, dwCookie1);
    ok_ole_success(hr, IRunningObjectTable_Revoke);

    hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject);
    ok_ole_success(hr, IRunningObjectTable_GetObject);
1085
    IUnknown_Release(pObject);
1086 1087 1088 1089 1090 1091 1092 1093 1094

    hr = IRunningObjectTable_Revoke(pROT, dwCookie2);
    ok_ole_success(hr, IRunningObjectTable_Revoke);

    IMoniker_Release(pMoniker);

    IRunningObjectTable_Release(pROT);
}

1095 1096 1097 1098 1099 1100
static HRESULT WINAPI ParseDisplayName_QueryInterface(IParseDisplayName *iface, REFIID riid, void **ppv)
{
    if (IsEqualIID(riid, &IID_IUnknown) ||
        IsEqualIID(riid, &IID_IParseDisplayName))
    {
        *ppv = iface;
1101
        IParseDisplayName_AddRef(iface);
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143
        return S_OK;
    }
    *ppv = NULL;
    return E_NOINTERFACE;
}

static ULONG WINAPI ParseDisplayName_AddRef(IParseDisplayName *iface)
{
    return 2;
}

static ULONG WINAPI ParseDisplayName_Release(IParseDisplayName *iface)
{
    return 1;
}

static LPCWSTR expected_display_name;

static HRESULT WINAPI ParseDisplayName_ParseDisplayName(IParseDisplayName *iface,
                                                        IBindCtx *pbc,
                                                        LPOLESTR pszDisplayName,
                                                        ULONG *pchEaten,
                                                        IMoniker **ppmkOut)
{
    char display_nameA[256];
    WideCharToMultiByte(CP_ACP, 0, pszDisplayName, -1, display_nameA, sizeof(display_nameA), NULL, NULL);
    ok(!lstrcmpW(pszDisplayName, expected_display_name), "unexpected display name \"%s\"\n", display_nameA);
    ok(pszDisplayName == expected_display_name, "pszDisplayName should be the same pointer as passed into MkParseDisplayName\n");
    *pchEaten = lstrlenW(pszDisplayName);
    return CreateAntiMoniker(ppmkOut);
}

static const IParseDisplayNameVtbl ParseDisplayName_Vtbl =
{
    ParseDisplayName_QueryInterface,
    ParseDisplayName_AddRef,
    ParseDisplayName_Release,
    ParseDisplayName_ParseDisplayName
};

static IParseDisplayName ParseDisplayName = { &ParseDisplayName_Vtbl };

1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
static int count_moniker_matches(IBindCtx * pbc, IEnumMoniker * spEM)
{
    IMoniker * spMoniker;
    int monCnt=0, matchCnt=0;

    while ((IEnumMoniker_Next(spEM, 1, &spMoniker, NULL)==S_OK))
    {
        HRESULT hr;
        WCHAR * szDisplayn;
        monCnt++;
        hr=IMoniker_GetDisplayName(spMoniker, pbc, NULL, &szDisplayn);
        if (SUCCEEDED(hr))
        {
1157
            if (!lstrcmpiW(szDisplayn, wszFileName1) || !lstrcmpiW(szDisplayn, wszFileName2))
1158 1159 1160 1161 1162 1163 1164
                matchCnt++;
            CoTaskMemFree(szDisplayn);
        }
    }
    return matchCnt;
}

1165
static void test_MkParseDisplayName(void)
1166 1167 1168
{
    IBindCtx * pbc = NULL;
    HRESULT hr;
1169 1170 1171
    IMoniker * pmk  = NULL;
    IMoniker * pmk1 = NULL;
    IMoniker * pmk2 = NULL;
1172
    ULONG eaten;
1173
    int matchCnt;
1174
    IUnknown * object = NULL;
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185

    IUnknown *lpEM1;

    IEnumMoniker *spEM1  = NULL;
    IEnumMoniker *spEM2  = NULL;
    IEnumMoniker *spEM3  = NULL;

    DWORD pdwReg1=0;
    DWORD pdwReg2=0;
    IRunningObjectTable * pprot=NULL;

1186 1187 1188
    /* CLSID of My Computer */
    static const WCHAR wszDisplayName[] = {'c','l','s','i','d',':',
        '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};
1189
    static const WCHAR wszDisplayNameClsid[] = {'c','l','s','i','d',':',0};
1190
    static const WCHAR wszNonExistentProgId[] = {'N','o','n','E','x','i','s','t','e','n','t','P','r','o','g','I','d',':',0};
1191 1192 1193 1194
    static const WCHAR wszDisplayNameRunning[] = {'W','i','n','e','T','e','s','t','R','u','n','n','i','n','g',0};
    static const WCHAR wszDisplayNameProgId1[] = {'S','t','d','F','o','n','t',':',0};
    static const WCHAR wszDisplayNameProgId2[] = {'@','S','t','d','F','o','n','t',0};
    static const WCHAR wszDisplayNameProgIdFail[] = {'S','t','d','F','o','n','t',0};
1195
    static const WCHAR wszEmpty[] = {0};
1196 1197
    char szDisplayNameFile[256];
    WCHAR wszDisplayNameFile[256];
1198
    int i, len;
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224

    const struct
    {
        LPBC *ppbc;
        LPCOLESTR szDisplayName;
        LPDWORD pchEaten;
        LPMONIKER *ppmk;
    } invalid_parameters[] =
    {
        {NULL,  NULL,     NULL,   NULL},
        {NULL,  NULL,     NULL,   &pmk},
        {NULL,  NULL,     &eaten, NULL},
        {NULL,  NULL,     &eaten, &pmk},
        {NULL,  wszEmpty, NULL,   NULL},
        {NULL,  wszEmpty, NULL,   &pmk},
        {NULL,  wszEmpty, &eaten, NULL},
        {NULL,  wszEmpty, &eaten, &pmk},
        {&pbc,  NULL,     NULL,   NULL},
        {&pbc,  NULL,     NULL,   &pmk},
        {&pbc,  NULL,     &eaten, NULL},
        {&pbc,  NULL,     &eaten, &pmk},
        {&pbc,  wszEmpty, NULL,   NULL},
        {&pbc,  wszEmpty, NULL,   &pmk},
        {&pbc,  wszEmpty, &eaten, NULL},
        {&pbc,  wszEmpty, &eaten, &pmk},
    };
1225 1226 1227
    struct test_factory factory;

    test_factory_init(&factory);
1228 1229 1230 1231

    hr = CreateBindCtx(0, &pbc);
    ok_ole_success(hr, CreateBindCtx);

1232
    for (i = 0; i < ARRAY_SIZE(invalid_parameters); i++)
1233 1234 1235 1236 1237 1238 1239
    {
        eaten = 0xdeadbeef;
        pmk = (IMoniker *)0xdeadbeef;
        hr = MkParseDisplayName(invalid_parameters[i].ppbc ? *invalid_parameters[i].ppbc : NULL,
                                invalid_parameters[i].szDisplayName,
                                invalid_parameters[i].pchEaten,
                                invalid_parameters[i].ppmk);
1240 1241
        ok(hr == E_INVALIDARG, "[%d] MkParseDisplayName should have failed with E_INVALIDARG instead of 0x%08lx\n", i, hr);
        ok(eaten == 0xdeadbeef, "[%d] Processed character count should have been 0xdeadbeef instead of %lu\n", i, eaten);
1242 1243 1244
        ok(pmk == (IMoniker *)0xdeadbeef, "[%d] Output moniker pointer should have been 0xdeadbeef instead of %p\n", i, pmk);
    }

1245 1246
    eaten = 0xdeadbeef;
    pmk = (IMoniker *)0xdeadbeef;
1247
    hr = MkParseDisplayName(pbc, wszNonExistentProgId, &eaten, &pmk);
1248
    todo_wine
1249 1250
    ok(hr == MK_E_SYNTAX, "Unexpected hr %#lx.\n", hr);
    ok(eaten == 0, "Processed character count should have been 0 instead of %lu\n", eaten);
1251
    ok(pmk == NULL, "Output moniker pointer should have been NULL instead of %p\n", pmk);
1252 1253 1254

    /* no special handling of "clsid:" without the string form of the clsid
     * following */
1255 1256
    eaten = 0xdeadbeef;
    pmk = (IMoniker *)0xdeadbeef;
1257
    hr = MkParseDisplayName(pbc, wszDisplayNameClsid, &eaten, &pmk);
1258
    todo_wine
1259 1260
    ok(hr == MK_E_SYNTAX, "Unexpected hr %#lx.\n", hr);
    ok(eaten == 0, "Processed character count should have been 0 instead of %lu\n", eaten);
1261
    ok(pmk == NULL, "Output moniker pointer should have been NULL instead of %p\n", pmk);
1262 1263 1264 1265 1266 1267

    /* shows clsid has higher precedence than a running object */
    hr = CreateFileMoniker(wszDisplayName, &pmk);
    ok_ole_success(hr, CreateFileMoniker);
    hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
    ok_ole_success(hr, IBindCtx_GetRunningObjectTable);
1268
    hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&factory.IClassFactory_iface, pmk, &pdwReg1);
1269 1270 1271 1272
    ok_ole_success(hr, IRunningObjectTable_Register);
    IMoniker_Release(pmk);
    pmk = NULL;
    hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
1273
    ok_ole_success(hr, MkParseDisplayName);
1274
    ok(eaten == ARRAY_SIZE(wszDisplayName) - 1,
1275
        "Processed character count should have been 43 instead of %lu\n", eaten);
1276 1277
    if (pmk)
    {
1278
        TEST_MONIKER_TYPE(pmk, MKSYS_CLASSMONIKER);
1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
        IMoniker_Release(pmk);
    }
    hr = IRunningObjectTable_Revoke(pprot, pdwReg1);
    ok_ole_success(hr, IRunningObjectTable_Revoke);
    IRunningObjectTable_Release(pprot);

    hr = CreateFileMoniker(wszDisplayNameRunning, &pmk);
    ok_ole_success(hr, CreateFileMoniker);
    hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
    ok_ole_success(hr, IBindCtx_GetRunningObjectTable);
1289
    hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&factory.IClassFactory_iface, pmk, &pdwReg1);
1290 1291 1292 1293
    ok_ole_success(hr, IRunningObjectTable_Register);
    IMoniker_Release(pmk);
    pmk = NULL;
    hr = MkParseDisplayName(pbc, wszDisplayNameRunning, &eaten, &pmk);
1294
    ok_ole_success(hr, MkParseDisplayName);
1295
    ok(eaten == ARRAY_SIZE(wszDisplayNameRunning) - 1,
1296
        "Processed character count should have been 15 instead of %lu\n", eaten);
1297 1298
    if (pmk)
    {
1299
        TEST_MONIKER_TYPE(pmk, MKSYS_FILEMONIKER);
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
        IMoniker_Release(pmk);
    }
    hr = IRunningObjectTable_Revoke(pprot, pdwReg1);
    ok_ole_success(hr, IRunningObjectTable_Revoke);
    IRunningObjectTable_Release(pprot);

    hr = CoRegisterClassObject(&CLSID_StdFont, (IUnknown *)&ParseDisplayName, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &pdwReg1);
    ok_ole_success(hr, CoRegisterClassObject);

    expected_display_name = wszDisplayNameProgId1;
    hr = MkParseDisplayName(pbc, wszDisplayNameProgId1, &eaten, &pmk);
1311
    ok_ole_success(hr, MkParseDisplayName);
1312
    ok(eaten == ARRAY_SIZE(wszDisplayNameProgId1) - 1,
1313
        "Processed character count should have been 8 instead of %lu\n", eaten);
1314 1315
    if (pmk)
    {
1316
        TEST_MONIKER_TYPE(pmk, MKSYS_ANTIMONIKER);
1317 1318 1319 1320 1321
        IMoniker_Release(pmk);
    }

    expected_display_name = wszDisplayNameProgId2;
    hr = MkParseDisplayName(pbc, wszDisplayNameProgId2, &eaten, &pmk);
1322
    ok_ole_success(hr, MkParseDisplayName);
1323
    ok(eaten == ARRAY_SIZE(wszDisplayNameProgId2) - 1,
1324
        "Processed character count should have been 8 instead of %lu\n", eaten);
1325 1326
    if (pmk)
    {
1327
        TEST_MONIKER_TYPE(pmk, MKSYS_ANTIMONIKER);
1328 1329 1330
        IMoniker_Release(pmk);
    }

1331 1332
    eaten = 0xdeadbeef;
    pmk = (IMoniker *)0xdeadbeef;
1333
    hr = MkParseDisplayName(pbc, wszDisplayNameProgIdFail, &eaten, &pmk);
1334
    todo_wine
1335 1336
    ok(hr == MK_E_SYNTAX, "Unexpected hr %#lx.\n", hr);
    ok(eaten == 0, "Processed character count should have been 0 instead of %lu\n", eaten);
1337
    ok(pmk == NULL, "Output moniker pointer should have been NULL instead of %p\n", pmk);
1338 1339 1340 1341 1342 1343

    hr = CoRevokeClassObject(pdwReg1);
    ok_ole_success(hr, CoRevokeClassObject);

    GetSystemDirectoryA(szDisplayNameFile, sizeof(szDisplayNameFile));
    strcat(szDisplayNameFile, "\\kernel32.dll");
1344 1345
    len = MultiByteToWideChar(CP_ACP, 0, szDisplayNameFile, -1, wszDisplayNameFile,
        ARRAY_SIZE(wszDisplayNameFile));
1346
    hr = MkParseDisplayName(pbc, wszDisplayNameFile, &eaten, &pmk);
1347
    ok_ole_success(hr, MkParseDisplayName);
1348
    ok(eaten == len - 1, "Processed character count should have been %d instead of %lu\n", len - 1, eaten);
1349 1350
    if (pmk)
    {
1351
        TEST_MONIKER_TYPE(pmk, MKSYS_FILEMONIKER);
1352 1353 1354
        IMoniker_Release(pmk);
    }

1355
    hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
1356
    ok_ole_success(hr, MkParseDisplayName);
1357
    ok(eaten == ARRAY_SIZE(wszDisplayName) - 1,
1358
        "Processed character count should have been 43 instead of %lu\n", eaten);
1359

1360
    if (pmk)
1361 1362 1363 1364
    {
        hr = IMoniker_BindToObject(pmk, pbc, NULL, &IID_IUnknown, (LPVOID*)&object);
        ok_ole_success(hr, IMoniker_BindToObject);

1365 1366
        if (SUCCEEDED(hr))
            IUnknown_Release(object);
1367
        IMoniker_Release(pmk);
1368 1369
    }
    IBindCtx_Release(pbc);
1370 1371 1372 1373 1374 1375

    /* Test the EnumMoniker interface */
    hr = CreateBindCtx(0, &pbc);
    ok_ole_success(hr, CreateBindCtx);

    hr = CreateFileMoniker(wszFileName1, &pmk1);
1376
    ok(hr == S_OK, "Failed to create file moniker, hr %#lx.\n", hr);
1377
    hr = CreateFileMoniker(wszFileName2, &pmk2);
1378
    ok(hr == S_OK, "Failed to create file moniker, hr %#lx.\n", hr);
1379
    hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
1380
    ok(hr == S_OK, "Failed to get ROT, hr %#lx.\n", hr);
1381 1382 1383

    /* Check EnumMoniker before registering */
    hr = IRunningObjectTable_EnumRunning(pprot, &spEM1);
1384
    ok(hr == S_OK, "Failed to get enum object, hr %#lx.\n", hr);
1385
    hr = IEnumMoniker_QueryInterface(spEM1, &IID_IUnknown, (void *)&lpEM1);
1386
    /* Register a couple of Monikers and check is ok */
1387
    ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
1388

1389 1390
    matchCnt = count_moniker_matches(pbc, spEM1);

1391
    hr = IRunningObjectTable_Register(pprot, ROTFLAGS_REGISTRATIONKEEPSALIVE, lpEM1, pmk1, &pdwReg1);
1392
    ok(hr == S_OK, "Failed to register object, hr %#lx.\n", hr);
1393

1394
    hr = IRunningObjectTable_Register(pprot, ROTFLAGS_REGISTRATIONKEEPSALIVE, lpEM1, pmk2, &pdwReg2);
1395
    ok(hr == S_OK, "Failed to register object, hr %#lx.\n", hr);
1396 1397

    hr = IRunningObjectTable_EnumRunning(pprot, &spEM2);
1398
    ok(hr == S_OK, "Failed to get enum object, hr %#lx.\n", hr);
1399

1400 1401
    matchCnt = count_moniker_matches(pbc, spEM2);
    ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
1402 1403

    IEnumMoniker_Clone(spEM2, &spEM3);
1404 1405 1406 1407 1408 1409 1410 1411

    matchCnt = count_moniker_matches(pbc, spEM3);
    ok(matchCnt==0, "Number of matches should be equal to 0 not %i\n", matchCnt);
    IEnumMoniker_Reset(spEM3);

    matchCnt = count_moniker_matches(pbc, spEM3);
    ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);

1412
    hr = IRunningObjectTable_Revoke(pprot,pdwReg1);
1413
    ok(hr == S_OK, "Failed to revoke, hr %#lx.\n", hr);
1414
    hr = IRunningObjectTable_Revoke(pprot,pdwReg2);
1415
    ok(hr == S_OK, "Failed to revoke, hr %#lx.\n", hr);
1416
    IUnknown_Release(lpEM1);
1417 1418 1419 1420 1421 1422 1423 1424
    IEnumMoniker_Release(spEM1);
    IEnumMoniker_Release(spEM2);
    IEnumMoniker_Release(spEM3);
    IMoniker_Release(pmk1);
    IMoniker_Release(pmk2);
    IRunningObjectTable_Release(pprot);

    IBindCtx_Release(pbc);
1425 1426
}

1427 1428 1429
static const LARGE_INTEGER llZero;

static const BYTE expected_class_moniker_marshal_data[] =
Robert Shearman's avatar
Robert Shearman committed
1430
{
1431 1432 1433 1434 1435 1436 1437 1438 1439
    0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
    0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
    0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x00,0x00,0x00,0x00,
Robert Shearman's avatar
Robert Shearman committed
1440 1441
};

1442 1443 1444 1445 1446 1447
static const BYTE expected_class_moniker_saved_data[] =
{
     0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x00,0x00,0x00,0x00,
};
Robert Shearman's avatar
Robert Shearman committed
1448

1449 1450 1451 1452 1453 1454 1455 1456
static const BYTE expected_class_moniker_comparison_data[] =
{
     0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
};

1457 1458 1459 1460 1461 1462 1463
static const WCHAR expected_class_moniker_display_name[] =
{
    'c','l','s','i','d',':','0','0','0','2','E','0','0','5','-','0','0','0',
    '0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0',
    '0','0','0','0','4','6',':',0
};

1464 1465 1466 1467
static const BYTE expected_item_moniker_comparison_data[] =
{
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493
      '!',0x00, 'T',0x00, 'E',0x00, 'S',0x00,
      'T',0x00,0x00,0x00,
};

static const BYTE expected_item_moniker_comparison_data2[] =
{
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
      'T',0x00, 'E',0x00, 'S',0x00, 'T',0x00,
     0x00,0x00,
};

static const BYTE expected_item_moniker_comparison_data4[] =
{
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
      '&',0x00, '&',0x00, 'T',0x00, 'E',0x00,
      'S',0x00, 'T',0x00,0x00,0x00,
};

static const BYTE expected_item_moniker_comparison_data5[] =
{
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
      'A',0x00, 'B',0x00, 'T',0x00, 'E',0x00,
      'S',0x00, 'T',0x00,0x00,0x00,
1494 1495
};

1496 1497 1498 1499 1500 1501 1502
static const BYTE expected_item_moniker_comparison_data6[] =
{
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x00,0x00,
};

1503 1504
static const BYTE expected_item_moniker_saved_data[] =
{
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530
     0x02,0x00,0x00,0x00, '!',0x00,0x05,0x00,
     0x00,0x00, 'T', 'e', 's', 't',0x00,
};

static const BYTE expected_item_moniker_saved_data2[] =
{
     0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,
      'T', 'e', 's', 't',0x00,
};

static const BYTE expected_item_moniker_saved_data3[] =
{
     0x01,0x00,0x00,0x00,0x00,0x05,0x00,0x00,
     0x00,'T', 'e', 's', 't',0x00,
};

static const BYTE expected_item_moniker_saved_data4[] =
{
     0x03,0x00,0x00,0x00, '&', '&',0x00,0x05,
     0x00,0x00,0x00, 'T', 'e', 's', 't',0x00,
};

static const BYTE expected_item_moniker_saved_data5[] =
{
     0x03,0x00,0x00,0x00, 'a', 'b',0x00,0x05,
     0x00,0x00,0x00, 'T', 'e', 's', 't',0x00,
1531 1532
};

1533 1534 1535 1536 1537 1538
static const BYTE expected_item_moniker_saved_data6[] =
{
     0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
     0x00,0x00,
};

1539 1540 1541 1542 1543 1544 1545 1546
static const BYTE expected_item_moniker_marshal_data[] =
{
     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
     0x02,0x00,0x00,0x00, '!',0x00,0x05,0x00,
     0x00,0x00, 'T', 'e', 's', 't',0x00,
};

static const BYTE expected_item_moniker_marshal_data2[] =
{
     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x00,0x00,0x00,0x00,0x2e,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,
      'T', 'e', 's', 't',0x00,
};

static const BYTE expected_item_moniker_marshal_data3[] =
{
     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x00,0x00,0x00,0x00,0x32,0x00,0x00,0x00,
     0x01,0x00,0x00,0x00,0x00,0x05,0x00,0x00,
     0x00, 'T', 'e', 's', 't',0x00,
};

static const BYTE expected_item_moniker_marshal_data4[] =
{
     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x00,0x00,0x00,0x00,0x3a,0x00,0x00,0x00,
     0x03,0x00,0x00,0x00, '&', '&',0x00,0x05,
     0x00,0x00,0x00, 'T', 'e', 's', 't',0x00,
};

static const BYTE expected_item_moniker_marshal_data5[] =
{
     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x00,0x00,0x00,0x00,0x3a,0x00,0x00,0x00,
     0x03,0x00,0x00,0x00, 'a', 'b',0x00,0x05,
     0x00,0x00,0x00, 'T', 'e', 's', 't',0x00,
1597 1598
};

1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610
static const BYTE expected_item_moniker_marshal_data6[] =
{
     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
     0x00,0x00,0x00,0x00,0x22,0x00,0x00,0x00,
     0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,
     0x00,0x00,
};

1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
static const BYTE expected_anti_moniker_marshal_data[] =
{
    0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
    0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
    0x01,0x00,0x00,0x00,
};

1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
static const BYTE expected_anti_moniker_marshal_data2[] =
{
    0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
    0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
    0x02,0x00,0x00,0x00,
};

1633 1634 1635 1636 1637
static const BYTE expected_anti_moniker_saved_data[] =
{
    0x01,0x00,0x00,0x00,
};

1638 1639 1640 1641 1642
static const BYTE expected_anti_moniker_saved_data2[] =
{
    0x02,0x00,0x00,0x00,
};

1643 1644 1645 1646 1647 1648 1649
static const BYTE expected_anti_moniker_comparison_data[] =
{
    0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x01,0x00,0x00,0x00,
};

1650 1651 1652 1653 1654 1655 1656
static const BYTE expected_anti_moniker_comparison_data2[] =
{
    0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x02,0x00,0x00,0x00,
};

1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701
static const BYTE expected_gc_moniker_marshal_data[] =
{
    0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
    0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x00,0x00,0x00,0x00,0x2c,0x01,0x00,0x00,
    0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
    0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
    0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
    0x00,0x00,0x54,0x65,0x73,0x74,0x00,0x4d,
    0x45,0x4f,0x57,0x04,0x00,0x00,0x00,0x0f,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
    0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x04,
    0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
    0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,
    0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x02,
    0x00,0x00,0x00,0x23,0x00,0x05,0x00,0x00,
    0x00,0x57,0x69,0x6e,0x65,0x00,
};

static const BYTE expected_gc_moniker_saved_data[] =
{
    0x02,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
    0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
    0x00,0x00,0x00,0x46,0x02,0x00,0x00,0x00,
    0x21,0x00,0x05,0x00,0x00,0x00,0x54,0x65,
    0x73,0x74,0x00,0x04,0x03,0x00,0x00,0x00,
    0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,
    0x00,0x00,0x46,0x02,0x00,0x00,0x00,0x23,
    0x00,0x05,0x00,0x00,0x00,0x57,0x69,0x6e,
    0x65,0x00,
};

static const BYTE expected_gc_moniker_comparison_data[] =
{
    0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
    0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
    0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1702 1703
     '!',0x00, 'T',0x00, 'E',0x00, 'S',0x00,
     'T',0x00,0x00,0x00,0x04,0x03,0x00,0x00,
1704
    0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
1705 1706
    0x00,0x00,0x00,0x46, '#',0x00, 'W',0x00,
     'I',0x00, 'N',0x00, 'E',0x00,0x00,0x00,
1707 1708
};

1709 1710
static void test_moniker(
    const char *testname, IMoniker *moniker,
1711 1712 1713
    const BYTE *expected_moniker_marshal_data, unsigned int sizeof_expected_moniker_marshal_data,
    const BYTE *expected_moniker_saved_data, unsigned int sizeof_expected_moniker_saved_data,
    const BYTE *expected_moniker_comparison_data, unsigned int sizeof_expected_moniker_comparison_data,
1714
    int expected_max_size, LPCWSTR expected_display_name)
Robert Shearman's avatar
Robert Shearman committed
1715
{
1716
    ULARGE_INTEGER max_size;
Robert Shearman's avatar
Robert Shearman committed
1717
    IStream * stream;
1718
    IROTData * rotdata;
Robert Shearman's avatar
Robert Shearman committed
1719 1720 1721 1722
    HRESULT hr;
    HGLOBAL hglobal;
    LPBYTE moniker_data;
    DWORD moniker_size;
1723
    DWORD i, moniker_type;
1724
    BOOL same;
1725
    BYTE buffer[128];
1726
    IMoniker * moniker_proxy;
Robert Shearman's avatar
Robert Shearman committed
1727

1728
    hr = IMoniker_IsDirty(moniker);
1729
    ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08lx\n", testname, hr);
1730

1731
    /* Display Name */
1732
    TEST_DISPLAY_NAME(moniker, expected_display_name);
1733

1734
    hr = IMoniker_IsDirty(moniker);
1735
    ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08lx\n", testname, hr);
1736

1737 1738 1739
    /* IROTData::GetComparisonData test */

    hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
1740
    ok_ole_success(hr, IMoniker_QueryInterface_IID_IROTData);
Robert Shearman's avatar
Robert Shearman committed
1741

1742 1743 1744 1745 1746 1747 1748
    hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &moniker_size);
    ok_ole_success(hr, IROTData_GetComparisonData);

    if (hr != S_OK) moniker_size = 0;

    /* first check we have the right amount of data */
    ok(moniker_size == sizeof_expected_moniker_comparison_data,
1749
        "%s: Size of comparison data differs (expected %d, actual %ld)\n",
1750 1751 1752
        testname, sizeof_expected_moniker_comparison_data, moniker_size);

    /* then do a byte-by-byte comparison */
1753
    same = TRUE;
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767
    for (i = 0; i < min(moniker_size, sizeof_expected_moniker_comparison_data); i++)
    {
        if (expected_moniker_comparison_data[i] != buffer[i])
        {
            same = FALSE;
            break;
        }
    }

    ok(same, "%s: Comparison data differs\n", testname);
    if (!same)
    {
        for (i = 0; i < moniker_size; i++)
        {
1768 1769 1770
            if (i % 8 == 0) printf("     ");
            printf("0x%02x,", buffer[i]);
            if (i % 8 == 7) printf("\n");
1771
        }
1772
        printf("\n");
1773 1774 1775 1776
    }

    IROTData_Release(rotdata);
  
Robert Shearman's avatar
Robert Shearman committed
1777
    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1778
    ok_ole_success(hr, CreateStreamOnHGlobal);
1779 1780
  
    /* Saving */
1781 1782 1783 1784
    moniker_type = 0;
    IMoniker_IsSystemMoniker(moniker, &moniker_type);

    hr = IMoniker_GetSizeMax(moniker, &max_size);
1785
    ok(hr == S_OK, "Failed to get max size, hr %#lx.\n", hr);
1786
    todo_wine_if(moniker_type == MKSYS_GENERICCOMPOSITE)
1787
    ok(expected_max_size == max_size.u.LowPart, "%s: unexpected max size %lu.\n", testname, max_size.u.LowPart);
Robert Shearman's avatar
Robert Shearman committed
1788

1789 1790
    hr = IMoniker_Save(moniker, stream, TRUE);
    ok_ole_success(hr, IMoniker_Save);
Robert Shearman's avatar
Robert Shearman committed
1791 1792 1793 1794 1795 1796 1797 1798 1799

    hr = GetHGlobalFromStream(stream, &hglobal);
    ok_ole_success(hr, GetHGlobalFromStream);

    moniker_size = GlobalSize(hglobal);

    moniker_data = GlobalLock(hglobal);

    /* first check we have the right amount of data */
1800
    ok(moniker_size == round_global_size(sizeof_expected_moniker_saved_data),
1801
        "%s: Size of saved data differs (expected %ld, actual %ld)\n",
1802
        testname, (DWORD)round_global_size(sizeof_expected_moniker_saved_data), moniker_size);
Robert Shearman's avatar
Robert Shearman committed
1803 1804

    /* then do a byte-by-byte comparison */
1805
    same = TRUE;
1806
    for (i = 0; i < min(moniker_size, round_global_size(sizeof_expected_moniker_saved_data)); i++)
Robert Shearman's avatar
Robert Shearman committed
1807
    {
1808
        if (expected_moniker_saved_data[i] != moniker_data[i])
Robert Shearman's avatar
Robert Shearman committed
1809 1810 1811 1812 1813 1814
        {
            same = FALSE;
            break;
        }
    }

1815
    ok(same, "%s: Saved data differs\n", testname);
Robert Shearman's avatar
Robert Shearman committed
1816 1817 1818 1819
    if (!same)
    {
        for (i = 0; i < moniker_size; i++)
        {
1820 1821 1822
            if (i % 8 == 0) printf("     ");
            printf("0x%02x,", moniker_data[i]);
            if (i % 8 == 7) printf("\n");
1823
        }
1824
        printf("\n");
1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846
    }

    GlobalUnlock(hglobal);

    IStream_Release(stream);

    /* Marshaling tests */

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
    ok_ole_success(hr, CreateStreamOnHGlobal);

    hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
    ok_ole_success(hr, CoMarshalInterface);

    hr = GetHGlobalFromStream(stream, &hglobal);
    ok_ole_success(hr, GetHGlobalFromStream);

    moniker_size = GlobalSize(hglobal);

    moniker_data = GlobalLock(hglobal);

    /* first check we have the right amount of data */
1847
    ok(moniker_size == round_global_size(sizeof_expected_moniker_marshal_data),
1848
        "%s: Size of marshaled data differs (expected %ld, actual %ld)\n",
1849
        testname, (DWORD)round_global_size(sizeof_expected_moniker_marshal_data), moniker_size);
1850 1851

    /* then do a byte-by-byte comparison */
1852
    same = TRUE;
1853
    if (expected_moniker_marshal_data)
1854
    {
1855
        for (i = 0; i < min(moniker_size, round_global_size(sizeof_expected_moniker_marshal_data)); i++)
1856
        {
1857 1858 1859 1860 1861
            if (expected_moniker_marshal_data[i] != moniker_data[i])
            {
                same = FALSE;
                break;
            }
1862 1863 1864 1865 1866 1867 1868 1869
        }
    }

    ok(same, "%s: Marshaled data differs\n", testname);
    if (!same)
    {
        for (i = 0; i < moniker_size; i++)
        {
1870 1871 1872
            if (i % 8 == 0) printf("     ");
            printf("0x%02x,", moniker_data[i]);
            if (i % 8 == 7) printf("\n");
Robert Shearman's avatar
Robert Shearman committed
1873
        }
1874
        printf("\n");
Robert Shearman's avatar
Robert Shearman committed
1875 1876 1877 1878 1879
    }

    GlobalUnlock(hglobal);

    IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
1880 1881
    hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker_proxy);
    ok_ole_success(hr, CoUnmarshalInterface);
Robert Shearman's avatar
Robert Shearman committed
1882 1883

    IStream_Release(stream);
1884
    IMoniker_Release(moniker_proxy);
1885 1886 1887 1888
}

static void test_class_moniker(void)
{
1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904
    static const struct parse_test
    {
        const WCHAR *name;
        ULONG eaten;
        HRESULT hr;
    }
    tests[] =
    {
        { L"clsid:11111111-0000-0000-2222-444444444444;extra data:", 54 },
        { L"clsid:11111111-0000-0000-2222-444444444444extra data", 52 },
        { L"clsid:11111111-0000-0000-2222-444444444444:", 43 },
        { L"clsid:11111111-0000-0000-2222-444444444444", 42 },
        { L"clsid:{11111111-0000-0000-2222-444444444444}", 44 },
        { L"clsid:{11111111-0000-0000-2222-444444444444", 0, MK_E_SYNTAX },
        { L"clsid:11111111-0000-0000-2222-444444444444}", 43 },
    };
1905
    IMoniker *moniker, *moniker2, *inverse, *reduced, *anti, *c;
1906
    IEnumMoniker *enummoniker;
1907 1908 1909 1910
    ULONG length, eaten;
    ULARGE_INTEGER size;
    LARGE_INTEGER pos;
    IROTData *rotdata;
1911 1912
    HRESULT hr;
    DWORD hash;
1913 1914 1915
    IBindCtx *bindctx;
    IUnknown *unknown;
    FILETIME filetime;
1916 1917
    IStream *stream;
    BYTE buffer[100];
1918 1919 1920
    HGLOBAL hglobal;
    unsigned int i;
    DWORD *data;
1921 1922

    hr = CreateBindCtx(0, &bindctx);
1923
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1924

1925 1926 1927 1928
    for (i = 0; i < ARRAY_SIZE(tests); ++i)
    {
        eaten = 0xdeadbeef;
        hr = MkParseDisplayName(bindctx, tests[i].name, &eaten, &moniker);
1929
        todo_wine_if(i == 5)
1930 1931
        ok(hr == tests[i].hr, "%u: unexpected hr %#lx.\n", i, hr);
        ok(eaten == tests[i].eaten, "%u: unexpected eaten length %lu, expected %lu.\n", i, eaten, tests[i].eaten);
1932 1933 1934 1935 1936 1937 1938
        if (SUCCEEDED(hr))
        {
            TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER);
            IMoniker_Release(moniker);
        }
    }

1939 1940
    /* Extended syntax, handled by class moniker directly, only CLSID is meaningful for equality. */
    hr = MkParseDisplayName(bindctx, L"clsid:11111111-0000-0000-2222-444444444444;extra data:", &eaten, &moniker);
1941 1942
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(eaten == 54, "Unexpected length %lu.\n", eaten);
1943

1944
    hr = MkParseDisplayName(bindctx, L"clsid:11111111-0000-0000-2222-444444444444;different extra data:", &eaten, &moniker2);
1945
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1946

1947 1948 1949
    TEST_DISPLAY_NAME(moniker, L"clsid:11111111-0000-0000-2222-444444444444;extra data:");
    TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER);
    hr = IMoniker_GetSizeMax(moniker, &size);
1950 1951
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(size.LowPart == 44, "Unexpected size %lu.\n", size.LowPart);
1952

1953
    TEST_MONIKER_TYPE(moniker2, MKSYS_CLASSMONIKER);
1954

1955
    hr = IMoniker_IsEqual(moniker, moniker2);
1956
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1957

1958
    hr = IMoniker_IsEqual(moniker2, moniker);
1959
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1960

1961 1962
    IMoniker_Release(moniker2);
    IMoniker_Release(moniker);
1963

1964 1965
    /* From persistent state */
    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1966
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1967 1968

    hr = CreateClassMoniker(&GUID_NULL, &moniker);
1969
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1970

1971 1972 1973 1974 1975 1976 1977
    check_interface(moniker, &IID_IMoniker, TRUE);
    check_interface(moniker, &IID_IPersist, TRUE);
    check_interface(moniker, &IID_IPersistStream, TRUE);
    check_interface(moniker, &CLSID_ClassMoniker, TRUE);
    check_interface(moniker, &IID_IROTData, TRUE);
    check_interface(moniker, &IID_IMarshal, TRUE);

1978
    hr = IMoniker_GetSizeMax(moniker, &size);
1979 1980
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(size.QuadPart == 20, "Unexpected size %lu.\n", size.LowPart);
1981 1982

    hr = IStream_Write(stream, &CLSID_StdComponentCategoriesMgr, sizeof(CLSID), NULL);
1983
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1984 1985
    length = 5 * sizeof(WCHAR);
    hr = IStream_Write(stream, &length, sizeof(length), NULL);
1986
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1987
    hr = IStream_Write(stream, L"data", length, NULL);
1988
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1989 1990
    pos.QuadPart = 0;
    hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
1991
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1992 1993

    hr = IMoniker_Load(moniker, stream);
1994
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1995 1996

    hr = IMoniker_GetSizeMax(moniker, &size);
1997 1998
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(size.QuadPart == 30, "Unexpected size %lu.\n", size.LowPart);
1999
    TEST_DISPLAY_NAME(moniker, L"clsid:0002E005-0000-0000-C000-000000000046data:");
2000 2001 2002
    IStream_Release(stream);

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2003
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2004 2005

    hr = GetHGlobalFromStream(stream, &hglobal);
2006
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2007 2008

    hr = IMoniker_Save(moniker, stream, FALSE);
2009
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2010 2011 2012

    length = GlobalSize(hglobal);
    data = GlobalLock(hglobal);
2013
    ok(length == 30, "Unexpected stream size %lu.\n", length);
2014 2015
    ok(IsEqualGUID((CLSID *)data, &CLSID_StdComponentCategoriesMgr), "Unexpected clsid.\n");
    data += sizeof(CLSID) / sizeof(*data);
2016
    ok(*data == 10, "Unexpected data length %lu.\n", *data);
2017 2018 2019 2020
    data++;
    ok(!lstrcmpW((WCHAR *)data, L"data"), "Unexpected data.\n");

    IStream_Release(stream);
2021 2022 2023

    /* Extra data does not affect comparison */
    hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
2024
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2025
    hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &length);
2026 2027
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(length == sizeof(expected_class_moniker_comparison_data), "Unexpected comparison data length %lu.\n", length);
2028 2029 2030 2031 2032
    ok(!memcmp(buffer, expected_class_moniker_comparison_data, length), "Unexpected data.\n");
    IROTData_Release(rotdata);

    IMoniker_Release(moniker);

2033
    hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker);
2034
    ok_ole_success(hr, CreateClassMoniker);
2035

2036
    hr = IMoniker_GetSizeMax(moniker, &size);
2037 2038
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(size.LowPart == 20, "Unexpected size %lu.\n", size.LowPart);
2039

2040
    hr = IMoniker_QueryInterface(moniker, &CLSID_ClassMoniker, (void **)&unknown);
2041
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2042 2043
    ok(unknown == (IUnknown *)moniker, "Unexpected interface.\n");
    IUnknown_Release(unknown);
2044 2045 2046 2047

    test_moniker("class moniker", moniker, 
        expected_class_moniker_marshal_data, sizeof(expected_class_moniker_marshal_data),
        expected_class_moniker_saved_data, sizeof(expected_class_moniker_saved_data),
2048
        expected_class_moniker_comparison_data, sizeof(expected_class_moniker_comparison_data),
2049
        sizeof(expected_class_moniker_saved_data), expected_class_moniker_display_name);
2050 2051 2052 2053 2054 2055 2056

    /* Hashing */

    hr = IMoniker_Hash(moniker, &hash);
    ok_ole_success(hr, IMoniker_Hash);

    ok(hash == CLSID_StdComponentCategoriesMgr.Data1,
2057
        "Hash value != Data1 field of clsid, instead was 0x%08lx\n",
2058 2059 2060
        hash);

    /* IsSystemMoniker test */
2061
    TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER);
2062

2063
    /* IsRunning test */
2064
    hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
2065
    ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08lx\n", hr);
2066

2067
    hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
2068
    ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08lx\n", hr);
2069 2070

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
2071
    ok(hr == MK_E_UNAVAILABLE, "IMoniker_GetTimeOfLastChange should return MK_E_UNAVAILABLE, not 0x%08lx\n", hr);
2072 2073

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
2074
    ok_ole_success(hr, IMoniker_BindToObject);
2075 2076 2077 2078 2079 2080 2081
    IUnknown_Release(unknown);

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
    ok_ole_success(hr, IMoniker_BindToStorage);
    IUnknown_Release(unknown);

    hr = IMoniker_Inverse(moniker, &inverse);
2082
    ok(hr == S_OK, "Failed to get inverse, hr %#lx.\n", hr);
2083
    TEST_MONIKER_TYPE(inverse, MKSYS_ANTIMONIKER);
2084 2085
    IMoniker_Release(inverse);

2086 2087
    /* Reduce() */
    hr = IMoniker_Reduce(moniker, NULL, MKRREDUCE_ALL, NULL, &reduced);
2088
    ok(hr == MK_S_REDUCED_TO_SELF, "Unexpected hr %#lx.\n", hr);
2089 2090 2091
    ok(reduced == moniker, "Unexpected moniker.\n");
    IMoniker_Release(reduced);

2092 2093 2094
    /* Enum() */
    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker, TRUE, &enummoniker);
2095
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2096 2097 2098 2099
    ok(!enummoniker, "Unexpected pointer.\n");

    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker, FALSE, &enummoniker);
2100
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2101 2102 2103
    ok(!enummoniker, "Unexpected pointer.\n");

    hr = IMoniker_Enum(moniker, FALSE, NULL);
2104
    todo_wine
2105
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2106

2107 2108
    IBindCtx_Release(bindctx);

2109 2110 2111 2112 2113
    /* ComposeWith() */

    /* C + A -> () */
    anti = create_antimoniker(1);
    hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
2114
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
2115 2116 2117
    ok(!moniker2, "Unexpected pointer.\n");
    IMoniker_Release(anti);

2118
    /* C + A2 -> () */
2119 2120
    anti = create_antimoniker(2);
    hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
2121
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
2122 2123 2124
    ok(!moniker2, "Unexpected pointer.\n");
    IMoniker_Release(anti);

2125 2126
    /* C + (A,I) -> I */
    hr = create_moniker_from_desc("CA1I1", &c);
2127
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2128
    hr = IMoniker_ComposeWith(moniker, c, TRUE, &moniker2);
2129
    ok(hr == MK_E_NEEDGENERIC, "Unexpected hr %#lx.\n", hr);
2130
    hr = IMoniker_ComposeWith(moniker, c, FALSE, &moniker2);
2131
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2132 2133 2134 2135 2136 2137
    TEST_MONIKER_TYPE(moniker2, MKSYS_ITEMMONIKER);
    IMoniker_Release(moniker2);
    IMoniker_Release(c);

    /* C + (A2,I) -> I */
    hr = create_moniker_from_desc("CA1I1", &c);
2138
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2139
    hr = IMoniker_ComposeWith(moniker, c, TRUE, &moniker2);
2140
    ok(hr == MK_E_NEEDGENERIC, "Unexpected hr %#lx.\n", hr);
2141
    hr = IMoniker_ComposeWith(moniker, c, FALSE, &moniker2);
2142
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2143 2144 2145 2146
    TEST_MONIKER_TYPE(moniker2, MKSYS_ITEMMONIKER);
    IMoniker_Release(moniker2);
    IMoniker_Release(c);

2147
    IMoniker_Release(moniker);
Robert Shearman's avatar
Robert Shearman committed
2148 2149
}

2150 2151
static void test_file_moniker(WCHAR* path)
{
2152
    IMoniker *moniker1 = NULL, *moniker2 = NULL, *m3, *inverse, *reduced, *anti;
2153
    IEnumMoniker *enummoniker;
2154
    IBindCtx *bind_ctx;
2155
    IStream *stream;
2156
    IUnknown *unk;
2157
    DWORD hash;
2158 2159 2160 2161 2162
    HRESULT hr;

    hr = CreateFileMoniker(path, &moniker1);
    ok_ole_success(hr, CreateFileMoniker); 

2163
    hr = IMoniker_QueryInterface(moniker1, &CLSID_FileMoniker, (void **)&unk);
2164
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2165 2166
    ok(unk == (IUnknown *)moniker1, "Unexpected interface.\n");
    IUnknown_Release(unk);
2167

2168
    hr = IMoniker_Inverse(moniker1, &inverse);
2169
    ok(hr == S_OK, "Failed to get inverse, hr %#lx.\n", hr);
2170
    TEST_MONIKER_TYPE(inverse, MKSYS_ANTIMONIKER);
2171 2172
    IMoniker_Release(inverse);

2173
    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2174
    ok_ole_success(hr, CreateStreamOnHGlobal);
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190

    /* Marshal */
    hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker1, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
    ok_ole_success(hr, CoMarshalInterface);
    
    /* Rewind */
    hr = IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
    ok_ole_success(hr, IStream_Seek);

    /* Unmarshal */
    hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void**)&moniker2);
    ok_ole_success(hr, CoUnmarshalInterface);

    hr = IMoniker_IsEqual(moniker1, moniker2);
    ok_ole_success(hr, IsEqual);

2191 2192
    /* Reduce() */
    hr = CreateBindCtx(0, &bind_ctx);
2193
    ok(hr == S_OK, "Failed to create bind context, hr %#lx.\n", hr);
2194 2195

    hr = IMoniker_Reduce(moniker1, NULL, MKRREDUCE_ALL, NULL, &reduced);
2196
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2197

2198
    hr = IMoniker_Reduce(moniker1, bind_ctx, MKRREDUCE_ALL, NULL, NULL);
2199
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2200 2201 2202

    m3 = anti = create_antimoniker(1);
    hr = IMoniker_Reduce(moniker1, bind_ctx, MKRREDUCE_ALL, &m3, &reduced);
2203
    ok(hr == MK_S_REDUCED_TO_SELF, "Unexpected hr %#lx.\n", hr);
2204 2205 2206 2207 2208
    ok(reduced == moniker1, "Unexpected moniker.\n");
    ok(m3 == anti, "Unexpected pointer.\n");
    IMoniker_Release(reduced);
    IMoniker_Release(anti);

2209
    hr = IMoniker_Reduce(moniker1, bind_ctx, MKRREDUCE_ALL, NULL, &reduced);
2210
    ok(hr == MK_S_REDUCED_TO_SELF, "Unexpected hr %#lx.\n", hr);
2211 2212 2213
    ok(reduced == moniker1, "Unexpected moniker.\n");
    IMoniker_Release(reduced);

2214 2215 2216
    /* Enum() */
    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker1, TRUE, &enummoniker);
2217
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2218 2219 2220 2221
    ok(!enummoniker, "Unexpected pointer.\n");

    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker1, FALSE, &enummoniker);
2222
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2223 2224 2225
    ok(!enummoniker, "Unexpected pointer.\n");

    hr = IMoniker_Enum(moniker1, FALSE, NULL);
2226
    todo_wine
2227
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2228

2229 2230
    IBindCtx_Release(bind_ctx);

2231
    IStream_Release(stream);
2232 2233 2234 2235 2236 2237 2238
    IMoniker_Release(moniker2);

    /* ComposeWith() */

    /* F + A -> () */
    anti = create_antimoniker(1);
    hr = IMoniker_ComposeWith(moniker1, anti, TRUE, &moniker2);
2239
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
2240 2241 2242 2243 2244 2245
    ok(!moniker2, "Unexpected pointer.\n");
    IMoniker_Release(anti);

    /* I + A2 -> (A) */
    anti = create_antimoniker(2);
    hr = IMoniker_ComposeWith(moniker1, anti, TRUE, &moniker2);
2246
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
2247 2248
    TEST_MONIKER_TYPE(moniker2, MKSYS_ANTIMONIKER);
    hr = IMoniker_Hash(moniker2, &hash);
2249
    ok(hr == S_OK, "Failed to get hash, hr %#lx.\n", hr);
2250 2251
    ok(hash == 0x80000001, "Unexpected hash.\n");
    IMoniker_Release(moniker2);
2252

2253 2254 2255
    IMoniker_Release(anti);

    IMoniker_Release(moniker1);
2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270
}

static void test_file_monikers(void)
{
    static WCHAR wszFile[][30] = {
        {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0},
        {'\\', '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},
        /* These map to themselves in Windows-1252 & 932 (Shift-JIS) */
        {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0},
        /* U+2020 = DAGGER     = 0x86 (1252) = 0x813f (932)
         * U+20AC = EURO SIGN  = 0x80 (1252) =  undef (932)
         * U+0100 .. = Latin extended-A
         */ 
        {0x20ac, 0x2020, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c,  0},
        };
2271
    WCHAR filename[MAX_PATH], path[MAX_PATH];
2272
    IMoniker *moniker, *moniker2;
2273 2274 2275 2276 2277
    BIND_OPTS bind_opts;
    IStorage *storage;
    IBindCtx *bindctx;
    STATSTG statstg;
    HRESULT hr;
2278 2279 2280 2281
    int i; 

    trace("ACP is %u\n", GetACP());

2282
    for (i = 0; i < ARRAY_SIZE(wszFile); ++i)
2283 2284
    {
        int j ;
2285 2286 2287 2288 2289 2290 2291 2292 2293 2294
        if (i == 2)
        {
            BOOL used;
            WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, wszFile[i], -1, NULL, 0, NULL, &used );
            if (used)
            {
                skip("string 2 doesn't round trip in codepage %u\n", GetACP() );
                continue;
            }
        }
2295 2296 2297 2298 2299 2300
        for (j = lstrlenW(wszFile[i]); j > 0; --j)
        {
            wszFile[i][j] = 0;
            test_file_moniker(wszFile[i]);
        }
    }
2301 2302 2303 2304 2305 2306 2307

    /* BindToStorage() */
    GetTempPathW(MAX_PATH, path);
    GetTempFileNameW(path, L"stg", 1, filename);

    hr = StgCreateStorageEx(filename, STGM_SHARE_EXCLUSIVE | STGM_READWRITE, STGFMT_STORAGE,
            0, NULL, NULL, &IID_IStorage, (void **)&storage);
2308
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2309 2310 2311
    IStorage_Release(storage);

    hr = CreateFileMoniker(filename, &moniker);
2312
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2313

2314
    check_interface(moniker, &IID_IMoniker, TRUE);
2315
    todo_wine
2316 2317 2318 2319 2320 2321
    check_interface(moniker, &IID_IPersist, FALSE);
    check_interface(moniker, &IID_IPersistStream, TRUE);
    check_interface(moniker, &CLSID_FileMoniker, TRUE);
    check_interface(moniker, &IID_IROTData, TRUE);
    check_interface(moniker, &IID_IMarshal, TRUE);

2322
    hr = IMoniker_BindToStorage(moniker, NULL, NULL, &IID_IStorage, (void **)&storage);
2323
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2324 2325

    hr = CreateBindCtx(0, &bindctx);
2326
    ok(hr == S_OK, "Failed to create bind context, hr %#lx.\n", hr);
2327 2328

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IStorage, (void **)&storage);
2329
    ok(hr == STG_E_INVALIDFLAG, "Unexpected hr %#lx.\n", hr);
2330 2331 2332 2333

    bind_opts.cbStruct = sizeof(bind_opts);
    bind_opts.grfMode = STGM_READWRITE | STGM_SHARE_DENY_WRITE;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2334
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2335 2336

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IStorage, (void **)&storage);
2337
    ok(hr == STG_E_INVALIDFLAG, "Unexpected hr %#lx.\n", hr);
2338 2339 2340

    bind_opts.grfMode = STGM_READ | STGM_SHARE_DENY_WRITE;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2341
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2342 2343

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IStorage, (void **)&storage);
2344
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2345 2346 2347

    memset(&statstg, 0, sizeof(statstg));
    hr = IStorage_Stat(storage, &statstg, STATFLAG_NONAME);
2348 2349
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(statstg.grfMode == (STGM_READ | STGM_SHARE_DENY_WRITE), "Unexpected mode %#lx.\n", statstg.grfMode);
2350 2351 2352 2353 2354 2355

    IStorage_Release(storage);
    IBindCtx_Release(bindctx);
    IMoniker_Release(moniker);

    DeleteFileW(filename);
2356 2357 2358

    /* IsEqual() */
    hr = CreateFileMoniker(L"test.bmp", &moniker);
2359
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2360 2361

    hr = CreateFileMoniker(L"TEST.bmp", &moniker2);
2362
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2363 2364

    hr = IMoniker_IsEqual(moniker, moniker2);
2365
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2366 2367

    hr = IMoniker_IsEqual(moniker, NULL);
2368
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2369 2370 2371

    IMoniker_Release(moniker2);
    IMoniker_Release(moniker);
2372 2373
}

2374
static void test_item_moniker(void)
2375
{
2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403
    static const char item_moniker_unicode_delim_stream[] =
    {
        0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, '!',
        0x00, 0x02, 0x00, 0x00, 0x00,  'A', 0x00,
    };
    static const char item_moniker_unicode_item_stream[] =
    {
        0x02, 0x00, 0x00, 0x00,  '!', 0x00, 0x05, 0x00,
        0x00, 0x00, 0xff, 0xff, 0x00,  'B', 0x00,
    };
    static const char item_moniker_unicode_delim_item_stream[] =
    {
        0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,  '!',
        0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
        0x00,  'C', 0x00,
    };
    static struct
    {
        const char *data;
        int data_len;
        const WCHAR *display_name;
    }
    item_moniker_data[] =
    {
        { item_moniker_unicode_delim_stream, sizeof(item_moniker_unicode_delim_stream), L"!A" },
        { item_moniker_unicode_item_stream, sizeof(item_moniker_unicode_item_stream), L"!B" },
        { item_moniker_unicode_delim_item_stream, sizeof(item_moniker_unicode_delim_item_stream), L"!C" },
    };
2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420
    static const struct
    {
        const WCHAR *delim1;
        const WCHAR *item1;
        const WCHAR *delim2;
        const WCHAR *item2;
        HRESULT hr;
    } isequal_tests[] =
    {
        { L"!", L"Item1", L"!", L"ITEM1", S_OK },
        { NULL, L"Item1", L"!", L"ITEM1", S_OK },
        { L"", L"Item1", L"!", L"ITEM1", S_OK },
        { L"&", L"Item1", L"!", L"ITEM1", S_OK },
        {L"&&", L"Item1", L"&", L"&Item1", S_FALSE },
        { NULL, L"Item1", NULL, L"Item2", S_FALSE },
        { NULL, L"Item1", NULL, L"ITEM1", S_OK },
    };
2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
    static const struct
    {
        const WCHAR *delim;
        const WCHAR *item;
        DWORD hash;
    } hash_tests[] =
    {
        { L"!", L"Test", 0x73c },
        { L"%", L"Test", 0x73c },
        { L"%", L"TEST", 0x73c },
        { L"%", L"T", 0x54 },
        { L"%", L"A", 0x41 },
        { L"%", L"a", 0x41 },
    };
2435 2436 2437 2438 2439
    static const char *methods_isrunning[] =
    {
        "Moniker_IsRunning",
        NULL
    };
2440
    IMoniker *moniker, *moniker1, *moniker2, *moniker3, *reduced, *anti, *inverse, *c;
2441
    DWORD i, hash, eaten, cookie;
2442
    HRESULT hr;
2443 2444
    IBindCtx *bindctx;
    IUnknown *unknown;
2445
    static const WCHAR wszDelimiter[] = {'!',0};
2446
    static const WCHAR wszObjectName[] = {'T','e','s','t',0};
2447
    static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 };
2448
    struct test_moniker *container_moniker;
2449
    WCHAR displayname[16] = L"display name";
2450
    IEnumMoniker *enummoniker;
2451
    IRunningObjectTable *rot;
2452
    BIND_OPTS bind_opts;
2453 2454
    LARGE_INTEGER pos;
    IStream *stream;
2455

2456
    hr = CreateItemMoniker(NULL, wszObjectName, &moniker);
2457
    ok(hr == S_OK, "Failed to create item moniker, hr %#lx.\n", hr);
2458

2459
    hr = IMoniker_QueryInterface(moniker, &CLSID_ItemMoniker, (void **)&unknown);
2460
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2461 2462
    ok(unknown == (IUnknown *)moniker, "Unexpected interface.\n");
    IUnknown_Release(unknown);
2463

2464 2465 2466 2467
    test_moniker("item moniker 2", moniker,
        expected_item_moniker_marshal_data2, sizeof(expected_item_moniker_marshal_data2),
        expected_item_moniker_saved_data2, sizeof(expected_item_moniker_saved_data2),
        expected_item_moniker_comparison_data2, sizeof(expected_item_moniker_comparison_data2),
2468
        46, L"Test");
2469 2470 2471 2472

    IMoniker_Release(moniker);

    hr = CreateItemMoniker(L"", wszObjectName, &moniker);
2473
    ok(hr == S_OK, "Failed to create item moniker, hr %#lx.\n", hr);
2474 2475 2476 2477 2478

    test_moniker("item moniker 3", moniker,
        expected_item_moniker_marshal_data3, sizeof(expected_item_moniker_marshal_data3),
        expected_item_moniker_saved_data3, sizeof(expected_item_moniker_saved_data3),
        expected_item_moniker_comparison_data2, sizeof(expected_item_moniker_comparison_data2),
2479
        50, L"Test");
2480 2481 2482 2483

    IMoniker_Release(moniker);

    hr = CreateItemMoniker(L"&&", wszObjectName, &moniker);
2484
    ok(hr == S_OK, "Failed to create item moniker, hr %#lx.\n", hr);
2485 2486 2487 2488 2489

    test_moniker("item moniker 4", moniker,
        expected_item_moniker_marshal_data4, sizeof(expected_item_moniker_marshal_data4),
        expected_item_moniker_saved_data4, sizeof(expected_item_moniker_saved_data4),
        expected_item_moniker_comparison_data4, sizeof(expected_item_moniker_comparison_data4),
2490
        58, L"&&Test");
2491 2492 2493 2494

    IMoniker_Release(moniker);

    hr = CreateItemMoniker(L"ab", wszObjectName, &moniker);
2495
    ok(hr == S_OK, "Failed to create item moniker, hr %#lx.\n", hr);
2496 2497 2498 2499 2500

    test_moniker("item moniker 5", moniker,
        expected_item_moniker_marshal_data5, sizeof(expected_item_moniker_marshal_data5),
        expected_item_moniker_saved_data5, sizeof(expected_item_moniker_saved_data5),
        expected_item_moniker_comparison_data5, sizeof(expected_item_moniker_comparison_data5),
2501
        58, L"abTest");
2502

2503 2504
    /* Serialize and load back. */
    hr = CreateItemMoniker(NULL, L"object", &moniker2);
2505
    ok(hr == S_OK, "Failed to create item moniker, hr %#lx.\n", hr);
2506 2507

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2508
    ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
2509 2510

    hr = CreateBindCtx(0, &bindctx);
2511
    ok(hr == S_OK, "Failed to create bind context, hr %#lx.\n", hr);
2512 2513 2514 2515 2516

    for (i = 0; i < ARRAY_SIZE(item_moniker_data); ++i)
    {
        pos.QuadPart = 0;
        hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2517
        ok(hr == S_OK, "Failed to seek stream, hr %#lx.\n", hr);
2518 2519

        hr = IStream_Write(stream, item_moniker_data[i].data, item_moniker_data[i].data_len, NULL);
2520
        ok(hr == S_OK, "Failed to write stream contents, hr %#lx.\n", hr);
2521 2522 2523

        pos.QuadPart = 0;
        hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2524
        ok(hr == S_OK, "Failed to seek stream, hr %#lx.\n", hr);
2525 2526

        hr = IMoniker_Load(moniker2, stream);
2527
        ok(hr == S_OK, "Failed to load moniker, hr %#lx.\n", hr);
2528

2529
        TEST_DISPLAY_NAME(moniker2, item_moniker_data[i].display_name);
2530 2531 2532 2533 2534
    }

    IStream_Release(stream);

    IMoniker_Release(moniker2);
2535 2536
    IMoniker_Release(moniker);

2537 2538 2539 2540 2541
    /* Hashing */

    for (i = 0; i < ARRAY_SIZE(hash_tests); ++i)
    {
        hr = CreateItemMoniker(hash_tests[i].delim, hash_tests[i].item, &moniker);
2542
        ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2543 2544

        hr = IMoniker_Hash(moniker, &hash);
2545 2546
        ok(hr == S_OK, "Failed to get hash value, hr %#lx.\n", hr);
        ok(hash == hash_tests[i].hash, "%ld: unexpected hash value %#lx.\n", i, hash);
2547 2548 2549 2550

        IMoniker_Release(moniker);
    }

2551
    hr = CreateItemMoniker(wszDelimiter, wszObjectName, &moniker);
2552 2553
    ok_ole_success(hr, CreateItemMoniker);

2554
    test_moniker("item moniker 1", moniker,
2555 2556
        expected_item_moniker_marshal_data, sizeof(expected_item_moniker_marshal_data),
        expected_item_moniker_saved_data, sizeof(expected_item_moniker_saved_data),
2557
        expected_item_moniker_comparison_data, sizeof(expected_item_moniker_comparison_data),
2558
        54, expected_display_name);
2559 2560

    /* IsSystemMoniker test */
2561
    TEST_MONIKER_TYPE(moniker, MKSYS_ITEMMONIKER);
2562

2563 2564
    container_moniker = create_test_moniker();

2565
    /* IsRunning test */
2566
    hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
2567
    ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08lx\n", hr);
2568

2569
    hr = IMoniker_IsRunning(moniker, NULL, &container_moniker->IMoniker_iface, NULL);
2570
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2571

2572
    hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
2573
    ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08lx\n", hr);
2574

2575
    hr = CreateItemMoniker(wszDelimiter, wszObjectName, &moniker2);
2576
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2577
    hr = IMoniker_IsRunning(moniker, bindctx, NULL, moniker2);
2578
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2579 2580 2581 2582
    IMoniker_Release(moniker2);

    /* Different moniker as newly running. */
    hr = CreateItemMoniker(wszDelimiter, L"Item123", &moniker2);
2583
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2584 2585

    hr = IMoniker_IsRunning(moniker, bindctx, NULL, moniker2);
2586
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
2587 2588

    hr = IBindCtx_GetRunningObjectTable(bindctx, &rot);
2589
    ok(hr == S_OK, "Failed to get ROT, hr %#lx.\n", hr);
2590 2591

    hr = IRunningObjectTable_Register(rot, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)moniker, moniker, &cookie);
2592
    ok(hr == S_OK, "Failed to register, hr %#lx.\n", hr);
2593 2594

    hr = IRunningObjectTable_IsRunning(rot, moniker);
2595
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2596 2597

    hr = IMoniker_IsRunning(moniker, bindctx, NULL, moniker2);
2598
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
2599 2600

    hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
2601
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2602 2603

    hr = IRunningObjectTable_Revoke(rot, cookie);
2604
    ok(hr == S_OK, "Failed to revoke registration, hr %#lx.\n", hr);
2605 2606 2607 2608 2609

    IRunningObjectTable_Release(rot);

    expected_method_list = methods_isrunning;
    hr = IMoniker_IsRunning(moniker, bindctx, &container_moniker->IMoniker_iface, NULL);
2610
    ok(hr == 0x8beef000, "Unexpected hr %#lx.\n", hr);
2611 2612 2613

    expected_method_list = methods_isrunning;
    hr = IMoniker_IsRunning(moniker, bindctx, &container_moniker->IMoniker_iface, moniker2);
2614
    ok(hr == 0x8beef000, "Unexpected hr %#lx.\n", hr);
2615
    expected_method_list = NULL;
2616 2617 2618

    IMoniker_Release(moniker2);

2619
    /* BindToObject() */
2620
    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
2621
    ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08lx\n", hr);
2622

2623
    hr = IMoniker_BindToObject(moniker, bindctx, &container_moniker->IMoniker_iface, &IID_IUnknown, (void **)&unknown);
2624
    ok(hr == (0x8bee0000 | BINDSPEED_INDEFINITE), "Unexpected hr %#lx.\n", hr);
2625 2626 2627

    bind_opts.cbStruct = sizeof(bind_opts);
    hr = IBindCtx_GetBindOptions(bindctx, &bind_opts);
2628
    ok(hr == S_OK, "Failed to get bind options, hr %#lx.\n", hr);
2629 2630 2631

    bind_opts.dwTickCountDeadline = 1;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2632
    ok(hr == S_OK, "Failed to set bind options, hr %#lx.\n", hr);
2633
    hr = IMoniker_BindToObject(moniker, bindctx, &container_moniker->IMoniker_iface, &IID_IUnknown, (void **)&unknown);
2634
    ok(hr == (0x8bee0000 | BINDSPEED_IMMEDIATE), "Unexpected hr %#lx.\n", hr);
2635 2636 2637

    bind_opts.dwTickCountDeadline = 2499;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2638
    ok(hr == S_OK, "Failed to set bind options, hr %#lx.\n", hr);
2639
    hr = IMoniker_BindToObject(moniker, bindctx, &container_moniker->IMoniker_iface, &IID_IUnknown, (void **)&unknown);
2640
    ok(hr == (0x8bee0000 | BINDSPEED_IMMEDIATE), "Unexpected hr %#lx.\n", hr);
2641 2642 2643

    bind_opts.dwTickCountDeadline = 2500;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2644
    ok(hr == S_OK, "Failed to set bind options, hr %#lx.\n", hr);
2645
    hr = IMoniker_BindToObject(moniker, bindctx, &container_moniker->IMoniker_iface, &IID_IUnknown, (void **)&unknown);
2646
    ok(hr == (0x8bee0000 | BINDSPEED_MODERATE), "Unexpected hr %#lx.\n", hr);
2647

2648
    /* BindToStorage() */
2649
    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
2650
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2651

2652
    hr = IMoniker_BindToStorage(moniker, bindctx, &container_moniker->IMoniker_iface, &IID_IUnknown, (void **)&unknown);
2653
    ok(hr == 0x8bee0001, "Unexpected hr %#lx.\n", hr);
2654

2655 2656
    /* ParseDisplayName() */
    hr = IMoniker_ParseDisplayName(moniker, bindctx, NULL, displayname, &eaten, &moniker2);
2657
    ok(hr == MK_E_SYNTAX, "Unexpected hr %#lx.\n", hr);
2658 2659 2660

    bind_opts.dwTickCountDeadline = 0;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2661
    ok(hr == S_OK, "Failed to set bind options, hr %#lx.\n", hr);
2662
    hr = IMoniker_ParseDisplayName(moniker, bindctx, &container_moniker->IMoniker_iface, displayname, &eaten, &moniker2);
2663
    ok(hr == (0x8bee0000 | BINDSPEED_INDEFINITE), "Unexpected hr %#lx.\n", hr);
2664 2665 2666

    bind_opts.dwTickCountDeadline = 1;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2667
    ok(hr == S_OK, "Failed to set bind options, hr %#lx.\n", hr);
2668
    hr = IMoniker_ParseDisplayName(moniker, bindctx, &container_moniker->IMoniker_iface, displayname, &eaten, &moniker2);
2669
    ok(hr == (0x8bee0000 | BINDSPEED_IMMEDIATE), "Unexpected hr %#lx.\n", hr);
2670 2671 2672

    bind_opts.dwTickCountDeadline = 2499;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2673
    ok(hr == S_OK, "Failed to set bind options, hr %#lx.\n", hr);
2674
    hr = IMoniker_ParseDisplayName(moniker, bindctx, &container_moniker->IMoniker_iface, displayname, &eaten, &moniker2);
2675
    ok(hr == (0x8bee0000 | BINDSPEED_IMMEDIATE), "Unexpected hr %#lx.\n", hr);
2676 2677 2678

    bind_opts.dwTickCountDeadline = 2500;
    hr = IBindCtx_SetBindOptions(bindctx, &bind_opts);
2679
    ok(hr == S_OK, "Failed to set bind options, hr %#lx.\n", hr);
2680
    hr = IMoniker_ParseDisplayName(moniker, bindctx, &container_moniker->IMoniker_iface, displayname, &eaten, &moniker2);
2681
    ok(hr == (0x8bee0000 | BINDSPEED_MODERATE), "Unexpected hr %#lx.\n", hr);
2682 2683

    IMoniker_Release(&container_moniker->IMoniker_iface);
2684 2685 2686 2687

    IBindCtx_Release(bindctx);

    hr = IMoniker_Inverse(moniker, &inverse);
2688
    ok(hr == S_OK, "Failed to get inverse, hr %#lx.\n", hr);
2689
    TEST_MONIKER_TYPE(inverse, MKSYS_ANTIMONIKER);
2690 2691
    IMoniker_Release(inverse);

2692 2693
    /* Reduce() */
    hr = IMoniker_Reduce(moniker, NULL, MKRREDUCE_ALL, NULL, &reduced);
2694
    ok(hr == MK_S_REDUCED_TO_SELF, "Unexpected hr %#lx.\n", hr);
2695 2696 2697
    ok(reduced == moniker, "Unexpected moniker.\n");
    IMoniker_Release(reduced);

2698 2699 2700
    /* Enum() */
    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker, TRUE, &enummoniker);
2701
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2702 2703 2704 2705
    ok(!enummoniker, "Unexpected pointer.\n");

    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker, FALSE, &enummoniker);
2706
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2707 2708 2709
    ok(!enummoniker, "Unexpected pointer.\n");

    hr = IMoniker_Enum(moniker, FALSE, NULL);
2710
    todo_wine
2711
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2712

2713
    hr = IMoniker_IsEqual(moniker, NULL);
2714
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2715

2716
    IMoniker_Release(moniker);
2717 2718 2719 2720 2721

    /* IsEqual */
    for (i = 0; i < ARRAY_SIZE(isequal_tests); ++i)
    {
        hr = CreateItemMoniker(isequal_tests[i].delim1, isequal_tests[i].item1, &moniker);
2722
        ok(hr == S_OK, "Failed to create moniker, hr %#lx.\n", hr);
2723 2724

        hr = CreateItemMoniker(isequal_tests[i].delim2, isequal_tests[i].item2, &moniker2);
2725
        ok(hr == S_OK, "Failed to create moniker, hr %#lx.\n", hr);
2726 2727

        hr = IMoniker_IsEqual(moniker, moniker2);
2728
        ok(hr == isequal_tests[i].hr, "%ld: unexpected result %#lx.\n", i, hr);
2729 2730

        hr = IMoniker_IsEqual(moniker2, moniker);
2731
        ok(hr == isequal_tests[i].hr, "%ld: unexpected result %#lx.\n", i, hr);
2732 2733 2734 2735

        IMoniker_Release(moniker);
        IMoniker_Release(moniker2);
    }
2736 2737 2738

    /* Default instance. */
    hr = CoCreateInstance(&CLSID_ItemMoniker, NULL, CLSCTX_SERVER, &IID_IMoniker, (void **)&moniker);
2739
    ok(hr == S_OK, "Failed to create item moniker, hr %#lx.\n", hr);
2740 2741 2742 2743 2744 2745 2746

    test_moniker("item moniker 6", moniker,
        expected_item_moniker_marshal_data6, sizeof(expected_item_moniker_marshal_data6),
        expected_item_moniker_saved_data6, sizeof(expected_item_moniker_saved_data6),
        expected_item_moniker_comparison_data6, sizeof(expected_item_moniker_comparison_data6),
        34, L"");

2747
    hr = CoCreateInstance(&CLSID_ItemMoniker, (IUnknown *)moniker, CLSCTX_SERVER, &IID_IMoniker, (void **)&moniker2);
2748
    ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
2749

2750
    IMoniker_Release(moniker);
2751 2752 2753

    /* ComposeWith() */
    hr = CreateItemMoniker(L"!", L"Item", &moniker);
2754
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2755 2756 2757 2758

    /* I + A -> () */
    anti = create_antimoniker(1);
    hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
2759
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
2760 2761 2762
    ok(!moniker2, "Unexpected pointer.\n");
    IMoniker_Release(anti);

2763
    /* I + A2 -> A */
2764 2765
    anti = create_antimoniker(2);
    hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
2766
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
2767 2768
    TEST_MONIKER_TYPE(moniker2, MKSYS_ANTIMONIKER);
    hr = IMoniker_Hash(moniker2, &hash);
2769
    ok(hr == S_OK, "Failed to get hash, hr %#lx.\n", hr);
2770 2771
    ok(hash == 0x80000001, "Unexpected hash.\n");
    IMoniker_Release(moniker2);
2772

2773 2774
    IMoniker_Release(anti);

2775 2776 2777 2778
    /* I + (A,A3) -> A3 */

    /* Simplification has to through generic composite logic,
       even when resolved to non-composite, generic composite option has to be enabled. */
2779
    hr = create_moniker_from_desc("CA1A3", &c);
2780
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2781
    hr = IMoniker_ComposeWith(moniker, c, TRUE, &moniker2);
2782
    ok(hr == MK_E_NEEDGENERIC, "Unexpected hr %#lx.\n", hr);
2783
    hr = IMoniker_ComposeWith(moniker, c, FALSE, &moniker2);
2784
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2785 2786
    TEST_MONIKER_TYPE(moniker2, MKSYS_ANTIMONIKER);
    hr = IMoniker_Hash(moniker2, &hash);
2787
    ok(hr == S_OK, "Failed to get hash, hr %#lx.\n", hr);
2788 2789 2790 2791
    ok(hash == 0x80000003, "Unexpected hash.\n");
    IMoniker_Release(moniker2);
    IMoniker_Release(c);

2792
    IMoniker_Release(moniker);
2793 2794 2795

    /* CommonPrefixWith */
    hr = CreateItemMoniker(L"!", L"Item", &moniker);
2796
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2797
    hr = CreateItemMoniker(L"#", L"Item", &moniker2);
2798
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2799 2800

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
2801
    ok(hr == MK_S_US, "Unexpected hr %#lx.\n", hr);
2802 2803 2804 2805 2806 2807
    ok(moniker3 == moniker, "Unexpected object.\n");
    IMoniker_Release(moniker3);

    IMoniker_Release(moniker2);

    hr = CreateItemMoniker(L"!", L"Item2", &moniker2);
2808
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
2809 2810 2811

    moniker3 = (void *)0xdeadbeef;
    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
2812
    todo_wine
2813
{
2814
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
2815 2816 2817 2818 2819 2820
    ok(!moniker3, "Unexpected object.\n");
}

    IMoniker_Release(moniker2);

    IMoniker_Release(moniker);
2821 2822 2823

    /* RelativePathTo() */
    hr = create_moniker_from_desc("I1", &moniker);
2824
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2825
    hr = create_moniker_from_desc("I2", &moniker1);
2826
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2827 2828

    hr = IMoniker_RelativePathTo(moniker, NULL, NULL);
2829
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2830
    hr = IMoniker_RelativePathTo(moniker, NULL, &moniker2);
2831
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2832
    hr = IMoniker_RelativePathTo(moniker, moniker1, NULL);
2833
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2834 2835
    moniker2 = (void *)0xdeadbeef;
    hr = IMoniker_RelativePathTo(moniker, moniker1, &moniker2);
2836
    ok(hr == MK_E_NOTBINDABLE, "Unexpected hr %#lx.\n", hr);
2837 2838 2839 2840
    ok(!moniker2, "Unexpected pointer.\n");

    IMoniker_Release(moniker1);
    IMoniker_Release(moniker);
2841 2842
}

2843 2844 2845 2846 2847 2848 2849
static void stream_write_dword(IStream *stream, DWORD value)
{
    LARGE_INTEGER pos;
    HRESULT hr;

    pos.QuadPart = 0;
    hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2850
    ok(hr == S_OK, "Failed to seek, hr %#lx.\n", hr);
2851 2852

    hr = IStream_Write(stream, &value, sizeof(value), NULL);
2853
    ok(hr == S_OK, "Stream write failed, hr %#lx.\n", hr);
2854 2855

    hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
2856
    ok(hr == S_OK, "Failed to seek, hr %#lx.\n", hr);
2857 2858
}

2859 2860
static void test_anti_moniker(void)
{
2861
    IMoniker *moniker, *moniker2, *moniker3, *inverse, *reduced;
2862 2863
    HRESULT hr;
    DWORD hash;
2864 2865 2866
    IBindCtx *bindctx;
    FILETIME filetime;
    IUnknown *unknown;
2867
    static const WCHAR expected_display_name[] = { '\\','.','.',0 };
2868
    IEnumMoniker *enummoniker;
2869
    IStream *stream;
2870 2871 2872

    hr = CreateAntiMoniker(&moniker);
    ok_ole_success(hr, CreateAntiMoniker);
2873

2874
    check_interface(moniker, &IID_IMoniker, TRUE);
2875
    todo_wine
2876 2877 2878 2879 2880 2881
    check_interface(moniker, &IID_IPersist, FALSE);
    check_interface(moniker, &IID_IPersistStream, TRUE);
    check_interface(moniker, &CLSID_AntiMoniker, TRUE);
    check_interface(moniker, &IID_IROTData, TRUE);
    check_interface(moniker, &IID_IMarshal, TRUE);

2882
    hr = IMoniker_QueryInterface(moniker, &CLSID_AntiMoniker, (void **)&unknown);
2883
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2884 2885
    ok(unknown == (IUnknown *)moniker, "Unexpected interface.\n");
    IUnknown_Release(unknown);
2886 2887 2888 2889

    test_moniker("anti moniker", moniker, 
        expected_anti_moniker_marshal_data, sizeof(expected_anti_moniker_marshal_data),
        expected_anti_moniker_saved_data, sizeof(expected_anti_moniker_saved_data),
2890
        expected_anti_moniker_comparison_data, sizeof(expected_anti_moniker_comparison_data),
2891
        20, expected_display_name);
2892 2893 2894 2895 2896

    /* Hashing */
    hr = IMoniker_Hash(moniker, &hash);
    ok_ole_success(hr, IMoniker_Hash);
    ok(hash == 0x80000001,
2897
        "Hash value != 0x80000001, instead was 0x%08lx\n",
2898 2899 2900
        hash);

    /* IsSystemMoniker test */
2901
    TEST_MONIKER_TYPE(moniker, MKSYS_ANTIMONIKER);
2902 2903

    hr = IMoniker_Inverse(moniker, &inverse);
2904
    ok(hr == MK_E_NOINVERSE, "IMoniker_Inverse should have returned MK_E_NOINVERSE instead of 0x%08lx\n", hr);
2905 2906
    ok(inverse == NULL, "inverse should have been set to NULL instead of %p\n", inverse);

2907 2908 2909 2910 2911
    hr = CreateBindCtx(0, &bindctx);
    ok_ole_success(hr, CreateBindCtx);

    /* IsRunning test */
    hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
2912
    ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08lx\n", hr);
2913 2914

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
2915
    ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08lx\n", hr);
2916 2917

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
2918
    ok(hr == E_NOTIMPL, "IMoniker_BindToObject should return E_NOTIMPL, not 0x%08lx\n", hr);
2919 2920

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
2921
    ok(hr == E_NOTIMPL, "IMoniker_BindToStorage should return E_NOTIMPL, not 0x%08lx\n", hr);
2922

2923 2924
    /* ComposeWith */
    hr = CreateAntiMoniker(&moniker2);
2925
    ok(hr == S_OK, "Failed to create moniker, hr %#lx.\n", hr);
2926 2927 2928

    moniker3 = moniker;
    hr = IMoniker_ComposeWith(moniker, moniker2, TRUE, &moniker3);
2929
    ok(hr == MK_E_NEEDGENERIC, "Unexpected hr %#lx.\n", hr);
2930 2931 2932
    ok(!moniker3, "Unexpected interface.\n");

    hr = IMoniker_ComposeWith(moniker, moniker2, FALSE, &moniker3);
2933
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
2934
    TEST_MONIKER_TYPE(moniker3, MKSYS_GENERICCOMPOSITE);
2935
    IMoniker_Release(moniker3);
2936

2937 2938 2939
    IMoniker_Release(moniker2);

    /* Load with composed number > 1. */
2940
    hr = CreateAntiMoniker(&moniker2);
2941
    ok(hr == S_OK, "Failed to create moniker, hr %#lx.\n", hr);
2942

2943
    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
2944
    ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
2945 2946 2947 2948

    stream_write_dword(stream, 2);

    hr = IMoniker_Load(moniker, stream);
2949
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2950

2951 2952 2953 2954 2955 2956
    test_moniker("anti moniker 2", moniker,
        expected_anti_moniker_marshal_data2, sizeof(expected_anti_moniker_marshal_data2),
        expected_anti_moniker_saved_data2, sizeof(expected_anti_moniker_saved_data2),
        expected_anti_moniker_comparison_data2, sizeof(expected_anti_moniker_comparison_data2),
        20, L"\\..\\..");

2957
    hr = IMoniker_IsEqual(moniker, moniker2);
2958
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
2959 2960

    hr = IMoniker_IsEqual(moniker2, moniker);
2961
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
2962

2963
    hr = IMoniker_Hash(moniker, &hash);
2964 2965
    ok(hr == S_OK, "Failed to get hash value, hr %#lx.\n", hr);
    ok(hash == 0x80000002, "Unexpected hash value %#lx.\n", hash);
2966 2967

    /* Display name reflects anti combination. */
2968
    TEST_DISPLAY_NAME(moniker, L"\\..\\..");
2969 2970 2971 2972 2973

    /* Limit is at 0xfffff. */
    stream_write_dword(stream, 0xfffff);

    hr = IMoniker_Load(moniker, stream);
2974
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2975 2976

    hr = IMoniker_Hash(moniker, &hash);
2977 2978
    ok(hr == S_OK, "Failed to get hash value, hr %#lx.\n", hr);
    ok(hash == 0x800fffff, "Unexpected hash value %#lx.\n", hash);
2979 2980 2981 2982

    stream_write_dword(stream, 0xfffff + 1);

    hr = IMoniker_Load(moniker, stream);
2983
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2984 2985

    hr = IMoniker_Hash(moniker, &hash);
2986 2987
    ok(hr == S_OK, "Failed to get hash value, hr %#lx.\n", hr);
    ok(hash == 0x800fffff, "Unexpected hash value %#lx.\n", hash);
2988 2989 2990 2991 2992

    /* Zero combining counter is also valid. */
    stream_write_dword(stream, 0);

    hr = IMoniker_Load(moniker, stream);
2993
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2994

2995
    hr = IMoniker_IsEqual(moniker, moniker2);
2996
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
2997 2998

    hr = IMoniker_IsEqual(moniker2, moniker);
2999
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
3000

3001
    hr = IMoniker_Hash(moniker, &hash);
3002 3003
    ok(hr == S_OK, "Failed to get hash value, hr %#lx.\n", hr);
    ok(hash == 0x80000000, "Unexpected hash value %#lx.\n", hash);
3004

3005
    TEST_DISPLAY_NAME(moniker, L"");
3006

3007 3008 3009 3010
    /* Back to initial value. */
    stream_write_dword(stream, 1);

    hr = IMoniker_Load(moniker, stream);
3011
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3012 3013

    hr = IMoniker_IsEqual(moniker, moniker2);
3014
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3015 3016

    hr = IMoniker_IsEqual(moniker2, moniker);
3017
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3018 3019

    hr = IMoniker_IsEqual(moniker, NULL);
3020
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3021

3022
    /* Reduce() */
3023
    hr = IMoniker_Reduce(moniker, NULL, MKRREDUCE_ALL, NULL, &reduced);
3024
    ok(hr == MK_S_REDUCED_TO_SELF, "Unexpected hr %#lx.\n", hr);
3025 3026 3027
    ok(reduced == moniker, "Unexpected moniker.\n");
    IMoniker_Release(reduced);

3028 3029 3030
    /* Enum() */
    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker, TRUE, &enummoniker);
3031
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3032 3033 3034 3035
    ok(!enummoniker, "Unexpected pointer.\n");

    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker, FALSE, &enummoniker);
3036
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3037 3038 3039
    ok(!enummoniker, "Unexpected pointer.\n");

    hr = IMoniker_Enum(moniker, FALSE, NULL);
3040 3041 3042
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);

    hr = IMoniker_Enum(moniker, TRUE, NULL);
3043
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3044

3045 3046 3047 3048
    /* CommonPrefixWith() */
    stream_write_dword(stream, 0);

    hr = IMoniker_Load(moniker, stream);
3049
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3050 3051

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
3052
    ok(hr == MK_S_ME, "Unexpected hr %#lx.\n", hr);
3053 3054 3055 3056
    ok(moniker3 == moniker, "Unexpected prefix moniker.\n");
    IMoniker_Release(moniker3);

    hr = IMoniker_CommonPrefixWith(moniker2, moniker, &moniker3);
3057
    ok(hr == MK_S_HIM, "Unexpected hr %#lx.\n", hr);
3058 3059 3060 3061 3062 3063
    ok(moniker3 == moniker, "Unexpected prefix moniker.\n");
    IMoniker_Release(moniker3);

    stream_write_dword(stream, 10);

    hr = IMoniker_Load(moniker, stream);
3064
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3065 3066 3067 3068

    stream_write_dword(stream, 5);

    hr = IMoniker_Load(moniker2, stream);
3069
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3070 3071

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
3072
    ok(hr == MK_S_HIM, "Unexpected hr %#lx.\n", hr);
3073 3074 3075 3076
    ok(moniker3 == moniker2, "Unexpected prefix moniker.\n");
    IMoniker_Release(moniker3);

    hr = IMoniker_CommonPrefixWith(moniker2, moniker, &moniker3);
3077
    ok(hr == MK_S_ME, "Unexpected hr %#lx.\n", hr);
3078 3079 3080 3081 3082 3083
    ok(moniker3 == moniker2, "Unexpected prefix moniker.\n");
    IMoniker_Release(moniker3);

    /* Now same length, 0 or 2 */
    stream_write_dword(stream, 0);
    hr = IMoniker_Load(moniker, stream);
3084
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3085 3086 3087

    stream_write_dword(stream, 0);
    hr = IMoniker_Load(moniker2, stream);
3088
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3089 3090

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
3091
    ok(hr == MK_S_US, "Unexpected hr %#lx.\n", hr);
3092 3093 3094 3095 3096
    ok(moniker3 == moniker, "Unexpected prefix moniker.\n");
    IMoniker_Release(moniker3);

    stream_write_dword(stream, 2);
    hr = IMoniker_Load(moniker, stream);
3097
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3098 3099 3100

    stream_write_dword(stream, 2);
    hr = IMoniker_Load(moniker2, stream);
3101
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3102 3103

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
3104
    ok(hr == MK_S_US, "Unexpected hr %#lx.\n", hr);
3105 3106 3107 3108
    ok(moniker3 == moniker, "Unexpected prefix moniker.\n");
    IMoniker_Release(moniker3);

    IStream_Release(stream);
3109
    IBindCtx_Release(bindctx);
3110
    IMoniker_Release(moniker);
3111
    IMoniker_Release(moniker2);
3112 3113 3114 3115

    /* RelativePathTo() */
    moniker = create_antimoniker(1);
    hr = create_moniker_from_desc("I1", &moniker2);
3116
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3117
    hr = IMoniker_RelativePathTo(moniker, NULL, NULL);
3118
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3119
    hr = IMoniker_RelativePathTo(moniker, NULL, &moniker3);
3120
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3121
    hr = IMoniker_RelativePathTo(moniker, moniker2, NULL);
3122
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3123
    hr = IMoniker_RelativePathTo(moniker, moniker2, &moniker3);
3124
    ok(hr == MK_S_HIM, "Unexpected hr %#lx.\n", hr);
3125 3126 3127 3128 3129 3130
    ok(moniker3 == moniker2, "Unexpected object.\n");
    IMoniker_Release(moniker3);
    IMoniker_Release(moniker2);

    moniker2 = create_antimoniker(2);
    hr = IMoniker_RelativePathTo(moniker, moniker2, &moniker3);
3131
    ok(hr == MK_S_HIM, "Unexpected hr %#lx.\n", hr);
3132 3133 3134
    ok(moniker3 == moniker2, "Unexpected object.\n");
    IMoniker_Release(moniker3);
    hr = IMoniker_RelativePathTo(moniker2, moniker, &moniker3);
3135
    ok(hr == MK_S_HIM, "Unexpected hr %#lx.\n", hr);
3136 3137 3138 3139 3140
    ok(moniker3 == moniker, "Unexpected object.\n");
    IMoniker_Release(moniker3);

    IMoniker_Release(moniker2);
    IMoniker_Release(moniker);
3141 3142
}

3143 3144
static void test_generic_composite_moniker(void)
{
3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163
    static const struct simplify_test
    {
        const char *left;
        const char *right;
        unsigned int result_type;
        const WCHAR *name;
    }
    simplify_tests[] =
    {
        { "I1", "I2", MKSYS_GENERICCOMPOSITE, L"!I1!I2" },
        { "I1", "A2", MKSYS_ANTIMONIKER, L"\\.." },
        { "A1", "A1", MKSYS_GENERICCOMPOSITE, L"\\..\\.." },
        { "A2", "A1", MKSYS_GENERICCOMPOSITE, L"\\..\\..\\.." },
        { "CI1I2", "A1", MKSYS_ITEMMONIKER, L"!I1" },
        { "I1", "A1", MKSYS_NONE },
        { "CI1I2", "A2", MKSYS_NONE },
        { "CI1I2", "A3", MKSYS_ANTIMONIKER, L"\\.." },
        { "CI1I3", "CA1I2", MKSYS_GENERICCOMPOSITE, L"!I1!I2" },
    };
3164
    IMoniker *moniker, *inverse, *moniker1, *moniker2, *moniker3, *moniker4;
3165
    IEnumMoniker *enummoniker, *enummoniker2;
3166
    struct test_moniker *m, *m2;
3167 3168
    IRunningObjectTable *rot;
    DWORD hash, cookie;
3169
    HRESULT hr;
3170 3171 3172
    IBindCtx *bindctx;
    FILETIME filetime;
    IUnknown *unknown;
3173 3174
    IROTData *rotdata;
    IMarshal *marshal;
3175
    BYTE buffer[100];
3176
    IStream *stream;
3177
    unsigned int i;
3178
    FILETIME ft;
3179 3180
    WCHAR *str;
    ULONG len;
3181 3182

    hr = CreateBindCtx(0, &bindctx);
3183
    ok(hr == S_OK, "Failed to create bind context, hr %#lx.\n", hr);
3184

3185 3186 3187
    for (i = 0; i < ARRAY_SIZE(simplify_tests); ++i)
    {
        IMoniker *left, *right, *composite = NULL;
3188
        DWORD moniker_type;
3189
        WCHAR *name;
3190

3191
        winetest_push_context("simplify[%u]", i);
3192

3193
        hr = create_moniker_from_desc(simplify_tests[i].left, &left);
3194
        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3195
        hr = create_moniker_from_desc(simplify_tests[i].right, &right);
3196
        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3197
        hr = CreateGenericComposite(left, right, &composite);
3198
        ok(hr == S_OK, "Failed to create a composite, hr %#lx.\n", hr);
3199

3200 3201 3202
        if (composite)
        {
            hr = IMoniker_IsSystemMoniker(composite, &moniker_type);
3203 3204
            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
            ok(moniker_type == simplify_tests[i].result_type, "Unexpected result type %lu.\n", moniker_type);
3205

3206
            hr = IMoniker_GetDisplayName(composite, bindctx, NULL, &name);
3207
            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3208 3209
            ok(!lstrcmpW(name, simplify_tests[i].name), "Unexpected result name %s.\n", wine_dbgstr_w(name));
            CoTaskMemFree(name);
3210

3211 3212 3213 3214
            IMoniker_Release(composite);
        }
        else
            ok(simplify_tests[i].result_type == MKSYS_NONE, "Unexpected result type.\n");
3215

3216
        winetest_pop_context();
3217

3218 3219 3220
        IMoniker_Release(left);
        IMoniker_Release(right);
    }
3221

3222
    hr = CreateItemMoniker(L"!", L"Test", &moniker1);
3223
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
3224
    hr = CreateItemMoniker(L"#", L"Wine", &moniker2);
3225
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
3226
    hr = CreateGenericComposite(moniker1, moniker2, &moniker);
3227
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
3228

3229
    check_interface(moniker, &IID_IMoniker, TRUE);
3230
    todo_wine
3231 3232 3233 3234 3235
    check_interface(moniker, &IID_IPersist, FALSE);
    check_interface(moniker, &IID_IPersistStream, TRUE);
    check_interface(moniker, &IID_IROTData, TRUE);
    check_interface(moniker, &IID_IMarshal, TRUE);

3236
    hr = CreateGenericComposite(moniker1, moniker2, &moniker);
3237
    ok(hr == S_OK, "Failed to create composite, hr %#lx.\n", hr);
3238
    TEST_MONIKER_TYPE(moniker, MKSYS_GENERICCOMPOSITE);
3239

3240 3241
    /* Generic composite is special, as it does not addref in this case. */
    hr = IMoniker_QueryInterface(moniker, &CLSID_CompositeMoniker, (void **)&unknown);
3242
    todo_wine
3243
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3244 3245 3246
    if (SUCCEEDED(hr))
        ok(unknown == (IUnknown *)moniker, "Unexpected interface.\n");

3247
    test_moniker("generic composite moniker", moniker, 
3248
        expected_gc_moniker_marshal_data, sizeof(expected_gc_moniker_marshal_data),
3249
        expected_gc_moniker_saved_data, sizeof(expected_gc_moniker_saved_data),
3250
        expected_gc_moniker_comparison_data, sizeof(expected_gc_moniker_comparison_data),
3251
        160, L"!Test#Wine");
3252 3253 3254 3255 3256 3257 3258

    /* Hashing */

    hr = IMoniker_Hash(moniker, &hash);
    ok_ole_success(hr, IMoniker_Hash);

    ok(hash == 0xd87,
3259
        "Hash value != 0xd87, instead was 0x%08lx\n",
3260 3261 3262
        hash);

    /* IsSystemMoniker test */
3263
    TEST_MONIKER_TYPE(moniker, MKSYS_GENERICCOMPOSITE);
3264

3265 3266 3267 3268
    hr = CreateBindCtx(0, &bindctx);
    ok_ole_success(hr, CreateBindCtx);

    /* IsRunning test */
3269
    hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
3270
    ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08lx\n", hr);
3271

3272
    hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
3273
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
3274

3275
    hr = IMoniker_IsRunning(moniker, bindctx, NULL, moniker);
3276
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3277 3278

    hr = IMoniker_IsRunning(moniker, bindctx, moniker1, moniker);
3279
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
3280 3281

    hr = IMoniker_IsRunning(moniker, NULL, moniker1, moniker);
3282
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3283

3284
    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
3285
    ok(hr == MK_E_NOTBINDABLE, "IMoniker_GetTimeOfLastChange should return MK_E_NOTBINDABLE, not 0x%08lx\n", hr);
3286 3287

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
3288
    ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08lx\n", hr);
3289 3290

    hr = IMoniker_Inverse(moniker, &inverse);
3291
    ok(hr == S_OK, "Failed to get inverse, hr %#lx.\n", hr);
3292
    TEST_MONIKER_TYPE(inverse, MKSYS_GENERICCOMPOSITE);
3293 3294
    IMoniker_Release(inverse);

3295 3296
    /* BindToObject() */
    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
3297
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3298 3299

    hr = IBindCtx_GetRunningObjectTable(bindctx, &rot);
3300
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3301 3302 3303

    hr = IRunningObjectTable_Register(rot, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)moniker,
            moniker, &cookie);
3304
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3305 3306

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
3307
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3308 3309 3310
    IUnknown_Release(unknown);

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IMoniker, (void **)&unknown);
3311
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3312 3313 3314
    IUnknown_Release(unknown);

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IDispatch, (void **)&unknown);
3315
    ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
3316 3317

    hr = IRunningObjectTable_Revoke(rot, cookie);
3318
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3319

3320 3321 3322 3323
    IMoniker_Release(moniker);

    /* BindToObject() with moniker at left */
    hr = CreatePointerMoniker((IUnknown *)rot, &moniker);
3324
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3325 3326 3327

    /* (I1,P) */
    hr = create_moniker_from_desc("I1", &moniker2);
3328
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3329 3330

    hr = CreateGenericComposite(moniker2, moniker, &moniker3);
3331
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3332 3333

    hr = IMoniker_BindToObject(moniker3, bindctx, moniker2, &IID_IMoniker, (void **)&unknown);
3334
    ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
3335 3336 3337

    /* Register (I1,I1,P), check if ROT is used for left != NULL case  */
    hr = CreateGenericComposite(moniker2, moniker3, &moniker4);
3338
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3339

3340 3341 3342
    cookie = 0;
    hr = IRunningObjectTable_Register(rot, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)moniker4,
            moniker4, &cookie);
3343
    todo_wine
3344
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3345 3346

    hr = IMoniker_BindToObject(moniker3, bindctx, moniker2, &IID_IMoniker, (void **)&unknown);
3347
    ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
3348 3349

    hr = IRunningObjectTable_Revoke(rot, cookie);
3350
    todo_wine
3351
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3352 3353 3354

    IMoniker_Release(moniker3);
    IMoniker_Release(moniker2);
3355
    IMoniker_Release(moniker);
3356

3357 3358
    IRunningObjectTable_Release(rot);

3359 3360
    /* Uninitialized composite */
    hr = CoCreateInstance(&CLSID_CompositeMoniker, NULL, CLSCTX_SERVER, &IID_IMoniker, (void **)&moniker);
3361
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3362 3363

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3364
    ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
3365 3366
    /* Exact error is E_OUTOFMEMORY */
    hr = IMoniker_Save(moniker, stream, TRUE);
3367
    ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
3368 3369 3370 3371
    IStream_Release(stream);

    hash = 0xdeadbeef;
    hr = IMoniker_Hash(moniker, &hash);
3372 3373
    ok(hr == E_UNEXPECTED, "Unexpected hr %#lx.\n", hr);
    ok(hash == 0xdeadbeef, "Unexpected hash %#lx.\n", hash);
3374 3375

    hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &str);
3376
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3377 3378

    hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
3379
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3380
    hr = IROTData_GetComparisonData(rotdata, NULL, 0, &len);
3381
    ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
3382 3383 3384
    IROTData_Release(rotdata);

    hr = IMoniker_QueryInterface(moniker, &IID_IMarshal, (void **)&marshal);
3385
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3386
    hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IMoniker, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL, &len);
3387
    ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
3388
    hr = IMarshal_MarshalInterface(marshal, stream, &IID_IMoniker, NULL, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3389
    ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
3390 3391 3392 3393
    IMarshal_Release(marshal);

    IMoniker_Release(moniker);

3394
    /* GetTimeOfLastChange() */
3395
    hr = create_moniker_from_desc("CI1I2", &moniker);
3396
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3397

3398
    hr = create_moniker_from_desc("I1", &moniker1);
3399
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3400 3401 3402

    /* See if non-generic composition is possible */
    hr = IMoniker_ComposeWith(moniker1, moniker, TRUE, &moniker2);
3403
    ok(hr == MK_E_NEEDGENERIC, "Unexpected hr %#lx.\n", hr);
3404 3405

    hr = IBindCtx_GetRunningObjectTable(bindctx, &rot);
3406
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3407 3408

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, moniker1, &ft);
3409
    ok(hr == MK_E_NOTBINDABLE, "Unexpected hr %#lx.\n", hr);
3410 3411

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &ft);
3412
    ok(hr == MK_E_NOTBINDABLE, "Unexpected hr %#lx.\n", hr);
3413 3414

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, NULL);
3415
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3416 3417

    hr = IMoniker_GetTimeOfLastChange(moniker, NULL, NULL, &ft);
3418
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3419 3420 3421

    hr = IRunningObjectTable_Register(rot, ROTFLAGS_REGISTRATIONKEEPSALIVE, (IUnknown *)moniker,
            moniker, &cookie);
3422
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3423 3424

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &ft);
3425
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3426 3427

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, moniker1, &ft);
3428
    ok(hr == MK_E_NOTBINDABLE, "Unexpected hr %#lx.\n", hr);
3429 3430

    hr = IRunningObjectTable_Revoke(rot, cookie);
3431
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3432 3433 3434 3435 3436 3437

    IRunningObjectTable_Release(rot);

    IMoniker_Release(moniker);
    IMoniker_Release(moniker1);

3438 3439
    /* CommonPrefixWith() */
    hr = create_moniker_from_desc("CI1I2", &moniker);
3440
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3441
    hr = create_moniker_from_desc("CI1I2", &moniker1);
3442
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3443

3444
    hr = IMoniker_CommonPrefixWith(moniker, NULL, NULL);
3445
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3446 3447

    hr = IMoniker_CommonPrefixWith(moniker, moniker1, NULL);
3448
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3449

3450 3451
    moniker2 = (void *)0xdeadbeef;
    hr = IMoniker_CommonPrefixWith(moniker, NULL, &moniker2);
3452
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3453 3454 3455 3456
    ok(!moniker2, "Unexpected pointer.\n");

    /* With itself */
    hr = IMoniker_CommonPrefixWith(moniker, moniker, &moniker2);
3457
    ok(hr == MK_S_US, "Unexpected hr %#lx.\n", hr);
3458
    hr = IMoniker_IsEqual(moniker, moniker2);
3459
    ok(hr == S_OK && moniker2 != moniker, "Unexpected hr %#lx.\n", hr);
3460 3461 3462 3463
    IMoniker_Release(moniker2);

    /* Equal composites */
    hr = IMoniker_CommonPrefixWith(moniker, moniker1, &moniker2);
3464
    ok(hr == MK_S_US, "Unexpected hr %#lx.\n", hr);
3465 3466
    ok(moniker2 != moniker && moniker2 != moniker1, "Unexpected object.\n");
    hr = IMoniker_IsEqual(moniker, moniker2);
3467
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3468 3469 3470
    IMoniker_Release(moniker2);

    hr = create_moniker_from_desc("I2", &moniker2);
3471
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3472
    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
3473
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
3474 3475 3476
    IMoniker_Release(moniker2);

    hr = create_moniker_from_desc("I1", &moniker2);
3477
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3478
    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &moniker3);
3479
    ok(hr == MK_S_HIM, "Unexpected hr %#lx.\n", hr);
3480 3481 3482 3483 3484
    hr = IMoniker_IsEqual(moniker2, moniker3);
    ok(hr == S_OK && moniker3 != moniker2, "Unexpected object.\n");
    IMoniker_Release(moniker3);

    hr = IMoniker_CommonPrefixWith(moniker2, moniker, &moniker3);
3485
    todo_wine
3486
    ok(hr == MK_S_ME, "Unexpected hr %#lx.\n", hr);
3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498
    if (SUCCEEDED(hr))
    {
        hr = IMoniker_IsEqual(moniker2, moniker3);
        ok(hr == S_OK && moniker3 != moniker2, "Unexpected object.\n");
        IMoniker_Release(moniker3);
    }

    IMoniker_Release(moniker2);

    IMoniker_Release(moniker);
    IMoniker_Release(moniker1);

3499 3500
    /* IsEqual() */
    hr = create_moniker_from_desc("CI1I2", &moniker1);
3501
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3502
    hr = create_moniker_from_desc("CI1I2", &moniker2);
3503
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3504
    hr = IMoniker_IsEqual(moniker1, NULL);
3505
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3506
    hr = IMoniker_IsEqual(moniker1, moniker2);
3507
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3508
    hr = IMoniker_IsEqual(moniker1, moniker1);
3509
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3510 3511 3512
    IMoniker_Release(moniker2);
    IMoniker_Release(moniker1);

3513 3514
    /* ComposeWith() */
    hr = create_moniker_from_desc("CI1I2", &moniker1);
3515
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3516
    hr = create_moniker_from_desc("I3", &moniker2);
3517
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3518 3519

    hr = IMoniker_ComposeWith(moniker1, NULL, FALSE, &moniker);
3520
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3521 3522 3523 3524
    ok(moniker == moniker1, "Unexpected pointer.\n");
    IMoniker_Release(moniker);

    hr = IMoniker_ComposeWith(moniker1, NULL, TRUE, &moniker);
3525
    ok(hr == MK_E_NEEDGENERIC, "Unexpected hr %#lx.\n", hr);
3526 3527 3528 3529 3530
    ok(!moniker, "Unexpected pointer.\n");

    IMoniker_Release(moniker2);
    IMoniker_Release(moniker1);

3531 3532
    /* Inverse() */
    hr = create_moniker_from_desc("CI1I2", &moniker1);
3533
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3534
    hr = IMoniker_Inverse(moniker1, NULL);
3535
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3536
    hr = IMoniker_Inverse(moniker1, &inverse);
3537
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3538 3539 3540 3541 3542 3543
    TEST_MONIKER_TYPE(inverse, MKSYS_GENERICCOMPOSITE);
    TEST_DISPLAY_NAME(inverse, L"\\..\\..");
    IMoniker_Release(inverse);
    IMoniker_Release(moniker1);

    hr = create_moniker_from_desc("CA1A2", &moniker1);
3544
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3545 3546
    inverse = (void *)0xdeadbeef;
    hr = IMoniker_Inverse(moniker1, &inverse);
3547
    ok(hr == MK_E_NOINVERSE, "Unexpected hr %#lx.\n", hr);
3548 3549 3550 3551
    ok(!inverse, "Unexpected pointer.\n");
    IMoniker_Release(moniker1);

    hr = create_moniker_from_desc("CI1A2", &moniker1);
3552
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3553 3554
    inverse = (void *)0xdeadbeef;
    hr = IMoniker_Inverse(moniker1, &inverse);
3555
    ok(hr == MK_E_NOINVERSE, "Unexpected hr %#lx.\n", hr);
3556 3557 3558 3559 3560 3561 3562
    ok(!inverse, "Unexpected pointer.\n");
    IMoniker_Release(moniker1);

    /* Now with custom moniker to observe inverse order */
    m = create_test_moniker();
    m->inverse = "I5";
    hr = create_moniker_from_desc("I1", &moniker1);
3563
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3564
    hr = CreateGenericComposite(moniker1, &m->IMoniker_iface, &moniker2);
3565
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3566 3567 3568
    TEST_MONIKER_TYPE(moniker2, MKSYS_GENERICCOMPOSITE);
    inverse = (void *)0xdeadbeef;
    hr = IMoniker_Inverse(moniker2, &inverse);
3569
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3570 3571 3572 3573 3574 3575 3576 3577
    ok(!inverse, "Unexpected pointer.\n");
    IMoniker_Release(moniker1);

    /* Use custom monikers for both, so they don't invert to anti monikers. */
    m2 = create_test_moniker();
    m2->inverse = "I4";

    hr = CreateGenericComposite(&m2->IMoniker_iface, &m->IMoniker_iface, &moniker2);
3578
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3579
    hr = IMoniker_Inverse(moniker2, &inverse);
3580
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3581 3582 3583 3584 3585 3586 3587 3588
    TEST_MONIKER_TYPE(inverse, MKSYS_GENERICCOMPOSITE);
    TEST_DISPLAY_NAME(inverse, L"!I5!I4");
    IMoniker_Release(inverse);
    IMoniker_Release(moniker2);

    IMoniker_Release(&m->IMoniker_iface);
    IMoniker_Release(&m2->IMoniker_iface);

3589 3590 3591 3592
    /* Display name */

    /* One component does not support it. */
    hr = create_moniker_from_desc("CPI1", &moniker);
3593
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3594 3595

    hr = IMoniker_GetDisplayName(moniker, NULL, NULL, &str);
3596
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3597 3598

    hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, NULL);
3599
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3600 3601

    hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &str);
3602
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
3603

3604 3605
    /* Comparison data, pointer component does not support it. */
    hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
3606
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3607 3608 3609
    len = 0;
    hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &len);
todo_wine {
3610 3611
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
    ok(!len, "Unexpected length %lu.\n", len);
3612 3613 3614
}
    IROTData_Release(rotdata);

3615 3616
    IMoniker_Release(moniker);

3617 3618
    /* Reduce() */
    hr = create_moniker_from_desc("CI1I2", &moniker);
3619
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3620 3621

    hr = IMoniker_Reduce(moniker, NULL, MKRREDUCE_ALL, NULL, NULL);
3622
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3623
    hr = IMoniker_Reduce(moniker, bindctx, MKRREDUCE_ALL, NULL, NULL);
3624
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3625
    hr = IMoniker_Reduce(moniker, NULL, MKRREDUCE_ALL, NULL, &moniker2);
3626
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3627 3628

    hr = IMoniker_Reduce(moniker, bindctx, MKRREDUCE_ALL, NULL, &moniker2);
3629
    ok(hr == MK_S_REDUCED_TO_SELF, "Unexpected hr %#lx.\n", hr);
3630 3631 3632 3633 3634
    ok(moniker2 == moniker, "Unexpected object.\n");
    IMoniker_Release(moniker2);

    IMoniker_Release(moniker);

3635 3636
    /* Enum() */
    hr = create_moniker_from_desc("CI1CI2I3", &moniker);
3637
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3638 3639

    hr = IMoniker_Enum(moniker, FALSE, NULL);
3640
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3641 3642 3643

    /* Forward direction */
    hr = IMoniker_Enum(moniker, TRUE, &enummoniker);
3644
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3645 3646

    hr = IEnumMoniker_Next(enummoniker, 0, NULL, NULL);
3647
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3648 3649 3650

    moniker2 = (void *)0xdeadbeef;
    hr = IEnumMoniker_Next(enummoniker, 0, &moniker2, NULL);
3651
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3652 3653 3654 3655 3656
    ok(!moniker2, "Unexpected pointer.\n");

    len = 1;
    moniker2 = (void *)0xdeadbeef;
    hr = IEnumMoniker_Next(enummoniker, 0, &moniker2, &len);
3657 3658
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(!len, "Unexpected count %lu.\n", len);
3659 3660 3661
    ok(!moniker2, "Unexpected pointer.\n");

    hr = IEnumMoniker_Skip(enummoniker, 0);
3662
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3663 3664 3665

    len = 0;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3666 3667
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(len == 1, "Unexpected count %lu.\n", len);
3668 3669 3670 3671 3672
    TEST_DISPLAY_NAME(moniker2, L"!I1");
    IMoniker_Release(moniker2);

    len = 0;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3673 3674
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(len == 1, "Unexpected count %lu.\n", len);
3675 3676 3677 3678 3679
    TEST_DISPLAY_NAME(moniker2, L"!I2");
    IMoniker_Release(moniker2);

    len = 0;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3680 3681
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(len == 1, "Unexpected count %lu.\n", len);
3682 3683 3684 3685 3686
    TEST_DISPLAY_NAME(moniker2, L"!I3");
    IMoniker_Release(moniker2);

    len = 1;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3687 3688
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
    ok(!len, "Unexpected count %lu.\n", len);
3689 3690

    hr = IEnumMoniker_Skip(enummoniker, 0);
3691
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3692 3693

    hr = IEnumMoniker_Skip(enummoniker, 1);
3694
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
3695 3696

    hr = IEnumMoniker_Clone(enummoniker, NULL);
3697
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3698 3699 3700

    enummoniker2 = (void *)0xdeadbeef;
    hr = IEnumMoniker_Clone(enummoniker, &enummoniker2);
3701
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
3702
    ok(!enummoniker2, "Unexpected pointer.\n");
3703

3704
    hr = IEnumMoniker_Reset(enummoniker);
3705
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3706 3707

    hr = IEnumMoniker_Skip(enummoniker, 2);
3708
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3709 3710 3711

    len = 0;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3712 3713
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(len == 1, "Unexpected count %lu.\n", len);
3714 3715 3716 3717 3718
    TEST_DISPLAY_NAME(moniker2, L"!I3");
    IMoniker_Release(moniker2);

    enummoniker2 = (void *)0xdeadbeef;
    hr = IEnumMoniker_Clone(enummoniker, &enummoniker2);
3719
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
3720
    ok(!enummoniker2, "Unexpected pointer.\n");
3721

3722 3723 3724 3725
    IEnumMoniker_Release(enummoniker);

    /* Backward direction */
    hr = IMoniker_Enum(moniker, FALSE, &enummoniker);
3726
    ok(hr == S_OK, "Failed to get enumerator, hr %#lx.\n", hr);
3727 3728

    hr = IEnumMoniker_Next(enummoniker, 0, NULL, NULL);
3729
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3730 3731 3732

    moniker2 = (void *)0xdeadbeef;
    hr = IEnumMoniker_Next(enummoniker, 0, &moniker2, NULL);
3733
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3734 3735 3736 3737 3738
    ok(!moniker2, "Unexpected pointer.\n");

    len = 1;
    moniker2 = (void *)0xdeadbeef;
    hr = IEnumMoniker_Next(enummoniker, 0, &moniker2, &len);
3739 3740
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(!len, "Unexpected count %lu.\n", len);
3741 3742 3743
    ok(!moniker2, "Unexpected pointer.\n");

    hr = IEnumMoniker_Skip(enummoniker, 0);
3744
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3745 3746 3747

    len = 0;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3748 3749
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(len == 1, "Unexpected count %lu.\n", len);
3750 3751 3752 3753 3754
    TEST_DISPLAY_NAME(moniker2, L"!I3");
    IMoniker_Release(moniker2);

    len = 0;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3755 3756
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(len == 1, "Unexpected count %lu.\n", len);
3757 3758 3759 3760 3761
    TEST_DISPLAY_NAME(moniker2, L"!I2");
    IMoniker_Release(moniker2);

    len = 0;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3762 3763
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(len == 1, "Unexpected count %lu.\n", len);
3764 3765 3766 3767 3768
    TEST_DISPLAY_NAME(moniker2, L"!I1");
    IMoniker_Release(moniker2);

    len = 1;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3769 3770
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
    ok(!len, "Unexpected count %lu.\n", len);
3771 3772

    hr = IEnumMoniker_Skip(enummoniker, 0);
3773
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3774 3775

    hr = IEnumMoniker_Skip(enummoniker, 1);
3776
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
3777 3778

    hr = IEnumMoniker_Clone(enummoniker, NULL);
3779
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3780 3781 3782

    enummoniker2 = (void *)0xdeadbeef;
    hr = IEnumMoniker_Clone(enummoniker, &enummoniker2);
3783
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
3784
    ok(!enummoniker2, "Unexpected pointer.\n");
3785

3786
    hr = IEnumMoniker_Reset(enummoniker);
3787
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3788 3789

    hr = IEnumMoniker_Skip(enummoniker, 2);
3790
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3791 3792 3793

    len = 0;
    hr = IEnumMoniker_Next(enummoniker, 1, &moniker2, &len);
3794 3795
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
    ok(len == 1, "Unexpected count %lu.\n", len);
3796 3797 3798 3799 3800
    TEST_DISPLAY_NAME(moniker2, L"!I1");
    IMoniker_Release(moniker2);

    enummoniker2 = (void *)0xdeadbeef;
    hr = IEnumMoniker_Clone(enummoniker, &enummoniker2);
3801
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
3802
    ok(!enummoniker2, "Unexpected pointer.\n");
3803

3804 3805 3806 3807
    IEnumMoniker_Release(enummoniker);

    IMoniker_Release(moniker);

3808 3809
    /* RelativePathTo() */
    hr = create_moniker_from_desc("CI1I2", &moniker1);
3810
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3811 3812

    hr = create_moniker_from_desc("CI2I3", &moniker2);
3813
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3814 3815

    hr = IMoniker_RelativePathTo(moniker1, NULL, NULL);
3816
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3817
    hr = IMoniker_RelativePathTo(moniker1, moniker2, &moniker3);
3818
    ok(hr == MK_E_NOTBINDABLE, "Unexpected hr %#lx.\n", hr);
3819

3820
    IBindCtx_Release(bindctx);
3821 3822
}

3823 3824
static void test_pointer_moniker(void)
{
3825
    IMoniker *moniker, *moniker2, *moniker3, *prefix, *inverse, *anti, *c;
3826
    struct test_factory factory;
3827
    IEnumMoniker *enummoniker;
3828
    DWORD hash, size;
3829 3830 3831 3832 3833 3834
    HRESULT hr;
    IBindCtx *bindctx;
    FILETIME filetime;
    IUnknown *unknown;
    IStream *stream;
    LPOLESTR display_name;
3835 3836 3837
    IMarshal *marshal;
    LARGE_INTEGER pos;
    CLSID clsid;
3838

3839
    test_factory_init(&factory);
3840

3841
    hr = CreatePointerMoniker((IUnknown *)&factory.IClassFactory_iface, NULL);
3842
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3843

3844
    hr = CreatePointerMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker);
3845
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3846

3847
    check_interface(moniker, &IID_IMoniker, TRUE);
3848
    todo_wine
3849 3850 3851 3852 3853 3854
    check_interface(moniker, &IID_IPersist, FALSE);
    check_interface(moniker, &IID_IPersistStream, TRUE);
    check_interface(moniker, &CLSID_PointerMoniker, TRUE);
    check_interface(moniker, &IID_IMarshal, TRUE);
    check_interface(moniker, &IID_IROTData, FALSE);

3855
    hr = IMoniker_QueryInterface(moniker, &IID_IMoniker, NULL);
3856
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3857

3858
    hr = IMoniker_QueryInterface(moniker, &CLSID_PointerMoniker, (void **)&unknown);
3859 3860
    ok(unknown == (IUnknown *)moniker, "Unexpected interface.\n");
    IUnknown_Release(unknown);
3861

3862
    hr = IMoniker_QueryInterface(moniker, &IID_IMarshal, (void **)&marshal);
3863
    ok(hr == S_OK, "Failed to get interface, hr %#lx.\n", hr);
3864 3865

    hr = IMarshal_GetUnmarshalClass(marshal, NULL, NULL, 0, NULL, 0, &clsid);
3866
    ok(hr == S_OK, "Failed to get class, hr %#lx.\n", hr);
3867
    ok(IsEqualGUID(&clsid, &CLSID_PointerMoniker), "Unexpected class %s.\n", wine_dbgstr_guid(&clsid));
3868 3869

    hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IMoniker, NULL, CLSCTX_INPROC, NULL, 0, &size);
3870 3871
    ok(hr == S_OK, "Failed to get marshal size, hr %#lx.\n", hr);
    ok(size > 0, "Unexpected size %ld.\n", size);
3872 3873

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3874
    ok(hr == S_OK, "Failed to create a stream, hr %#lx.\n", hr);
3875 3876

    hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
3877
    ok(hr == S_OK, "Failed to marshal moniker, hr %#lx.\n", hr);
3878 3879 3880 3881

    pos.QuadPart = 0;
    IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
    hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker2);
3882
    ok(hr == S_OK, "Failed to unmarshal, hr %#lx.\n", hr);
3883
    hr = IMoniker_IsEqual(moniker, moniker2);
3884
    ok(hr == S_OK, "Expected equal moniker, hr %#lx.\n", hr);
3885 3886 3887 3888 3889 3890
    IMoniker_Release(moniker2);

    IStream_Release(stream);

    IMarshal_Release(marshal);

3891
    ok(factory.refcount > 1, "Unexpected factory refcount %lu.\n", factory.refcount);
3892 3893 3894 3895 3896 3897 3898

    /* Display Name */

    hr = CreateBindCtx(0, &bindctx);
    ok_ole_success(hr, CreateBindCtx);

    hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
3899
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
3900

3901
    hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, NULL);
3902
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3903 3904

    display_name = (void *)0xdeadbeef;
3905
    hr = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name);
3906
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3907
    ok(!display_name, "Unexpected pointer.\n");
3908 3909 3910 3911

    IBindCtx_Release(bindctx);

    hr = IMoniker_IsDirty(moniker);
3912
    ok(hr == S_FALSE, "IMoniker_IsDirty should return S_FALSE, not 0x%08lx\n", hr);
3913 3914 3915 3916 3917 3918 3919

    /* Saving */

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
    ok_ole_success(hr, CreateStreamOnHGlobal);

    hr = IMoniker_Save(moniker, stream, TRUE);
3920
    ok(hr == E_NOTIMPL, "IMoniker_Save should have returned E_NOTIMPL instead of 0x%08lx\n", hr);
3921 3922 3923 3924 3925 3926

    IStream_Release(stream);

    /* Hashing */
    hr = IMoniker_Hash(moniker, &hash);
    ok_ole_success(hr, IMoniker_Hash);
3927
    ok(hash == PtrToUlong(&factory.IClassFactory_iface), "Unexpected hash value %#lx.\n", hash);
3928 3929

    /* IsSystemMoniker test */
3930
    TEST_MONIKER_TYPE(moniker, MKSYS_POINTERMONIKER);
3931 3932

    hr = IMoniker_Inverse(moniker, &inverse);
3933
    ok(hr == S_OK, "Failed to get inverse, hr %#lx.\n", hr);
3934
    TEST_MONIKER_TYPE(inverse, MKSYS_ANTIMONIKER);
3935 3936 3937 3938 3939 3940 3941
    IMoniker_Release(inverse);

    hr = CreateBindCtx(0, &bindctx);
    ok_ole_success(hr, CreateBindCtx);

    /* IsRunning test */
    hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
3942
    ok(hr == S_OK, "IMoniker_IsRunning should return S_OK, not 0x%08lx\n", hr);
3943 3944

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
3945
    ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08lx\n", hr);
3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
    ok_ole_success(hr, IMoniker_BindToObject);
    IUnknown_Release(unknown);

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
    ok_ole_success(hr, IMoniker_BindToStorage);
    IUnknown_Release(unknown);

    IMoniker_Release(moniker);

3957
    ok(factory.refcount == 1, "Unexpected factory refcount %lu.\n", factory.refcount);
3958 3959 3960 3961 3962

    hr = CreatePointerMoniker(NULL, &moniker);
    ok_ole_success(hr, CreatePointerMoniker);

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
3963
    ok(hr == E_UNEXPECTED, "IMoniker_BindToObject should have returned E_UNEXPECTED instead of 0x%08lx\n", hr);
3964 3965

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
3966
    ok(hr == E_UNEXPECTED, "IMoniker_BindToStorage should have returned E_UNEXPECTED instead of 0x%08lx\n", hr);
3967 3968 3969

    IBindCtx_Release(bindctx);

3970 3971
    /* Enum() */
    hr = IMoniker_Enum(moniker, TRUE, &enummoniker);
3972
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
3973 3974

    hr = IMoniker_Enum(moniker, FALSE, &enummoniker);
3975
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
3976

3977
    IMoniker_Release(moniker);
3978 3979

    /* CommonPrefixWith() */
3980
    hr = CreatePointerMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker);
3981
    ok(hr == S_OK, "Failed to create moniker, hr %#lx.\n", hr);
3982

3983
    hr = CreatePointerMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker2);
3984
    ok(hr == S_OK, "Failed to create moniker, hr %#lx.\n", hr);
3985 3986

    hr = IMoniker_IsEqual(moniker, NULL);
3987
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3988 3989

    hr = IMoniker_IsEqual(moniker, moniker2);
3990
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
3991 3992

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, NULL);
3993
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3994 3995

    hr = IMoniker_CommonPrefixWith(moniker, NULL, &prefix);
3996
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
3997 3998

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &prefix);
3999
    ok(hr == MK_S_US, "Unexpected hr %#lx.\n", hr);
4000 4001 4002 4003 4004 4005
    ok(prefix == moniker, "Unexpected pointer.\n");
    IMoniker_Release(prefix);

    IMoniker_Release(moniker2);

    hr = CreatePointerMoniker((IUnknown *)moniker, &moniker2);
4006
    ok(hr == S_OK, "Failed to create moniker, hr %#lx.\n", hr);
4007 4008

    hr = IMoniker_IsEqual(moniker, moniker2);
4009
    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
4010 4011

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &prefix);
4012
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4013 4014 4015

    IMoniker_Release(moniker2);

4016 4017 4018 4019 4020
    /* ComposeWith() */

    /* P + A -> () */
    anti = create_antimoniker(1);
    hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
4021
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
4022 4023 4024 4025 4026 4027
    ok(!moniker2, "Unexpected pointer.\n");
    IMoniker_Release(anti);

    /* P + A2 -> A */
    anti = create_antimoniker(2);
    hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
4028
    ok(hr == S_OK, "Failed to compose, hr %#lx.\n", hr);
4029 4030
    TEST_MONIKER_TYPE(moniker2, MKSYS_ANTIMONIKER);
    IMoniker_Release(moniker2);
4031

4032 4033
    IMoniker_Release(anti);

4034 4035 4036 4037
    /* Simplification has to through generic composite logic,
       even when resolved to non-composite, generic composite option has to be enabled. */

    /* P + (A,A3) -> A3 */
4038
    hr = create_moniker_from_desc("CA1A3", &c);
4039
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4040
    hr = IMoniker_ComposeWith(moniker, c, TRUE, &moniker2);
4041
    ok(hr == MK_E_NEEDGENERIC, "Unexpected hr %#lx.\n", hr);
4042
    hr = IMoniker_ComposeWith(moniker, c, FALSE, &moniker2);
4043
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4044 4045
    TEST_MONIKER_TYPE(moniker2, MKSYS_ANTIMONIKER);
    hr = IMoniker_Hash(moniker2, &hash);
4046
    ok(hr == S_OK, "Failed to get hash, hr %#lx.\n", hr);
4047 4048 4049 4050 4051
    ok(hash == 0x80000003, "Unexpected hash.\n");
    IMoniker_Release(moniker2);
    IMoniker_Release(c);

    /* P + (A,I) -> I */
4052
    hr = create_moniker_from_desc("CA1I1", &c);
4053
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4054
    hr = IMoniker_ComposeWith(moniker, c, TRUE, &moniker2);
4055
    ok(hr == MK_E_NEEDGENERIC, "Unexpected hr %#lx.\n", hr);
4056
    hr = IMoniker_ComposeWith(moniker, c, FALSE, &moniker2);
4057
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4058 4059 4060 4061
    TEST_MONIKER_TYPE(moniker2, MKSYS_ITEMMONIKER);
    IMoniker_Release(moniker2);
    IMoniker_Release(c);

4062 4063
    /* RelativePathTo() */
    hr = create_moniker_from_desc("I1", &moniker3);
4064
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4065
    hr = IMoniker_RelativePathTo(moniker, NULL, NULL);
4066
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
4067 4068
    moniker2 = (void *)0xdeadbeef;
    hr = IMoniker_RelativePathTo(moniker, NULL, &moniker2);
4069
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
4070 4071
    ok(!moniker2, "Unexpected pointer.\n");
    hr = IMoniker_RelativePathTo(moniker, moniker3, NULL);
4072
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
4073 4074
    moniker2 = (void *)0xdeadbeef;
    hr = IMoniker_RelativePathTo(moniker, moniker3, &moniker2);
4075
    ok(hr == E_NOTIMPL, "Unexpected hr %#lx.\n", hr);
4076 4077 4078
    ok(!moniker2, "Unexpected pointer.\n");
    IMoniker_Release(moniker3);

4079
    IMoniker_Release(moniker);
4080 4081
}

4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101
static void test_objref_moniker(void)
{
    IMoniker *moniker, *moniker2, *prefix, *inverse, *anti;
    struct test_factory factory;
    IEnumMoniker *enummoniker;
    DWORD hash, size;
    HRESULT hr;
    IBindCtx *bindctx;
    FILETIME filetime;
    IUnknown *unknown;
    IStream *stream;
    IROTData *rotdata;
    LPOLESTR display_name;
    IMarshal *marshal;
    LARGE_INTEGER pos;
    CLSID clsid;

    test_factory_init(&factory);

    hr = CreateObjrefMoniker((IUnknown *)&factory.IClassFactory_iface, NULL);
4102
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx\n", hr);
4103 4104

    hr = CreateObjrefMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker);
4105
    ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
4106 4107

    hr = IMoniker_QueryInterface(moniker, &IID_IMoniker, NULL);
4108
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx\n", hr);
4109 4110 4111 4112 4113 4114 4115 4116 4117 4118

    hr = IMoniker_QueryInterface(moniker, &CLSID_PointerMoniker, (void **)&unknown);
    ok(unknown == (IUnknown *)moniker, "Unexpected interface\n");
    IUnknown_Release(unknown);

    hr = IMoniker_QueryInterface(moniker, &CLSID_ObjrefMoniker, (void **)&unknown);
    ok(unknown == (IUnknown *)moniker, "Unexpected interface\n");
    IUnknown_Release(unknown);

    hr = IMoniker_QueryInterface(moniker, &IID_IMarshal, (void **)&marshal);
4119
    ok(hr == S_OK, "Failed to get interface, hr %#lx\n", hr);
4120 4121

    hr = IMarshal_GetUnmarshalClass(marshal, NULL, NULL, 0, NULL, 0, &clsid);
4122
    ok(hr == S_OK, "Failed to get class, hr %#lx\n", hr);
4123 4124 4125
    ok(IsEqualGUID(&clsid, &CLSID_ObjrefMoniker), "Unexpected class %s\n", wine_dbgstr_guid(&clsid));

    hr = IMarshal_GetMarshalSizeMax(marshal, &IID_IMoniker, NULL, CLSCTX_INPROC, NULL, 0, &size);
4126 4127
    ok(hr == S_OK, "Failed to get marshal size, hr %#lx\n", hr);
    ok(size > 0, "Unexpected size %ld\n", size);
4128 4129

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4130
    ok(hr == S_OK, "Failed to create a stream, hr %#lx\n", hr);
4131 4132

    hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
4133
    ok(hr == S_OK, "Failed to marshal moniker, hr %#lx\n", hr);
4134 4135 4136 4137

    pos.QuadPart = 0;
    IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
    hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker2);
4138
    ok(hr == S_OK, "Failed to unmarshal, hr %#lx\n", hr);
4139
    hr = IMoniker_IsEqual(moniker, moniker2);
4140
    todo_wine
4141
    ok(hr == S_OK, "Expected equal moniker, hr %#lx\n", hr);
4142 4143 4144 4145 4146 4147
    IMoniker_Release(moniker2);

    IStream_Release(stream);

    IMarshal_Release(marshal);

4148
    ok(factory.refcount > 1, "Unexpected factory refcount %lu\n", factory.refcount);
4149 4150 4151 4152

    /* Display Name */

    hr = CreateBindCtx(0, &bindctx);
4153
    ok(hr == S_OK, "CreateBindCtx failed: 0x%08lx\n", hr);
4154 4155

    hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
4156
    todo_wine
4157
    ok(hr == S_OK, "IMoniker_GetDisplayName failed: 0x%08lx\n", hr);
4158 4159 4160 4161

    IBindCtx_Release(bindctx);

    hr = IMoniker_IsDirty(moniker);
4162
    ok(hr == S_FALSE, "IMoniker_IsDirty should return S_FALSE, not 0x%08lx\n", hr);
4163 4164 4165 4166

    /* IROTData::GetComparisonData test */

    hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
4167
    ok(hr == E_NOINTERFACE, "IMoniker_QueryInterface(IID_IROTData) should have returned E_NOINTERFACE instead of 0x%08lx\n", hr);
4168 4169 4170 4171

    /* Saving */

    hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
4172
    ok(hr == S_OK, "CreateStreamOnHGlobal failed: 0x%08lx\n", hr);
4173 4174

    hr = IMoniker_Save(moniker, stream, TRUE);
4175
    todo_wine
4176
    ok(hr == S_OK, "IMoniker_Save failed: 0x%08lx\n", hr);
4177 4178 4179 4180 4181

    IStream_Release(stream);

    /* Hashing */
    hr = IMoniker_Hash(moniker, &hash);
4182 4183
    ok(hr == S_OK, "IMoniker_Hash failed: 0x%08lx\n", hr);
    ok(hash == PtrToUlong(&factory.IClassFactory_iface), "Unexpected hash value %#lx\n", hash);
4184 4185 4186 4187 4188

    /* IsSystemMoniker test */
    TEST_MONIKER_TYPE(moniker, MKSYS_OBJREFMONIKER);

    hr = IMoniker_Inverse(moniker, &inverse);
4189
    todo_wine
4190
    ok(hr == S_OK, "Failed to get inverse, hr %#lx\n", hr);
4191 4192 4193 4194 4195 4196 4197
if (hr == S_OK)
{
    TEST_MONIKER_TYPE(inverse, MKSYS_ANTIMONIKER);
    IMoniker_Release(inverse);
}

    hr = CreateBindCtx(0, &bindctx);
4198
    ok(hr == S_OK, "CreateBindCtx failed: 0x%08lx\n", hr);
4199 4200 4201

    /* IsRunning test */
    hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
4202
    todo_wine
4203
    ok(hr == S_OK, "IMoniker_IsRunning should return S_OK, not 0x%08lx\n", hr);
4204 4205

    hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
4206
    ok(hr == MK_E_UNAVAILABLE, "IMoniker_GetTimeOfLastChange should return MK_E_UNAVAILABLE, not 0x%08lx\n", hr);
4207 4208

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
4209
    todo_wine
4210
    ok(hr == S_OK, "IMoniker_BindToObject failed: 0x%08lx\n", hr);
4211 4212
    if (hr == S_OK)
        IUnknown_Release(unknown);
4213 4214

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
4215
    todo_wine
4216
    ok(hr == S_OK, "IMoniker_BindToObject failed: 0x%08lx\n", hr);
4217 4218
    if (hr == S_OK)
        IUnknown_Release(unknown);
4219 4220 4221

    IMoniker_Release(moniker);

4222
    todo_wine
4223
    ok(factory.refcount > 1, "Unexpected factory refcount %lu\n", factory.refcount);
4224 4225

    hr = CreateObjrefMoniker(NULL, &moniker);
4226
    ok(hr == S_OK, "CreateObjrefMoniker failed, hr %#lx\n", hr);
4227 4228

    hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
4229
    todo_wine
4230
    ok(hr == E_UNEXPECTED, "IMoniker_BindToObject should have returned E_UNEXPECTED instead of 0x%08lx\n", hr);
4231 4232

    hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
4233
    todo_wine
4234
    ok(hr == E_UNEXPECTED, "IMoniker_BindToStorage should have returned E_UNEXPECTED instead of 0x%08lx\n", hr);
4235 4236 4237 4238 4239 4240

    IBindCtx_Release(bindctx);

    /* Enum() */
    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker, TRUE, &enummoniker);
4241
    ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
4242 4243 4244 4245
    ok(enummoniker == NULL, "got %p\n", enummoniker);

    enummoniker = (void *)0xdeadbeef;
    hr = IMoniker_Enum(moniker, FALSE, &enummoniker);
4246
    ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
4247 4248 4249 4250 4251 4252
    ok(enummoniker == NULL, "got %p\n", enummoniker);

    IMoniker_Release(moniker);

    /* CommonPrefixWith() */
    hr = CreateObjrefMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker);
4253
    ok(hr == S_OK, "CreateObjrefMoniker failed: hr %#lx\n", hr);
4254 4255

    hr = CreateObjrefMoniker((IUnknown *)&factory.IClassFactory_iface, &moniker2);
4256
    ok(hr == S_OK, "CreateObjrefMoniker failed: hr %#lx\n", hr);
4257 4258

    hr = IMoniker_IsEqual(moniker, NULL);
4259
    todo_wine
4260
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx\n", hr);
4261 4262

    hr = IMoniker_IsEqual(moniker, moniker2);
4263
    todo_wine
4264
    ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
4265 4266

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, NULL);
4267
    todo_wine
4268
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx\n", hr);
4269 4270

    hr = IMoniker_CommonPrefixWith(moniker, NULL, &prefix);
4271
    todo_wine
4272
    ok(hr == E_INVALIDARG, "Unexpected hr %#lx\n", hr);
4273 4274

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &prefix);
4275
    todo_wine
4276
    ok(hr == MK_S_US, "Unexpected hr %#lx\n", hr);
4277 4278 4279 4280 4281 4282 4283 4284 4285
if (hr == S_OK)
{
    ok(prefix == moniker, "Unexpected pointer\n");
    IMoniker_Release(prefix);
}

    IMoniker_Release(moniker2);

    hr = CreateObjrefMoniker((IUnknown *)moniker, &moniker2);
4286
    ok(hr == S_OK, "Failed to create moniker, hr %#lx\n", hr);
4287 4288

    hr = IMoniker_IsEqual(moniker, moniker2);
4289
    todo_wine
4290
    ok(hr == S_FALSE, "Unexpected hr %#lx\n", hr);
4291 4292

    hr = IMoniker_CommonPrefixWith(moniker, moniker2, &prefix);
4293
    todo_wine
4294
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx\n", hr);
4295 4296 4297 4298 4299 4300 4301 4302

    IMoniker_Release(moniker2);

    /* ComposeWith() */

    /* P + A -> () */
    anti = create_antimoniker(1);
    hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
4303
    todo_wine
4304
    ok(hr == S_OK, "Failed to compose, hr %#lx\n", hr);
4305 4306
    if (hr == S_OK)
        ok(!moniker2, "Unexpected pointer\n");
4307 4308 4309 4310 4311
    IMoniker_Release(anti);

    /* P + A2 -> A */
    anti = create_antimoniker(2);
    hr = IMoniker_ComposeWith(moniker, anti, TRUE, &moniker2);
4312
    todo_wine
4313
    ok(hr == S_OK, "Failed to compose, hr %#lx\n", hr);
4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324
if (hr == S_OK)
{
    TEST_MONIKER_TYPE(moniker2, MKSYS_ANTIMONIKER);
    IMoniker_Release(moniker2);
}

    IMoniker_Release(anti);

    IMoniker_Release(moniker);
}

4325 4326
static void test_bind_context(void)
{
4327
    IRunningObjectTable *rot, *rot2;
4328 4329 4330
    HRESULT hr;
    IBindCtx *pBindCtx;
    IEnumString *pEnumString;
4331
    BIND_OPTS3 bind_opts;
4332 4333
    HeapUnknown *unknown;
    HeapUnknown *unknown2;
4334
    IUnknown *param_obj;
4335 4336
    ULONG refs;
    static const WCHAR wszParamName[] = {'G','e','m','m','a',0};
4337
    static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
4338 4339

    hr = CreateBindCtx(0, NULL);
4340
    ok(hr == E_INVALIDARG, "CreateBindCtx with NULL ppbc should have returned E_INVALIDARG instead of 0x%08lx\n", hr);
4341 4342

    hr = CreateBindCtx(0xdeadbeef, &pBindCtx);
4343
    ok(hr == E_INVALIDARG, "CreateBindCtx with reserved value non-zero should have returned E_INVALIDARG instead of 0x%08lx\n", hr);
4344 4345 4346 4347

    hr = CreateBindCtx(0, &pBindCtx);
    ok_ole_success(hr, "CreateBindCtx");

4348
    hr = IBindCtx_GetRunningObjectTable(pBindCtx, NULL);
4349
    ok(FAILED(hr), "Unexpected hr %#lx.\n", hr);
4350 4351

    hr = IBindCtx_GetRunningObjectTable(pBindCtx, &rot);
4352
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4353 4354

    hr = GetRunningObjectTable(0, &rot2);
4355
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4356 4357 4358 4359
    ok(rot == rot2, "Unexpected ROT instance.\n");
    IRunningObjectTable_Release(rot);
    IRunningObjectTable_Release(rot2);

4360 4361 4362
    bind_opts.cbStruct = -1;
    hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
    ok_ole_success(hr, "IBindCtx_GetBindOptions");
4363
    ok(bind_opts.cbStruct == sizeof(BIND_OPTS3) || broken(bind_opts.cbStruct == sizeof(BIND_OPTS2)) /* XP */,
4364
        "Unexpected bind_opts.cbStruct %ld.\n", bind_opts.cbStruct);
4365

4366 4367 4368
    bind_opts.cbStruct = sizeof(BIND_OPTS);
    hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
    ok_ole_success(hr, "IBindCtx_GetBindOptions");
4369
    ok(bind_opts.cbStruct == sizeof(BIND_OPTS), "bind_opts.cbStruct was %ld\n", bind_opts.cbStruct);
4370

4371
    memset(&bind_opts, 0xfe, sizeof(bind_opts));
4372 4373 4374
    bind_opts.cbStruct = sizeof(bind_opts);
    hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
    ok_ole_success(hr, "IBindCtx_GetBindOptions");
4375
    ok(bind_opts.cbStruct == sizeof(bind_opts) || bind_opts.cbStruct == sizeof(BIND_OPTS2) /* XP */,
4376 4377 4378 4379 4380
        "Unexpected bind_opts.cbStruct %ld.\n", bind_opts.cbStruct);
    ok(bind_opts.grfFlags == 0, "bind_opts.grfFlags was 0x%lx instead of 0\n", bind_opts.grfFlags);
    ok(bind_opts.grfMode == STGM_READWRITE, "bind_opts.grfMode was 0x%lx instead of STGM_READWRITE\n", bind_opts.grfMode);
    ok(bind_opts.dwTickCountDeadline == 0, "bind_opts.dwTickCountDeadline was %ld instead of 0\n", bind_opts.dwTickCountDeadline);
    ok(bind_opts.dwTrackFlags == 0, "bind_opts.dwTrackFlags was 0x%lx instead of 0\n", bind_opts.dwTrackFlags);
4381
    ok(bind_opts.dwClassContext == (CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER),
4382 4383
        "bind_opts.dwClassContext should have been 0x15 instead of 0x%lx\n", bind_opts.dwClassContext);
    ok(bind_opts.locale == GetThreadLocale(), "bind_opts.locale should have been 0x%lx instead of 0x%lx\n", GetThreadLocale(), bind_opts.locale);
4384
    ok(bind_opts.pServerInfo == NULL, "bind_opts.pServerInfo should have been NULL instead of %p\n", bind_opts.pServerInfo);
4385 4386
    if (bind_opts.cbStruct >= sizeof(BIND_OPTS3))
        ok(bind_opts.hwnd == NULL, "Unexpected bind_opts.hwnd %p.\n", bind_opts.hwnd);
4387 4388 4389

    bind_opts.cbStruct = -1;
    hr = IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
4390
    ok(hr == E_INVALIDARG, "IBindCtx_SetBindOptions with bad cbStruct should have returned E_INVALIDARG instead of 0x%08lx\n", hr);
4391 4392

    hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, NULL);
4393
    ok(hr == E_INVALIDARG, "IBindCtx_RegisterObjectParam should have returned E_INVALIDARG instead of 0x%08lx\n", hr);
4394

4395
    unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
4396
    unknown->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
4397
    unknown->refs = 1;
4398
    hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, &unknown->IUnknown_iface);
4399 4400
    ok_ole_success(hr, "IBindCtx_RegisterObjectParam");

4401 4402 4403 4404
    hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszParamName, &param_obj);
    ok_ole_success(hr, "IBindCtx_GetObjectParam");
    IUnknown_Release(param_obj);

4405
    hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszNonExistent, &param_obj);
4406
    ok(hr == E_FAIL, "IBindCtx_GetObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08lx\n", hr);
4407
    ok(param_obj == NULL, "IBindCtx_GetObjectParam with nonexistent key should have set output parameter to NULL instead of %p\n", param_obj);
4408

4409
    hr = IBindCtx_RevokeObjectParam(pBindCtx, (WCHAR *)wszNonExistent);
4410
    ok(hr == E_FAIL, "IBindCtx_RevokeObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08lx\n", hr);
4411

4412
    hr = IBindCtx_EnumObjectParam(pBindCtx, &pEnumString);
4413
    ok(hr == E_NOTIMPL, "IBindCtx_EnumObjectParam should have returned E_NOTIMPL instead of 0x%08lx\n", hr);
4414 4415 4416 4417 4418
    ok(!pEnumString, "pEnumString should be NULL\n");

    hr = IBindCtx_RegisterObjectBound(pBindCtx, NULL);
    ok_ole_success(hr, "IBindCtx_RegisterObjectBound(NULL)");

4419
    hr = IBindCtx_RevokeObjectBound(pBindCtx, NULL);
4420
    ok(hr == E_INVALIDARG, "IBindCtx_RevokeObjectBound(NULL) should have return E_INVALIDARG instead of 0x%08lx\n", hr);
4421 4422

    unknown2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
4423
    unknown2->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
4424
    unknown2->refs = 1;
4425
    hr = IBindCtx_RegisterObjectBound(pBindCtx, &unknown2->IUnknown_iface);
4426 4427
    ok_ole_success(hr, "IBindCtx_RegisterObjectBound");

4428
    hr = IBindCtx_RevokeObjectBound(pBindCtx, &unknown2->IUnknown_iface);
4429 4430
    ok_ole_success(hr, "IBindCtx_RevokeObjectBound");

4431
    hr = IBindCtx_RevokeObjectBound(pBindCtx, &unknown2->IUnknown_iface);
4432
    ok(hr == MK_E_NOTBOUND, "IBindCtx_RevokeObjectBound with not bound object should have returned MK_E_NOTBOUND instead of 0x%08lx\n", hr);
4433

4434 4435
    IBindCtx_Release(pBindCtx);

4436
    refs = IUnknown_Release(&unknown->IUnknown_iface);
4437
    ok(!refs, "object param should have been destroyed, instead of having %ld refs\n", refs);
4438

4439
    refs = IUnknown_Release(&unknown2->IUnknown_iface);
4440
    ok(!refs, "bound object should have been destroyed, instead of having %ld refs\n", refs);
4441 4442
}

4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453
static void test_save_load_filemoniker(void)
{
    IMoniker* pMk;
    IStream* pStm;
    HRESULT hr;
    ULARGE_INTEGER size;
    LARGE_INTEGER zero_pos, dead_pos, nulls_pos;
    DWORD some_val = 0xFEDCBA98;
    int i;

    /* see FileMonikerImpl_Save docs */
4454 4455 4456
    zero_pos.QuadPart = 0;
    dead_pos.QuadPart = sizeof(WORD) + sizeof(DWORD) + (lstrlenW(wszFileName1) + 1) + sizeof(WORD);
    nulls_pos.QuadPart = dead_pos.QuadPart + sizeof(WORD);
4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471

    /* create the stream we're going to write to */
    hr = CreateStreamOnHGlobal(NULL, TRUE, &pStm);
    ok_ole_success(hr, "CreateStreamOnHGlobal");

    size.u.LowPart = 128;
    hr = IStream_SetSize(pStm, size);
    ok_ole_success(hr, "IStream_SetSize");

    /* create and save a moniker */
    hr = CreateFileMoniker(wszFileName1, &pMk);
    ok_ole_success(hr, "CreateFileMoniker");

    hr = IMoniker_Save(pMk, pStm, TRUE);
    ok_ole_success(hr, "IMoniker_Save");
4472
    IMoniker_Release(pMk);
4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502

    /* overwrite the constants with various values */
    hr = IStream_Seek(pStm, zero_pos, STREAM_SEEK_SET, NULL);
    ok_ole_success(hr, "IStream_Seek");
    hr = IStream_Write(pStm, &some_val, sizeof(WORD), NULL);
    ok_ole_success(hr, "IStream_Write");

    hr = IStream_Seek(pStm, dead_pos, STREAM_SEEK_SET, NULL);
    ok_ole_success(hr, "IStream_Seek");
    hr = IStream_Write(pStm, &some_val, sizeof(WORD), NULL);
    ok_ole_success(hr, "IStream_Write");

    hr = IStream_Seek(pStm, nulls_pos, STREAM_SEEK_SET, NULL);
    ok_ole_success(hr, "IStream_Seek");
    for(i = 0; i < 5; ++i){
        hr = IStream_Write(pStm, &some_val, sizeof(DWORD), NULL);
        ok_ole_success(hr, "IStream_Write");
    }

    /* go back to the start of the stream */
    hr = IStream_Seek(pStm, zero_pos, STREAM_SEEK_SET, NULL);
    ok_ole_success(hr, "IStream_Seek");

    /* create a new moniker and load into it */
    hr = CreateFileMoniker(wszFileName1, &pMk);
    ok_ole_success(hr, "CreateFileMoniker");

    hr = IMoniker_Load(pMk, pStm);
    ok_ole_success(hr, "IMoniker_Load");

4503 4504
    IMoniker_Release(pMk);
    IStream_Release(pStm);
4505 4506
}

4507 4508 4509 4510 4511 4512 4513 4514
static void test_MonikerCommonPrefixWith(void)
{
    IMoniker *moniker, *item, *file1, *file2, *composite, *composite2;
    HRESULT hr;

    moniker = (void *)0xdeadbeef;
    hr = MonikerCommonPrefixWith(NULL, NULL, &moniker);
todo_wine {
4515
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4516 4517 4518 4519 4520 4521
    ok(!moniker, "Unexpected pointer.\n");
}
    if (hr == E_NOTIMPL)
        return;

    hr = CreateItemMoniker(L"!", L"Item", &item);
4522
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
4523

4524
    moniker = (void *)0xdeadbeef;
4525
    hr = MonikerCommonPrefixWith(item, NULL, &moniker);
4526
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4527
    ok(!moniker, "Unexpected pointer.\n");
4528

4529
    moniker = (void *)0xdeadbeef;
4530
    hr = MonikerCommonPrefixWith(NULL, item, &moniker);
4531
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4532
    ok(!moniker, "Unexpected pointer.\n");
4533 4534

    hr = MonikerCommonPrefixWith(item, item, &moniker);
4535
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4536 4537

    hr = CreateFileMoniker(L"C:\\test.txt", &file1);
4538
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
4539 4540

    hr = MonikerCommonPrefixWith(file1, NULL, &moniker);
4541
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4542 4543

    hr = MonikerCommonPrefixWith(NULL, file1, &moniker);
4544
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4545 4546 4547

    /* F x F */
    hr = MonikerCommonPrefixWith(file1, file1, &moniker);
4548
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4549 4550

    hr = CreateFileMoniker(L"C:\\a\\test.txt", &file2);
4551
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
4552 4553 4554

    /* F1 x F2 */
    hr = MonikerCommonPrefixWith(file1, file2, &moniker);
4555
    ok(hr == MK_E_NOPREFIX, "Unexpected hr %#lx.\n", hr);
4556 4557

    hr = CreateGenericComposite(file1, item, &composite);
4558
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
4559 4560

    hr = CreateGenericComposite(file2, item, &composite2);
4561
    ok(hr == S_OK, "Failed to create a moniker, hr %#lx.\n", hr);
4562 4563 4564

    /* F x (F,I) -> F */
    hr = MonikerCommonPrefixWith(file1, composite, &moniker);
4565
    ok(hr == MK_S_ME, "Unexpected hr %#lx.\n", hr);
4566 4567 4568 4569 4570
    ok(moniker == file1, "Unexpected pointer.\n");
    IMoniker_Release(moniker);

    /* F1 x (F2,I) -> F */
    hr = MonikerCommonPrefixWith(file1, composite2, &moniker);
4571
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4572 4573 4574 4575 4576 4577
    TEST_MONIKER_TYPE(moniker, MKSYS_FILEMONIKER);
    TEST_DISPLAY_NAME(moniker, L"C:\\");
    IMoniker_Release(moniker);

    /* (F2,I) x F1 -> F */
    hr = MonikerCommonPrefixWith(composite2, file1, &moniker);
4578
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4579 4580 4581 4582 4583 4584
    TEST_MONIKER_TYPE(moniker, MKSYS_FILEMONIKER);
    TEST_DISPLAY_NAME(moniker, L"C:\\");
    IMoniker_Release(moniker);

    /* (F,I) x (F) -> F */
    hr = MonikerCommonPrefixWith(composite, file1, &moniker);
4585
    ok(hr == MK_S_HIM, "Unexpected hr %#lx.\n", hr);
4586 4587 4588 4589 4590
    ok(moniker == file1, "Unexpected pointer.\n");
    IMoniker_Release(moniker);

    /* (F,I) x (F,I) -> (F,I) */
    hr = MonikerCommonPrefixWith(composite, composite, &moniker);
4591
    ok(hr == MK_S_US, "Unexpected hr %#lx.\n", hr);
4592 4593 4594 4595 4596 4597 4598
    TEST_MONIKER_TYPE(moniker, MKSYS_GENERICCOMPOSITE);
    TEST_DISPLAY_NAME(moniker, L"C:\\test.txt!Item");
    ok(moniker != composite, "Unexpected pointer.\n");
    IMoniker_Release(moniker);

    /* (F1,I) x (F2,I) -> () */
    hr = MonikerCommonPrefixWith(composite, composite2, &moniker);
4599
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4600 4601 4602 4603
    ok(!moniker, "Unexpected pointer %p.\n", moniker);

    IMoniker_Release(composite2);
    IMoniker_Release(composite);
4604 4605 4606

    /* (I1,(I2,I3)) x ((I1,I2),I4) */
    hr = create_moniker_from_desc("CI1CI2I3", &composite);
4607
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4608
    hr = create_moniker_from_desc("CCI1I2I4", &composite2);
4609
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4610
    hr = MonikerCommonPrefixWith(composite, composite2, &moniker);
4611
    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
4612 4613 4614 4615
    TEST_MONIKER_TYPE(moniker, MKSYS_GENERICCOMPOSITE);
    TEST_DISPLAY_NAME(moniker, L"!I1!I2");
    IMoniker_Release(moniker);

4616 4617 4618 4619 4620
    IMoniker_Release(file2);
    IMoniker_Release(file1);
    IMoniker_Release(item);
}

4621 4622 4623 4624
START_TEST(moniker)
{
    CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

4625
    test_ROT();
4626
    test_ROT_multiple_entries();
4627
    test_MkParseDisplayName();
Robert Shearman's avatar
Robert Shearman committed
4628
    test_class_moniker();
4629
    test_file_monikers();
4630
    test_item_moniker();
4631
    test_anti_moniker();
4632
    test_generic_composite_moniker();
4633
    test_pointer_moniker();
4634
    test_objref_moniker();
4635
    test_save_load_filemoniker();
4636
    test_MonikerCommonPrefixWith();
4637

Robert Shearman's avatar
Robert Shearman committed
4638
    /* FIXME: test moniker creation funcs and parsing other moniker formats */
4639

4640 4641
    test_bind_context();

4642 4643
    CoUninitialize();
}