ole32: Add some more tests for MkParseDisplayName.
[wine] / dlls / ole32 / tests / moniker.c
1 /*
2  * Moniker Tests
3  *
4  * Copyright 2004 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define _WIN32_DCOM
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "objbase.h"
31 #include "comcat.h"
32 #include "olectl.h"
33
34 #include "wine/test.h"
35
36 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
37 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
38 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
39 #define COUNTOF(x) (sizeof(x) / sizeof(x[0]))
40
41 #define CHECK_EXPECTED_METHOD(method_name) \
42 do { \
43     trace("%s\n", method_name); \
44         ok(*expected_method_list != NULL, "Extra method %s called\n", method_name); \
45             if (*expected_method_list) \
46             { \
47                 ok(!strcmp(*expected_method_list, method_name), "Expected %s to be called instead of %s\n", \
48                    *expected_method_list, method_name); \
49                        expected_method_list++; \
50             } \
51 } while(0)
52
53 static char const * const *expected_method_list;
54 static const WCHAR wszFileName1[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','1','.','d','o','c',0};
55 static const WCHAR wszFileName2[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','2','.','d','o','c',0};
56
57 static const CLSID CLSID_WineTest =
58 { /* 9474ba1a-258b-490b-bc13-516e9239ace0 */
59     0x9474ba1a,
60     0x258b,
61     0x490b,
62     {0xbc, 0x13, 0x51, 0x6e, 0x92, 0x39, 0xac, 0xe0}
63 };
64
65 static const CLSID CLSID_TestMoniker =
66 { /* b306bfbc-496e-4f53-b93e-2ff9c83223d7 */
67     0xb306bfbc,
68     0x496e,
69     0x4f53,
70     {0xb9, 0x3e, 0x2f, 0xf9, 0xc8, 0x32, 0x23, 0xd7}
71 };
72
73 static LONG cLocks;
74
75 static void LockModule(void)
76 {
77     InterlockedIncrement(&cLocks);
78 }
79
80 static void UnlockModule(void)
81 {
82     InterlockedDecrement(&cLocks);
83 }
84
85 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
86     LPCLASSFACTORY iface,
87     REFIID riid,
88     LPVOID *ppvObj)
89 {
90     if (ppvObj == NULL) return E_POINTER;
91
92     if (IsEqualGUID(riid, &IID_IUnknown) ||
93         IsEqualGUID(riid, &IID_IClassFactory))
94     {
95         *ppvObj = (LPVOID)iface;
96         IClassFactory_AddRef(iface);
97         return S_OK;
98     }
99
100     *ppvObj = NULL;
101     return E_NOINTERFACE;
102 }
103
104 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
105 {
106     LockModule();
107     return 2; /* non-heap-based object */
108 }
109
110 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
111 {
112     UnlockModule();
113     return 1; /* non-heap-based object */
114 }
115
116 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
117     LPCLASSFACTORY iface,
118     LPUNKNOWN pUnkOuter,
119     REFIID riid,
120     LPVOID *ppvObj)
121 {
122     return E_NOTIMPL;
123 }
124
125 static HRESULT WINAPI Test_IClassFactory_LockServer(
126     LPCLASSFACTORY iface,
127     BOOL fLock)
128 {
129     return S_OK;
130 }
131
132 static const IClassFactoryVtbl TestClassFactory_Vtbl =
133 {
134     Test_IClassFactory_QueryInterface,
135     Test_IClassFactory_AddRef,
136     Test_IClassFactory_Release,
137     Test_IClassFactory_CreateInstance,
138     Test_IClassFactory_LockServer
139 };
140
141 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
142
143 typedef struct
144 {
145     const IUnknownVtbl *lpVtbl;
146     ULONG refs;
147 } HeapUnknown;
148
149 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
150 {
151     if (IsEqualIID(riid, &IID_IUnknown))
152     {
153         IUnknown_AddRef(iface);
154         *ppv = (LPVOID)iface;
155         return S_OK;
156     }
157     *ppv = NULL;
158     return E_NOINTERFACE;
159 }
160
161 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
162 {
163     HeapUnknown *This = (HeapUnknown *)iface;
164     return InterlockedIncrement((LONG*)&This->refs);
165 }
166
167 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
168 {
169     HeapUnknown *This = (HeapUnknown *)iface;
170     ULONG refs = InterlockedDecrement((LONG*)&This->refs);
171     if (!refs) HeapFree(GetProcessHeap(), 0, This);
172     return refs;
173 }
174
175 static const IUnknownVtbl HeapUnknown_Vtbl =
176 {
177     HeapUnknown_QueryInterface,
178     HeapUnknown_AddRef,
179     HeapUnknown_Release
180 };
181
182 static HRESULT WINAPI
183 MonikerNoROTData_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
184 {
185     if (!ppvObject)
186         return E_INVALIDARG;
187
188     *ppvObject = 0;
189
190     if (IsEqualIID(&IID_IUnknown, riid)      ||
191         IsEqualIID(&IID_IPersist, riid)      ||
192         IsEqualIID(&IID_IPersistStream,riid) ||
193         IsEqualIID(&IID_IMoniker, riid))
194         *ppvObject = iface;
195     if (IsEqualIID(&IID_IROTData, riid))
196         CHECK_EXPECTED_METHOD("Moniker_QueryInterface(IID_IROTData)");
197
198     if ((*ppvObject)==0)
199         return E_NOINTERFACE;
200
201     IMoniker_AddRef(iface);
202
203     return S_OK;
204 }
205
206 static ULONG WINAPI
207 Moniker_AddRef(IMoniker* iface)
208 {
209     return 2;
210 }
211
212 static ULONG WINAPI
213 Moniker_Release(IMoniker* iface)
214 {
215     return 1;
216 }
217
218 static HRESULT WINAPI
219 Moniker_GetClassID(IMoniker* iface, CLSID *pClassID)
220 {
221     CHECK_EXPECTED_METHOD("Moniker_GetClassID");
222
223     *pClassID = CLSID_TestMoniker;
224
225     return S_OK;
226 }
227
228 static HRESULT WINAPI
229 Moniker_IsDirty(IMoniker* iface)
230 {
231     CHECK_EXPECTED_METHOD("Moniker_IsDirty");
232
233     return S_FALSE;
234 }
235
236 static HRESULT WINAPI
237 Moniker_Load(IMoniker* iface, IStream* pStm)
238 {
239     CHECK_EXPECTED_METHOD("Moniker_Load");
240     return E_NOTIMPL;
241 }
242
243 static HRESULT WINAPI
244 Moniker_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
245 {
246     CHECK_EXPECTED_METHOD("Moniker_Save");
247     return E_NOTIMPL;
248 }
249
250 static HRESULT WINAPI
251 Moniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
252 {
253     CHECK_EXPECTED_METHOD("Moniker_GetSizeMax");
254     return E_NOTIMPL;
255 }
256
257 static HRESULT WINAPI
258 Moniker_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
259                              REFIID riid, VOID** ppvResult)
260 {
261     CHECK_EXPECTED_METHOD("Moniker_BindToObject");
262     return E_NOTIMPL;
263 }
264
265 static HRESULT WINAPI
266 Moniker_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
267                               REFIID riid, VOID** ppvObject)
268 {
269     CHECK_EXPECTED_METHOD("Moniker_BindToStorage");
270     return E_NOTIMPL;
271 }
272
273 static HRESULT WINAPI
274 Moniker_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
275                        IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
276 {
277     CHECK_EXPECTED_METHOD("Moniker_Reduce");
278
279     if (ppmkReduced==NULL)
280         return E_POINTER;
281
282     IMoniker_AddRef(iface);
283
284     *ppmkReduced=iface;
285
286     return MK_S_REDUCED_TO_SELF;
287 }
288
289 static HRESULT WINAPI
290 Moniker_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
291                             BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
292 {
293     CHECK_EXPECTED_METHOD("Moniker_ComposeWith");
294     return E_NOTIMPL;
295 }
296
297 static HRESULT WINAPI
298 Moniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
299 {
300     CHECK_EXPECTED_METHOD("Moniker_Enum");
301
302     if (ppenumMoniker == NULL)
303         return E_POINTER;
304
305     *ppenumMoniker = NULL;
306
307     return S_OK;
308 }
309
310 static HRESULT WINAPI
311 Moniker_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
312 {
313     CHECK_EXPECTED_METHOD("Moniker_IsEqual");
314     return E_NOTIMPL;
315 }
316
317 static HRESULT WINAPI
318 Moniker_Hash(IMoniker* iface,DWORD* pdwHash)
319 {
320     CHECK_EXPECTED_METHOD("Moniker_Hash");
321     return E_NOTIMPL;
322 }
323
324 static HRESULT WINAPI
325 Moniker_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
326                           IMoniker* pmkNewlyRunning)
327 {
328     CHECK_EXPECTED_METHOD("Moniker_IsRunning");
329     return E_NOTIMPL;
330 }
331
332 static HRESULT WINAPI
333 Moniker_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
334                                     IMoniker* pmkToLeft, FILETIME* pFileTime)
335 {
336     CHECK_EXPECTED_METHOD("Moniker_GetTimeOfLastChange");
337     return E_NOTIMPL;
338 }
339
340 static HRESULT WINAPI
341 Moniker_Inverse(IMoniker* iface,IMoniker** ppmk)
342 {
343     CHECK_EXPECTED_METHOD("Moniker_Inverse");
344     return E_NOTIMPL;
345 }
346
347 static HRESULT WINAPI
348 Moniker_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
349 {
350     CHECK_EXPECTED_METHOD("Moniker_CommonPrefixWith");
351     return E_NOTIMPL;
352 }
353
354 static HRESULT WINAPI
355 Moniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
356 {
357     CHECK_EXPECTED_METHOD("Moniker_RelativePathTo");
358     return E_NOTIMPL;
359 }
360
361 static HRESULT WINAPI
362 Moniker_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
363                                IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
364 {
365     static const WCHAR wszDisplayName[] = {'*','*','G','e','m','m','a',0};
366     CHECK_EXPECTED_METHOD("Moniker_GetDisplayName");
367     *ppszDisplayName = (LPOLESTR)CoTaskMemAlloc(sizeof(wszDisplayName));
368     memcpy(*ppszDisplayName, wszDisplayName, sizeof(wszDisplayName));
369     return S_OK;
370 }
371
372 static HRESULT WINAPI
373 Moniker_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
374                      LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
375 {
376     CHECK_EXPECTED_METHOD("Moniker_ParseDisplayName");
377     return E_NOTIMPL;
378 }
379
380 static HRESULT WINAPI
381 Moniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
382 {
383     CHECK_EXPECTED_METHOD("Moniker_IsSystemMoniker");
384
385     if (!pwdMksys)
386         return E_POINTER;
387
388     (*pwdMksys)=MKSYS_NONE;
389
390     return S_FALSE;
391 }
392
393 static const IMonikerVtbl MonikerNoROTDataVtbl =
394 {
395     MonikerNoROTData_QueryInterface,
396     Moniker_AddRef,
397     Moniker_Release,
398     Moniker_GetClassID,
399     Moniker_IsDirty,
400     Moniker_Load,
401     Moniker_Save,
402     Moniker_GetSizeMax,
403     Moniker_BindToObject,
404     Moniker_BindToStorage,
405     Moniker_Reduce,
406     Moniker_ComposeWith,
407     Moniker_Enum,
408     Moniker_IsEqual,
409     Moniker_Hash,
410     Moniker_IsRunning,
411     Moniker_GetTimeOfLastChange,
412     Moniker_Inverse,
413     Moniker_CommonPrefixWith,
414     Moniker_RelativePathTo,
415     Moniker_GetDisplayName,
416     Moniker_ParseDisplayName,
417     Moniker_IsSystemMoniker
418 };
419
420 static IMoniker MonikerNoROTData = { &MonikerNoROTDataVtbl };
421
422 static IMoniker Moniker;
423
424 static HRESULT WINAPI
425 ROTData_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
426 {
427     return IMoniker_QueryInterface(&Moniker, riid, ppvObject);
428 }
429
430 static ULONG WINAPI
431 ROTData_AddRef(IROTData *iface)
432 {
433     return 2;
434 }
435
436 static ULONG WINAPI
437 ROTData_Release(IROTData* iface)
438 {
439     return 1;
440 }
441
442 static HRESULT WINAPI
443 ROTData_GetComparisonData(IROTData* iface, BYTE* pbData,
444                                           ULONG cbMax, ULONG* pcbData)
445 {
446     CHECK_EXPECTED_METHOD("ROTData_GetComparisonData");
447
448     *pcbData = 1;
449     if (cbMax < *pcbData)
450         return E_OUTOFMEMORY;
451
452     *pbData = 0xde;
453
454     return S_OK;
455 }
456
457 static IROTDataVtbl ROTDataVtbl =
458 {
459     ROTData_QueryInterface,
460     ROTData_AddRef,
461     ROTData_Release,
462     ROTData_GetComparisonData
463 };
464
465 static IROTData ROTData = { &ROTDataVtbl };
466
467 static HRESULT WINAPI
468 Moniker_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
469 {
470     if (!ppvObject)
471         return E_INVALIDARG;
472
473     *ppvObject = 0;
474
475     if (IsEqualIID(&IID_IUnknown, riid)      ||
476         IsEqualIID(&IID_IPersist, riid)      ||
477         IsEqualIID(&IID_IPersistStream,riid) ||
478         IsEqualIID(&IID_IMoniker, riid))
479         *ppvObject = iface;
480     if (IsEqualIID(&IID_IROTData, riid))
481     {
482         CHECK_EXPECTED_METHOD("Moniker_QueryInterface(IID_IROTData)");
483         *ppvObject = &ROTData;
484     }
485
486     if ((*ppvObject)==0)
487         return E_NOINTERFACE;
488
489     IMoniker_AddRef(iface);
490
491     return S_OK;
492 }
493
494 static const IMonikerVtbl MonikerVtbl =
495 {
496     Moniker_QueryInterface,
497     Moniker_AddRef,
498     Moniker_Release,
499     Moniker_GetClassID,
500     Moniker_IsDirty,
501     Moniker_Load,
502     Moniker_Save,
503     Moniker_GetSizeMax,
504     Moniker_BindToObject,
505     Moniker_BindToStorage,
506     Moniker_Reduce,
507     Moniker_ComposeWith,
508     Moniker_Enum,
509     Moniker_IsEqual,
510     Moniker_Hash,
511     Moniker_IsRunning,
512     Moniker_GetTimeOfLastChange,
513     Moniker_Inverse,
514     Moniker_CommonPrefixWith,
515     Moniker_RelativePathTo,
516     Moniker_GetDisplayName,
517     Moniker_ParseDisplayName,
518     Moniker_IsSystemMoniker
519 };
520
521 static IMoniker Moniker = { &MonikerVtbl };
522
523 static void test_ROT(void)
524 {
525     static const WCHAR wszFileName[] = {'B','E','2','0','E','2','F','5','-',
526         '1','9','0','3','-','4','A','A','E','-','B','1','A','F','-',
527         '2','0','4','6','E','5','8','6','C','9','2','5',0};
528     HRESULT hr;
529     IMoniker *pMoniker = NULL;
530     IRunningObjectTable *pROT = NULL;
531     DWORD dwCookie;
532     static const char *methods_register_no_ROTData[] =
533     {
534         "Moniker_Reduce",
535         "Moniker_GetTimeOfLastChange",
536         "Moniker_QueryInterface(IID_IROTData)",
537         "Moniker_GetDisplayName",
538         "Moniker_GetClassID",
539         NULL
540     };
541     static const char *methods_register[] =
542     {
543         "Moniker_Reduce",
544         "Moniker_GetTimeOfLastChange",
545         "Moniker_QueryInterface(IID_IROTData)",
546         "ROTData_GetComparisonData",
547         NULL
548     };
549     static const char *methods_isrunning_no_ROTData[] =
550     {
551         "Moniker_Reduce",
552         "Moniker_QueryInterface(IID_IROTData)",
553         "Moniker_GetDisplayName",
554         "Moniker_GetClassID",
555         NULL
556     };
557     static const char *methods_isrunning[] =
558     {
559         "Moniker_Reduce",
560         "Moniker_QueryInterface(IID_IROTData)",
561         "ROTData_GetComparisonData",
562         NULL
563     };
564
565     cLocks = 0;
566
567     hr = GetRunningObjectTable(0, &pROT);
568     ok_ole_success(hr, GetRunningObjectTable);
569
570     expected_method_list = methods_register_no_ROTData;
571     /* try with our own moniker that doesn't support IROTData */
572     hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE,
573         (IUnknown*)&Test_ClassFactory, &MonikerNoROTData, &dwCookie);
574     todo_wine { /* only fails because of lack of IMoniker marshaling */
575     ok_ole_success(hr, IRunningObjectTable_Register);
576     }
577     ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
578
579     todo_wine { /* only fails because of lack of IMoniker marshaling */
580     ok_more_than_one_lock();
581     }
582
583     expected_method_list = methods_isrunning_no_ROTData;
584     hr = IRunningObjectTable_IsRunning(pROT, &MonikerNoROTData);
585     todo_wine { /* only fails because of lack of IMoniker marshaling */
586     ok_ole_success(hr, IRunningObjectTable_IsRunning);
587     }
588     ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
589
590     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
591     todo_wine { /* only fails because of lack of IMoniker marshaling */
592     ok_ole_success(hr, IRunningObjectTable_Revoke);
593     }
594
595     ok_no_locks();
596
597     expected_method_list = methods_register;
598     /* try with our own moniker */
599     hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE,
600         (IUnknown*)&Test_ClassFactory, &Moniker, &dwCookie);
601     todo_wine { /* only fails because of lack of IMoniker marshaling */
602     ok_ole_success(hr, IRunningObjectTable_Register);
603     }
604     ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
605
606     todo_wine { /* only fails because of lack of IMoniker marshaling */
607     ok_more_than_one_lock();
608     }
609
610     expected_method_list = methods_isrunning;
611     hr = IRunningObjectTable_IsRunning(pROT, &Moniker);
612     todo_wine { /* only fails because of lack of IMoniker marshaling */
613     ok_ole_success(hr, IRunningObjectTable_IsRunning);
614     }
615     ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
616
617     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
618     todo_wine { /* only fails because of lack of IMoniker marshaling */
619     ok_ole_success(hr, IRunningObjectTable_Revoke);
620     }
621
622     ok_no_locks();
623
624     hr = CreateFileMoniker(wszFileName, &pMoniker);
625     ok_ole_success(hr, CreateClassMoniker);
626
627     /* test flags: 0 */
628     hr = IRunningObjectTable_Register(pROT, 0, (IUnknown*)&Test_ClassFactory,
629                                       pMoniker, &dwCookie);
630     ok_ole_success(hr, IRunningObjectTable_Register);
631
632     ok_more_than_one_lock();
633
634     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
635     ok_ole_success(hr, IRunningObjectTable_Revoke);
636
637     ok_no_locks();
638
639     /* test flags: ROTFLAGS_REGISTRATIONKEEPSALIVE */
640     hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE,
641         (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
642     ok_ole_success(hr, IRunningObjectTable_Register);
643
644     ok_more_than_one_lock();
645
646     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
647     ok_ole_success(hr, IRunningObjectTable_Revoke);
648
649     ok_no_locks();
650
651     /* test flags: ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT */
652     /* only succeeds when process is started by SCM and has LocalService
653      * or RunAs AppId values */
654     hr = IRunningObjectTable_Register(pROT,
655         ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT,
656         (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
657     todo_wine {
658     ok(hr == CO_E_WRONG_SERVER_IDENTITY, "IRunningObjectTable_Register should have returned CO_E_WRONG_SERVER_IDENTITY instead of 0x%08x\n", hr);
659     }
660
661     hr = IRunningObjectTable_Register(pROT, 0xdeadbeef,
662         (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
663     ok(hr == E_INVALIDARG, "IRunningObjectTable_Register should have returned E_INVALIDARG instead of 0x%08x\n", hr);
664
665     IMoniker_Release(pMoniker);
666
667     IRunningObjectTable_Release(pROT);
668 }
669
670 static HRESULT WINAPI ParseDisplayName_QueryInterface(IParseDisplayName *iface, REFIID riid, void **ppv)
671 {
672     if (IsEqualIID(riid, &IID_IUnknown) ||
673         IsEqualIID(riid, &IID_IParseDisplayName))
674     {
675         *ppv = iface;
676         IUnknown_AddRef(iface);
677         return S_OK;
678     }
679     *ppv = NULL;
680     return E_NOINTERFACE;
681 }
682
683 static ULONG WINAPI ParseDisplayName_AddRef(IParseDisplayName *iface)
684 {
685     return 2;
686 }
687
688 static ULONG WINAPI ParseDisplayName_Release(IParseDisplayName *iface)
689 {
690     return 1;
691 }
692
693 static LPCWSTR expected_display_name;
694
695 static HRESULT WINAPI ParseDisplayName_ParseDisplayName(IParseDisplayName *iface,
696                                                         IBindCtx *pbc,
697                                                         LPOLESTR pszDisplayName,
698                                                         ULONG *pchEaten,
699                                                         IMoniker **ppmkOut)
700 {
701     char display_nameA[256];
702     WideCharToMultiByte(CP_ACP, 0, pszDisplayName, -1, display_nameA, sizeof(display_nameA), NULL, NULL);
703     ok(!lstrcmpW(pszDisplayName, expected_display_name), "unexpected display name \"%s\"\n", display_nameA);
704     ok(pszDisplayName == expected_display_name, "pszDisplayName should be the same pointer as passed into MkParseDisplayName\n");
705     *pchEaten = lstrlenW(pszDisplayName);
706     return CreateAntiMoniker(ppmkOut);
707 }
708
709 static const IParseDisplayNameVtbl ParseDisplayName_Vtbl =
710 {
711     ParseDisplayName_QueryInterface,
712     ParseDisplayName_AddRef,
713     ParseDisplayName_Release,
714     ParseDisplayName_ParseDisplayName
715 };
716
717 static IParseDisplayName ParseDisplayName = { &ParseDisplayName_Vtbl };
718
719 static int count_moniker_matches(IBindCtx * pbc, IEnumMoniker * spEM)
720 {
721     IMoniker * spMoniker;
722     int monCnt=0, matchCnt=0;
723
724     while ((IEnumMoniker_Next(spEM, 1, &spMoniker, NULL)==S_OK))
725     {
726         HRESULT hr;
727         WCHAR * szDisplayn;
728         monCnt++;
729         hr=IMoniker_GetDisplayName(spMoniker, pbc, NULL, &szDisplayn);
730         if (SUCCEEDED(hr))
731         {
732             if (!lstrcmpiW(szDisplayn, wszFileName1) || !lstrcmpiW(szDisplayn, wszFileName2))
733                 matchCnt++;
734             CoTaskMemFree(szDisplayn);
735         }
736     }
737     trace("Total number of monikers is %i\n", monCnt);
738     return matchCnt;
739 }
740
741 static void test_MkParseDisplayName(void)
742 {
743     IBindCtx * pbc = NULL;
744     HRESULT hr;
745     IMoniker * pmk  = NULL;
746     IMoniker * pmk1 = NULL;
747     IMoniker * pmk2 = NULL;
748     ULONG eaten;
749     int matchCnt;
750     IUnknown * object = NULL;
751
752     IUnknown *lpEM1;
753
754     IEnumMoniker *spEM1  = NULL;
755     IEnumMoniker *spEM2  = NULL;
756     IEnumMoniker *spEM3  = NULL;
757
758     DWORD pdwReg1=0;
759     DWORD grflags=0;
760     DWORD pdwReg2=0;
761     DWORD moniker_type;
762     IRunningObjectTable * pprot=NULL;
763
764     /* CLSID of My Computer */
765     static const WCHAR wszDisplayName[] = {'c','l','s','i','d',':',
766         '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};
767     static const WCHAR wszDisplayNameClsid[] = {'c','l','s','i','d',':',0};
768     static const WCHAR wszNonExistantProgId[] = {'N','o','n','E','x','i','s','t','a','n','t','P','r','o','g','I','d',':',0};
769     static const WCHAR wszDisplayNameRunning[] = {'W','i','n','e','T','e','s','t','R','u','n','n','i','n','g',0};
770     static const WCHAR wszDisplayNameProgId1[] = {'S','t','d','F','o','n','t',':',0};
771     static const WCHAR wszDisplayNameProgId2[] = {'@','S','t','d','F','o','n','t',0};
772     static const WCHAR wszDisplayNameProgIdFail[] = {'S','t','d','F','o','n','t',0};
773     char szDisplayNameFile[256];
774     WCHAR wszDisplayNameFile[256];
775
776     hr = CreateBindCtx(0, &pbc);
777     ok_ole_success(hr, CreateBindCtx);
778
779     hr = MkParseDisplayName(pbc, wszNonExistantProgId, &eaten, &pmk);
780     todo_wine { ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName should have failed with MK_E_CANTOPENFILE instead of 0x%08x\n", hr); }
781
782     /* no special handling of "clsid:" without the string form of the clsid
783      * following */
784     hr = MkParseDisplayName(pbc, wszDisplayNameClsid, &eaten, &pmk);
785     todo_wine { ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName should have failed with MK_E_CANTOPENFILE instead of 0x%08x\n", hr); }
786
787     /* shows clsid has higher precedence than a running object */
788     hr = CreateFileMoniker(wszDisplayName, &pmk);
789     ok_ole_success(hr, CreateFileMoniker);
790     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
791     ok_ole_success(hr, IBindCtx_GetRunningObjectTable);
792     hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&Test_ClassFactory, pmk, &pdwReg1);
793     ok_ole_success(hr, IRunningObjectTable_Register);
794     IMoniker_Release(pmk);
795     pmk = NULL;
796     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
797     todo_wine { ok_ole_success(hr, MkParseDisplayName); }
798     if (pmk)
799     {
800         IMoniker_IsSystemMoniker(pmk, &moniker_type);
801         ok(moniker_type == MKSYS_CLASSMONIKER, "moniker_type was %d instead of MKSYS_CLASSMONIKER\n", moniker_type);
802         IMoniker_Release(pmk);
803     }
804     hr = IRunningObjectTable_Revoke(pprot, pdwReg1);
805     ok_ole_success(hr, IRunningObjectTable_Revoke);
806     IRunningObjectTable_Release(pprot);
807
808     hr = CreateFileMoniker(wszDisplayNameRunning, &pmk);
809     ok_ole_success(hr, CreateFileMoniker);
810     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
811     ok_ole_success(hr, IBindCtx_GetRunningObjectTable);
812     hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&Test_ClassFactory, pmk, &pdwReg1);
813     ok_ole_success(hr, IRunningObjectTable_Register);
814     IMoniker_Release(pmk);
815     pmk = NULL;
816     hr = MkParseDisplayName(pbc, wszDisplayNameRunning, &eaten, &pmk);
817     todo_wine { ok_ole_success(hr, MkParseDisplayName); }
818     if (pmk)
819     {
820         IMoniker_IsSystemMoniker(pmk, &moniker_type);
821         ok(moniker_type == MKSYS_FILEMONIKER, "moniker_type was %d instead of MKSYS_FILEMONIKER\n", moniker_type);
822         IMoniker_Release(pmk);
823     }
824     hr = IRunningObjectTable_Revoke(pprot, pdwReg1);
825     ok_ole_success(hr, IRunningObjectTable_Revoke);
826     IRunningObjectTable_Release(pprot);
827
828     hr = CoRegisterClassObject(&CLSID_StdFont, (IUnknown *)&ParseDisplayName, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &pdwReg1);
829     ok_ole_success(hr, CoRegisterClassObject);
830
831     expected_display_name = wszDisplayNameProgId1;
832     hr = MkParseDisplayName(pbc, wszDisplayNameProgId1, &eaten, &pmk);
833     todo_wine { ok_ole_success(hr, MkParseDisplayName); }
834     if (pmk)
835     {
836         IMoniker_IsSystemMoniker(pmk, &moniker_type);
837         ok(moniker_type == MKSYS_ANTIMONIKER, "moniker_type was %d instead of MKSYS_ANTIMONIKER\n", moniker_type);
838         IMoniker_Release(pmk);
839     }
840
841     expected_display_name = wszDisplayNameProgId2;
842     hr = MkParseDisplayName(pbc, wszDisplayNameProgId2, &eaten, &pmk);
843     todo_wine { ok_ole_success(hr, MkParseDisplayName); }
844     if (pmk)
845     {
846         IMoniker_IsSystemMoniker(pmk, &moniker_type);
847         ok(moniker_type == MKSYS_ANTIMONIKER, "moniker_type was %d instead of MKSYS_ANTIMONIKER\n", moniker_type);
848         IMoniker_Release(pmk);
849     }
850
851     hr = MkParseDisplayName(pbc, wszDisplayNameProgIdFail, &eaten, &pmk);
852     todo_wine { ok(hr == MK_E_CANTOPENFILE, "MkParseDisplayName with ProgId without marker should fail with MK_E_CANTOPENFILE instead of 0x%08x\n", hr); }
853
854     hr = CoRevokeClassObject(pdwReg1);
855     ok_ole_success(hr, CoRevokeClassObject);
856
857     GetSystemDirectoryA(szDisplayNameFile, sizeof(szDisplayNameFile));
858     strcat(szDisplayNameFile, "\\kernel32.dll");
859     MultiByteToWideChar(CP_ACP, 0, szDisplayNameFile, -1, wszDisplayNameFile, sizeof(wszDisplayNameFile)/sizeof(wszDisplayNameFile[0]));
860     hr = MkParseDisplayName(pbc, wszDisplayNameFile, &eaten, &pmk);
861     todo_wine { ok_ole_success(hr, MkParseDisplayName); }
862     if (pmk)
863     {
864         IMoniker_IsSystemMoniker(pmk, &moniker_type);
865         ok(moniker_type == MKSYS_FILEMONIKER, "moniker_type was %d instead of MKSYS_FILEMONIKER\n", moniker_type);
866         IMoniker_Release(pmk);
867     }
868
869     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
870     todo_wine { ok_ole_success(hr, MkParseDisplayName); }
871
872     if (pmk)
873     {
874         hr = IMoniker_BindToObject(pmk, pbc, NULL, &IID_IUnknown, (LPVOID*)&object);
875         ok_ole_success(hr, IMoniker_BindToObject);
876
877         IUnknown_Release(object);
878     }
879     IBindCtx_Release(pbc);
880
881     /* Test the EnumMoniker interface */
882     hr = CreateBindCtx(0, &pbc);
883     ok_ole_success(hr, CreateBindCtx);
884
885     hr = CreateFileMoniker(wszFileName1, &pmk1);
886     ok(hr==0, "CreateFileMoniker for file hr=%08x\n", hr);
887     hr = CreateFileMoniker(wszFileName2, &pmk2);
888     ok(hr==0, "CreateFileMoniker for file hr=%08x\n", hr);
889     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
890     ok(hr==0, "IBindCtx_GetRunningObjectTable hr=%08x\n", hr);
891
892     /* Check EnumMoniker before registering */
893     hr = IRunningObjectTable_EnumRunning(pprot, &spEM1);
894     ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr);
895     hr = IEnumMoniker_QueryInterface(spEM1, &IID_IUnknown, (void*) &lpEM1);
896     /* Register a couple of Monikers and check is ok */
897     ok(hr==0, "IEnumMoniker_QueryInterface hr %08x %p\n", hr, lpEM1);
898     hr = MK_E_NOOBJECT;
899     
900     matchCnt = count_moniker_matches(pbc, spEM1);
901     trace("Number of matches is %i\n", matchCnt);
902
903     grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE;
904     hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk1, &pdwReg1);
905     ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n",
906         hr, pprot, grflags, lpEM1, pmk1, pdwReg1);
907
908     trace("IROT::Register\n");
909     grflags=0;
910     grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE;
911     hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk2, &pdwReg2);
912     ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n", hr,
913        pprot, grflags, lpEM1, pmk2, pdwReg2);
914
915     hr = IRunningObjectTable_EnumRunning(pprot, &spEM2);
916     ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr);
917
918     matchCnt = count_moniker_matches(pbc, spEM2);
919     ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
920
921     trace("IEnumMoniker::Clone\n");
922     IEnumMoniker_Clone(spEM2, &spEM3);
923
924     matchCnt = count_moniker_matches(pbc, spEM3);
925     ok(matchCnt==0, "Number of matches should be equal to 0 not %i\n", matchCnt);
926     trace("IEnumMoniker::Reset\n");
927     IEnumMoniker_Reset(spEM3);
928
929     matchCnt = count_moniker_matches(pbc, spEM3);
930     ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
931
932     IRunningObjectTable_Revoke(pprot,pdwReg1);
933     IRunningObjectTable_Revoke(pprot,pdwReg2);
934     IEnumMoniker_Release(spEM1);
935     IEnumMoniker_Release(spEM1);
936     IEnumMoniker_Release(spEM2);
937     IEnumMoniker_Release(spEM3);
938     IMoniker_Release(pmk1);
939     IMoniker_Release(pmk2);
940     IRunningObjectTable_Release(pprot);
941
942     IBindCtx_Release(pbc);
943 }
944
945 static const LARGE_INTEGER llZero;
946
947 static const BYTE expected_class_moniker_marshal_data[] =
948 {
949     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
950     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
951     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
952     0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
953     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
954     0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
955     0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
956     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
957     0x00,0x00,0x00,0x00,
958 };
959
960 static const BYTE expected_class_moniker_saved_data[] =
961 {
962      0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
963      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
964      0x00,0x00,0x00,0x00,
965 };
966
967 static const BYTE expected_class_moniker_comparison_data[] =
968 {
969      0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
970      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
971      0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
972      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
973 };
974
975 static const WCHAR expected_class_moniker_display_name[] =
976 {
977     'c','l','s','i','d',':','0','0','0','2','E','0','0','5','-','0','0','0',
978     '0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0',
979     '0','0','0','0','4','6',':',0
980 };
981
982 static const BYTE expected_item_moniker_comparison_data[] =
983 {
984      0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
985      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
986      0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00,
987      0x54,0x00,0x00,0x00,
988 };
989
990 static const BYTE expected_item_moniker_saved_data[] =
991 {
992      0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
993      0x00,0x00,0x54,0x65,0x73,0x74,0x00,
994 };
995
996 static const BYTE expected_item_moniker_marshal_data[] =
997 {
998      0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
999      0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1000      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1001      0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1002      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1003      0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
1004      0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
1005      0x00,0x00,0x54,0x65,0x73,0x74,0x00,
1006 };
1007
1008 static const BYTE expected_anti_moniker_marshal_data[] =
1009 {
1010     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1011     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1012     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1013     0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1014     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1015     0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
1016     0x01,0x00,0x00,0x00,
1017 };
1018
1019 static const BYTE expected_anti_moniker_saved_data[] =
1020 {
1021     0x01,0x00,0x00,0x00,
1022 };
1023
1024 static const BYTE expected_anti_moniker_comparison_data[] =
1025 {
1026     0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1027     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1028     0x01,0x00,0x00,0x00,
1029 };
1030
1031 static const BYTE expected_gc_moniker_marshal_data[] =
1032 {
1033     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1034     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1035     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1036     0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1037     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1038     0x00,0x00,0x00,0x00,0x2c,0x01,0x00,0x00,
1039     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1040     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1041     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1042     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1043     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1044     0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
1045     0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
1046     0x00,0x00,0x54,0x65,0x73,0x74,0x00,0x4d,
1047     0x45,0x4f,0x57,0x04,0x00,0x00,0x00,0x0f,
1048     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
1049     0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x04,
1050     0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
1051     0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,
1052     0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x02,
1053     0x00,0x00,0x00,0x23,0x00,0x05,0x00,0x00,
1054     0x00,0x57,0x69,0x6e,0x65,0x00,
1055 };
1056
1057 static const BYTE expected_gc_moniker_saved_data[] =
1058 {
1059     0x02,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
1060     0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
1061     0x00,0x00,0x00,0x46,0x02,0x00,0x00,0x00,
1062     0x21,0x00,0x05,0x00,0x00,0x00,0x54,0x65,
1063     0x73,0x74,0x00,0x04,0x03,0x00,0x00,0x00,
1064     0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,
1065     0x00,0x00,0x46,0x02,0x00,0x00,0x00,0x23,
1066     0x00,0x05,0x00,0x00,0x00,0x57,0x69,0x6e,
1067     0x65,0x00,
1068 };
1069
1070 static const BYTE expected_gc_moniker_comparison_data[] =
1071 {
1072     0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1073     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1074     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1075     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1076     0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00,
1077     0x54,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
1078     0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
1079     0x00,0x00,0x00,0x46,0x23,0x00,0x57,0x00,
1080     0x49,0x00,0x4e,0x00,0x45,0x00,0x00,0x00,
1081 };
1082
1083 static void test_moniker(
1084     const char *testname, IMoniker *moniker,
1085     const BYTE *expected_moniker_marshal_data, unsigned int sizeof_expected_moniker_marshal_data,
1086     const BYTE *expected_moniker_saved_data, unsigned int sizeof_expected_moniker_saved_data,
1087     const BYTE *expected_moniker_comparison_data, unsigned int sizeof_expected_moniker_comparison_data,
1088     LPCWSTR expected_display_name)
1089 {
1090     IStream * stream;
1091     IROTData * rotdata;
1092     HRESULT hr;
1093     HGLOBAL hglobal;
1094     LPBYTE moniker_data;
1095     DWORD moniker_size;
1096     DWORD i;
1097     BOOL same = TRUE;
1098     BYTE buffer[128];
1099     IMoniker * moniker_proxy;
1100     LPOLESTR display_name;
1101     IBindCtx *bindctx;
1102
1103     hr = IMoniker_IsDirty(moniker);
1104     ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr);
1105
1106     /* Display Name */
1107
1108     hr = CreateBindCtx(0, &bindctx);
1109     ok_ole_success(hr, CreateBindCtx);
1110
1111     hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
1112     ok_ole_success(hr, IMoniker_GetDisplayName);
1113     ok(!lstrcmpW(display_name, expected_display_name), "%s: display name wasn't what was expected\n", testname);
1114
1115     CoTaskMemFree(display_name);
1116     IBindCtx_Release(bindctx);
1117
1118     hr = IMoniker_IsDirty(moniker);
1119     ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr);
1120
1121     /* IROTData::GetComparisonData test */
1122
1123     hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
1124     ok_ole_success(hr, IMoniker_QueryInterface_IID_IROTData);
1125
1126     hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &moniker_size);
1127     ok_ole_success(hr, IROTData_GetComparisonData);
1128
1129     if (hr != S_OK) moniker_size = 0;
1130
1131     /* first check we have the right amount of data */
1132     ok(moniker_size == sizeof_expected_moniker_comparison_data,
1133         "%s: Size of comparison data differs (expected %d, actual %d)\n",
1134         testname, sizeof_expected_moniker_comparison_data, moniker_size);
1135
1136     /* then do a byte-by-byte comparison */
1137     for (i = 0; i < min(moniker_size, sizeof_expected_moniker_comparison_data); i++)
1138     {
1139         if (expected_moniker_comparison_data[i] != buffer[i])
1140         {
1141             same = FALSE;
1142             break;
1143         }
1144     }
1145
1146     ok(same, "%s: Comparison data differs\n", testname);
1147     if (!same)
1148     {
1149         for (i = 0; i < moniker_size; i++)
1150         {
1151             if (i % 8 == 0) printf("     ");
1152             printf("0x%02x,", buffer[i]);
1153             if (i % 8 == 7) printf("\n");
1154         }
1155         printf("\n");
1156     }
1157
1158     IROTData_Release(rotdata);
1159   
1160     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1161   
1162     /* Saving */
1163
1164     hr = IMoniker_Save(moniker, stream, TRUE);
1165     ok_ole_success(hr, IMoniker_Save);
1166
1167     hr = GetHGlobalFromStream(stream, &hglobal);
1168     ok_ole_success(hr, GetHGlobalFromStream);
1169
1170     moniker_size = GlobalSize(hglobal);
1171
1172     moniker_data = GlobalLock(hglobal);
1173
1174     /* first check we have the right amount of data */
1175     ok(moniker_size == sizeof_expected_moniker_saved_data,
1176         "%s: Size of saved data differs (expected %d, actual %d)\n",
1177         testname, sizeof_expected_moniker_saved_data, moniker_size);
1178
1179     /* then do a byte-by-byte comparison */
1180     for (i = 0; i < min(moniker_size, sizeof_expected_moniker_saved_data); i++)
1181     {
1182         if (expected_moniker_saved_data[i] != moniker_data[i])
1183         {
1184             same = FALSE;
1185             break;
1186         }
1187     }
1188
1189     ok(same, "%s: Saved data differs\n", testname);
1190     if (!same)
1191     {
1192         for (i = 0; i < moniker_size; i++)
1193         {
1194             if (i % 8 == 0) printf("     ");
1195             printf("0x%02x,", moniker_data[i]);
1196             if (i % 8 == 7) printf("\n");
1197         }
1198         printf("\n");
1199     }
1200
1201     GlobalUnlock(hglobal);
1202
1203     IStream_Release(stream);
1204
1205     /* Marshaling tests */
1206
1207     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1208     ok_ole_success(hr, CreateStreamOnHGlobal);
1209
1210     hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1211     ok_ole_success(hr, CoMarshalInterface);
1212
1213     hr = GetHGlobalFromStream(stream, &hglobal);
1214     ok_ole_success(hr, GetHGlobalFromStream);
1215
1216     moniker_size = GlobalSize(hglobal);
1217
1218     moniker_data = GlobalLock(hglobal);
1219
1220     /* first check we have the right amount of data */
1221     ok(moniker_size == sizeof_expected_moniker_marshal_data,
1222         "%s: Size of marshaled data differs (expected %d, actual %d)\n",
1223         testname, sizeof_expected_moniker_marshal_data, moniker_size);
1224
1225     /* then do a byte-by-byte comparison */
1226     if (expected_moniker_marshal_data)
1227     {
1228         for (i = 0; i < min(moniker_size, sizeof_expected_moniker_marshal_data); i++)
1229         {
1230             if (expected_moniker_marshal_data[i] != moniker_data[i])
1231             {
1232                 same = FALSE;
1233                 break;
1234             }
1235         }
1236     }
1237
1238     ok(same, "%s: Marshaled data differs\n", testname);
1239     if (!same)
1240     {
1241         for (i = 0; i < moniker_size; i++)
1242         {
1243             if (i % 8 == 0) printf("     ");
1244             printf("0x%02x,", moniker_data[i]);
1245             if (i % 8 == 7) printf("\n");
1246         }
1247         printf("\n");
1248     }
1249
1250     GlobalUnlock(hglobal);
1251
1252     IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
1253     hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker_proxy);
1254     ok_ole_success(hr, CoUnmarshalInterface);
1255
1256     IStream_Release(stream);
1257     IMoniker_Release(moniker_proxy);
1258 }
1259
1260 static void test_class_moniker(void)
1261 {
1262     HRESULT hr;
1263     IMoniker *moniker;
1264     DWORD moniker_type;
1265     DWORD hash;
1266     IBindCtx *bindctx;
1267     IMoniker *inverse;
1268     IUnknown *unknown;
1269     FILETIME filetime;
1270
1271     hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker);
1272     ok_ole_success(hr, CreateClassMoniker);
1273     if (!moniker) return;
1274
1275     test_moniker("class moniker", moniker, 
1276         expected_class_moniker_marshal_data, sizeof(expected_class_moniker_marshal_data),
1277         expected_class_moniker_saved_data, sizeof(expected_class_moniker_saved_data),
1278         expected_class_moniker_comparison_data, sizeof(expected_class_moniker_comparison_data),
1279         expected_class_moniker_display_name);
1280
1281     /* Hashing */
1282
1283     hr = IMoniker_Hash(moniker, &hash);
1284     ok_ole_success(hr, IMoniker_Hash);
1285
1286     ok(hash == CLSID_StdComponentCategoriesMgr.Data1,
1287         "Hash value != Data1 field of clsid, instead was 0x%08x\n",
1288         hash);
1289
1290     /* IsSystemMoniker test */
1291
1292     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1293     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1294
1295     ok(moniker_type == MKSYS_CLASSMONIKER,
1296         "dwMkSys != MKSYS_CLASSMONIKER, instead was 0x%08x\n",
1297         moniker_type);
1298
1299     hr = CreateBindCtx(0, &bindctx);
1300     ok_ole_success(hr, CreateBindCtx);
1301
1302     /* IsRunning test */
1303     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1304     ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08x\n", hr);
1305
1306     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1307     ok(hr == MK_E_UNAVAILABLE, "IMoniker_GetTimeOfLastChange should return MK_E_UNAVAILABLE, not 0x%08x\n", hr);
1308
1309     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1310     ok_ole_success(hr, IMoniker_BindToStorage);
1311     IUnknown_Release(unknown);
1312
1313     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1314     ok_ole_success(hr, IMoniker_BindToStorage);
1315     IUnknown_Release(unknown);
1316
1317     IBindCtx_Release(bindctx);
1318
1319     hr = IMoniker_Inverse(moniker, &inverse);
1320     ok_ole_success(hr, IMoniker_Inverse);
1321     IMoniker_Release(inverse);
1322
1323     IMoniker_Release(moniker);
1324 }
1325
1326 static void test_file_moniker(WCHAR* path)
1327 {
1328     IStream *stream;
1329     IMoniker *moniker1 = NULL, *moniker2 = NULL;
1330     HRESULT hr;
1331
1332     hr = CreateFileMoniker(path, &moniker1);
1333     ok_ole_success(hr, CreateFileMoniker); 
1334
1335     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1336
1337     /* Marshal */
1338     hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker1, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1339     ok_ole_success(hr, CoMarshalInterface);
1340     
1341     /* Rewind */
1342     hr = IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
1343     ok_ole_success(hr, IStream_Seek);
1344
1345     /* Unmarshal */
1346     hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void**)&moniker2);
1347     ok_ole_success(hr, CoUnmarshalInterface);
1348
1349     hr = IMoniker_IsEqual(moniker1, moniker2);
1350     ok_ole_success(hr, IsEqual);
1351
1352     IStream_Release(stream);
1353     if (moniker1) 
1354         IMoniker_Release(moniker1);
1355     if (moniker2) 
1356         IMoniker_Release(moniker2);
1357 }
1358
1359 static void test_file_monikers(void)
1360 {
1361     static WCHAR wszFile[][30] = {
1362         {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0},
1363         {'\\', '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},
1364         /* These map to themselves in Windows-1252 & 932 (Shift-JIS) */
1365         {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0},
1366         /* U+2020 = DAGGER     = 0x86 (1252) = 0x813f (932)
1367          * U+20AC = EURO SIGN  = 0x80 (1252) =  undef (932)
1368          * U+0100 .. = Latin extended-A
1369          */ 
1370         {0x20ac, 0x2020, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c,  0},
1371         };
1372
1373     int i; 
1374
1375     trace("ACP is %u\n", GetACP());
1376
1377     for (i = 0; i < COUNTOF(wszFile); ++i)
1378     {
1379         int j ;
1380         for (j = lstrlenW(wszFile[i]); j > 0; --j)
1381         {
1382             wszFile[i][j] = 0;
1383             test_file_moniker(wszFile[i]);
1384         }
1385     }
1386 }
1387
1388 static void test_item_moniker(void)
1389 {
1390     HRESULT hr;
1391     IMoniker *moniker;
1392     DWORD moniker_type;
1393     DWORD hash;
1394     IBindCtx *bindctx;
1395     IMoniker *inverse;
1396     IUnknown *unknown;
1397     static const WCHAR wszDelimeter[] = {'!',0};
1398     static const WCHAR wszObjectName[] = {'T','e','s','t',0};
1399     static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 };
1400
1401     hr = CreateItemMoniker(wszDelimeter, wszObjectName, &moniker);
1402     ok_ole_success(hr, CreateItemMoniker);
1403
1404     test_moniker("item moniker", moniker, 
1405         expected_item_moniker_marshal_data, sizeof(expected_item_moniker_marshal_data),
1406         expected_item_moniker_saved_data, sizeof(expected_item_moniker_saved_data),
1407         expected_item_moniker_comparison_data, sizeof(expected_item_moniker_comparison_data),
1408         expected_display_name);
1409
1410     /* Hashing */
1411
1412     hr = IMoniker_Hash(moniker, &hash);
1413     ok_ole_success(hr, IMoniker_Hash);
1414
1415     ok(hash == 0x73c,
1416         "Hash value != 0x73c, instead was 0x%08x\n",
1417         hash);
1418
1419     /* IsSystemMoniker test */
1420
1421     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1422     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1423
1424     ok(moniker_type == MKSYS_ITEMMONIKER,
1425         "dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n",
1426         moniker_type);
1427
1428     hr = CreateBindCtx(0, &bindctx);
1429     ok_ole_success(hr, CreateBindCtx);
1430
1431     /* IsRunning test */
1432     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1433     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1434
1435     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1436     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
1437
1438     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1439     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
1440
1441     IBindCtx_Release(bindctx);
1442
1443     hr = IMoniker_Inverse(moniker, &inverse);
1444     ok_ole_success(hr, IMoniker_Inverse);
1445     IMoniker_Release(inverse);
1446
1447     IMoniker_Release(moniker);
1448 }
1449
1450 static void test_anti_moniker(void)
1451 {
1452     HRESULT hr;
1453     IMoniker *moniker;
1454     DWORD moniker_type;
1455     DWORD hash;
1456     IBindCtx *bindctx;
1457     FILETIME filetime;
1458     IMoniker *inverse;
1459     IUnknown *unknown;
1460     static const WCHAR expected_display_name[] = { '\\','.','.',0 };
1461
1462     hr = CreateAntiMoniker(&moniker);
1463     ok_ole_success(hr, CreateAntiMoniker);
1464     if (!moniker) return;
1465
1466     test_moniker("anti moniker", moniker, 
1467         expected_anti_moniker_marshal_data, sizeof(expected_anti_moniker_marshal_data),
1468         expected_anti_moniker_saved_data, sizeof(expected_anti_moniker_saved_data),
1469         expected_anti_moniker_comparison_data, sizeof(expected_anti_moniker_comparison_data),
1470         expected_display_name);
1471
1472     /* Hashing */
1473     hr = IMoniker_Hash(moniker, &hash);
1474     ok_ole_success(hr, IMoniker_Hash);
1475     ok(hash == 0x80000001,
1476         "Hash value != 0x80000001, instead was 0x%08x\n",
1477         hash);
1478
1479     /* IsSystemMoniker test */
1480     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1481     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1482     ok(moniker_type == MKSYS_ANTIMONIKER,
1483         "dwMkSys != MKSYS_ANTIMONIKER, instead was 0x%08x\n",
1484         moniker_type);
1485
1486     hr = IMoniker_Inverse(moniker, &inverse);
1487     ok(hr == MK_E_NOINVERSE, "IMoniker_Inverse should have returned MK_E_NOINVERSE instead of 0x%08x\n", hr);
1488     ok(inverse == NULL, "inverse should have been set to NULL instead of %p\n", inverse);
1489
1490     hr = CreateBindCtx(0, &bindctx);
1491     ok_ole_success(hr, CreateBindCtx);
1492
1493     /* IsRunning test */
1494     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1495     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1496
1497     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1498     ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr);
1499
1500     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1501     ok(hr == E_NOTIMPL, "IMoniker_BindToObject should return E_NOTIMPL, not 0x%08x\n", hr);
1502
1503     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1504     ok(hr == E_NOTIMPL, "IMoniker_BindToStorage should return E_NOTIMPL, not 0x%08x\n", hr);
1505
1506     IBindCtx_Release(bindctx);
1507
1508     IMoniker_Release(moniker);
1509 }
1510
1511 static void test_generic_composite_moniker(void)
1512 {
1513     HRESULT hr;
1514     IMoniker *moniker;
1515     IMoniker *moniker1;
1516     IMoniker *moniker2;
1517     DWORD moniker_type;
1518     DWORD hash;
1519     IBindCtx *bindctx;
1520     FILETIME filetime;
1521     IMoniker *inverse;
1522     IUnknown *unknown;
1523     static const WCHAR wszDelimeter1[] = {'!',0};
1524     static const WCHAR wszObjectName1[] = {'T','e','s','t',0};
1525     static const WCHAR wszDelimeter2[] = {'#',0};
1526     static const WCHAR wszObjectName2[] = {'W','i','n','e',0};
1527     static const WCHAR expected_display_name[] = { '!','T','e','s','t','#','W','i','n','e',0 };
1528
1529     hr = CreateItemMoniker(wszDelimeter1, wszObjectName1, &moniker1);
1530     ok_ole_success(hr, CreateItemMoniker);
1531     hr = CreateItemMoniker(wszDelimeter2, wszObjectName2, &moniker2);
1532     ok_ole_success(hr, CreateItemMoniker);
1533     hr = CreateGenericComposite(moniker1, moniker2, &moniker);
1534     ok_ole_success(hr, CreateGenericComposite);
1535
1536     test_moniker("generic composite moniker", moniker, 
1537         expected_gc_moniker_marshal_data, sizeof(expected_gc_moniker_marshal_data),
1538         expected_gc_moniker_saved_data, sizeof(expected_gc_moniker_saved_data),
1539         expected_gc_moniker_comparison_data, sizeof(expected_gc_moniker_comparison_data),
1540         expected_display_name);
1541
1542     /* Hashing */
1543
1544     hr = IMoniker_Hash(moniker, &hash);
1545     ok_ole_success(hr, IMoniker_Hash);
1546
1547     ok(hash == 0xd87,
1548         "Hash value != 0xd87, instead was 0x%08x\n",
1549         hash);
1550
1551     /* IsSystemMoniker test */
1552
1553     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1554     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1555
1556     ok(moniker_type == MKSYS_GENERICCOMPOSITE,
1557         "dwMkSys != MKSYS_GENERICCOMPOSITE, instead was 0x%08x\n",
1558         moniker_type);
1559
1560     hr = CreateBindCtx(0, &bindctx);
1561     ok_ole_success(hr, CreateBindCtx);
1562
1563     /* IsRunning test */
1564     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1565     todo_wine
1566     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1567
1568     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1569     ok(hr == MK_E_NOTBINDABLE, "IMoniker_GetTimeOfLastChange should return MK_E_NOTBINDABLE, not 0x%08x\n", hr);
1570
1571     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1572     todo_wine
1573     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
1574
1575     todo_wine
1576     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1577     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
1578
1579     IBindCtx_Release(bindctx);
1580
1581     hr = IMoniker_Inverse(moniker, &inverse);
1582     ok_ole_success(hr, IMoniker_Inverse);
1583     IMoniker_Release(inverse);
1584
1585     IMoniker_Release(moniker);
1586 }
1587
1588 static void test_bind_context(void)
1589 {
1590     HRESULT hr;
1591     IBindCtx *pBindCtx;
1592     IEnumString *pEnumString;
1593     BIND_OPTS2 bind_opts;
1594     HeapUnknown *unknown;
1595     HeapUnknown *unknown2;
1596     IUnknown *param_obj;
1597     ULONG refs;
1598     static const WCHAR wszParamName[] = {'G','e','m','m','a',0};
1599     static const WCHAR wszNonExistant[] = {'N','o','n','E','x','i','s','t','a','n','t',0};
1600
1601     hr = CreateBindCtx(0, NULL);
1602     ok(hr == E_INVALIDARG, "CreateBindCtx with NULL ppbc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1603
1604     hr = CreateBindCtx(0xdeadbeef, &pBindCtx);
1605     ok(hr == E_INVALIDARG, "CreateBindCtx with reserved value non-zero should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1606
1607     hr = CreateBindCtx(0, &pBindCtx);
1608     ok_ole_success(hr, "CreateBindCtx");
1609
1610     bind_opts.cbStruct = -1;
1611     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1612     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1613     ok(bind_opts.cbStruct == sizeof(bind_opts), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1614
1615     bind_opts.cbStruct = sizeof(BIND_OPTS);
1616     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1617     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1618     ok(bind_opts.cbStruct == sizeof(BIND_OPTS), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1619
1620     bind_opts.cbStruct = sizeof(bind_opts);
1621     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1622     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1623     ok(bind_opts.cbStruct == sizeof(bind_opts), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1624     ok(bind_opts.grfFlags == 0, "bind_opts.grfFlags was 0x%x instead of 0\n", bind_opts.grfFlags);
1625     ok(bind_opts.grfMode == STGM_READWRITE, "bind_opts.grfMode was 0x%x instead of STGM_READWRITE\n", bind_opts.grfMode);
1626     ok(bind_opts.dwTickCountDeadline == 0, "bind_opts.dwTickCountDeadline was %d instead of 0\n", bind_opts.dwTickCountDeadline);
1627     ok(bind_opts.dwTrackFlags == 0, "bind_opts.dwTrackFlags was 0x%x instead of 0\n", bind_opts.dwTrackFlags);
1628     ok(bind_opts.dwClassContext == (CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER),
1629         "bind_opts.dwClassContext should have been 0x15 instead of 0x%x\n", bind_opts.dwClassContext);
1630     ok(bind_opts.locale == GetThreadLocale(), "bind_opts.locale should have been 0x%x instead of 0x%x\n", GetThreadLocale(), bind_opts.locale);
1631     ok(bind_opts.pServerInfo == NULL, "bind_opts.pServerInfo should have been NULL instead of %p\n", bind_opts.pServerInfo);
1632
1633     bind_opts.cbStruct = -1;
1634     hr = IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1635     ok(hr == E_INVALIDARG, "IBindCtx_SetBindOptions with bad cbStruct should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1636
1637     hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, NULL);
1638     ok(hr == E_INVALIDARG, "IBindCtx_RegisterObjectParam should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1639
1640     unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
1641     unknown->lpVtbl = &HeapUnknown_Vtbl;
1642     unknown->refs = 1;
1643     hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, (IUnknown *)&unknown->lpVtbl);
1644     ok_ole_success(hr, "IBindCtx_RegisterObjectParam");
1645
1646     hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszParamName, &param_obj);
1647     ok_ole_success(hr, "IBindCtx_GetObjectParam");
1648     IUnknown_Release(param_obj);
1649
1650     hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszNonExistant, &param_obj);
1651     ok(hr == E_FAIL, "IBindCtx_GetObjectParam with non-existing key should have failed with E_FAIL instead of 0x%08x\n", hr);
1652     ok(param_obj == NULL, "IBindCtx_GetObjectParam with non-existing key should have set output parameter to NULL instead of %p\n", param_obj);
1653
1654     hr = IBindCtx_RevokeObjectParam(pBindCtx, (WCHAR *)wszNonExistant);
1655     ok(hr == E_FAIL, "IBindCtx_RevokeObjectParam with non-existing key should have failed with E_FAIL instead of 0x%08x\n", hr);
1656
1657     hr = IBindCtx_EnumObjectParam(pBindCtx, &pEnumString);
1658     ok(hr == E_NOTIMPL, "IBindCtx_EnumObjectParam should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1659     ok(!pEnumString, "pEnumString should be NULL\n");
1660
1661     hr = IBindCtx_RegisterObjectBound(pBindCtx, NULL);
1662     ok_ole_success(hr, "IBindCtx_RegisterObjectBound(NULL)");
1663
1664     hr = IBindCtx_RevokeObjectBound(pBindCtx, NULL);
1665     ok(hr == E_INVALIDARG, "IBindCtx_RevokeObjectBound(NULL) should have return E_INVALIDARG instead of 0x%08x\n", hr);
1666
1667     unknown2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
1668     unknown2->lpVtbl = &HeapUnknown_Vtbl;
1669     unknown2->refs = 1;
1670     hr = IBindCtx_RegisterObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1671     ok_ole_success(hr, "IBindCtx_RegisterObjectBound");
1672
1673     hr = IBindCtx_RevokeObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1674     ok_ole_success(hr, "IBindCtx_RevokeObjectBound");
1675
1676     hr = IBindCtx_RevokeObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1677     ok(hr == MK_E_NOTBOUND, "IBindCtx_RevokeObjectBound with not bound object should have returned MK_E_NOTBOUND instead of 0x%08x\n", hr);
1678
1679     IBindCtx_Release(pBindCtx);
1680
1681     refs = IUnknown_Release((IUnknown *)&unknown->lpVtbl);
1682     ok(!refs, "object param should have been destroyed, instead of having %d refs\n", refs);
1683
1684     refs = IUnknown_Release((IUnknown *)&unknown2->lpVtbl);
1685     ok(!refs, "bound object should have been destroyed, instead of having %d refs\n", refs);
1686 }
1687
1688 START_TEST(moniker)
1689 {
1690     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1691
1692     test_ROT();
1693     test_MkParseDisplayName();
1694     test_class_moniker();
1695     test_file_monikers();
1696     test_item_moniker();
1697     test_anti_moniker();
1698     test_generic_composite_moniker();
1699
1700     /* FIXME: test moniker creation funcs and parsing other moniker formats */
1701
1702     test_bind_context();
1703
1704     CoUninitialize();
1705 }