wintrust: Add a helper function to initialize chain creation parameters.
[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 wszNonExistentProgId[] = {'N','o','n','E','x','i','s','t','e','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, wszNonExistentProgId, &eaten, &pmk);
780     ok(hr == MK_E_SYNTAX || hr == MK_E_CANTOPENFILE /* Win9x */,
781         "MkParseDisplayName should have failed with MK_E_SYNTAX or MK_E_CANTOPENFILE instead of 0x%08x\n", hr);
782
783     /* no special handling of "clsid:" without the string form of the clsid
784      * following */
785     hr = MkParseDisplayName(pbc, wszDisplayNameClsid, &eaten, &pmk);
786     ok(hr == MK_E_SYNTAX || hr == MK_E_CANTOPENFILE /* Win9x */,
787         "MkParseDisplayName should have failed with MK_E_SYNTAX or MK_E_CANTOPENFILE instead of 0x%08x\n", hr);
788
789     /* shows clsid has higher precedence than a running object */
790     hr = CreateFileMoniker(wszDisplayName, &pmk);
791     ok_ole_success(hr, CreateFileMoniker);
792     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
793     ok_ole_success(hr, IBindCtx_GetRunningObjectTable);
794     hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&Test_ClassFactory, pmk, &pdwReg1);
795     ok_ole_success(hr, IRunningObjectTable_Register);
796     IMoniker_Release(pmk);
797     pmk = NULL;
798     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
799     ok_ole_success(hr, MkParseDisplayName);
800     if (pmk)
801     {
802         IMoniker_IsSystemMoniker(pmk, &moniker_type);
803         ok(moniker_type == MKSYS_CLASSMONIKER, "moniker_type was %d instead of MKSYS_CLASSMONIKER\n", moniker_type);
804         IMoniker_Release(pmk);
805     }
806     hr = IRunningObjectTable_Revoke(pprot, pdwReg1);
807     ok_ole_success(hr, IRunningObjectTable_Revoke);
808     IRunningObjectTable_Release(pprot);
809
810     hr = CreateFileMoniker(wszDisplayNameRunning, &pmk);
811     ok_ole_success(hr, CreateFileMoniker);
812     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
813     ok_ole_success(hr, IBindCtx_GetRunningObjectTable);
814     hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&Test_ClassFactory, pmk, &pdwReg1);
815     ok_ole_success(hr, IRunningObjectTable_Register);
816     IMoniker_Release(pmk);
817     pmk = NULL;
818     hr = MkParseDisplayName(pbc, wszDisplayNameRunning, &eaten, &pmk);
819     ok_ole_success(hr, MkParseDisplayName);
820     if (pmk)
821     {
822         IMoniker_IsSystemMoniker(pmk, &moniker_type);
823         ok(moniker_type == MKSYS_FILEMONIKER, "moniker_type was %d instead of MKSYS_FILEMONIKER\n", moniker_type);
824         IMoniker_Release(pmk);
825     }
826     hr = IRunningObjectTable_Revoke(pprot, pdwReg1);
827     ok_ole_success(hr, IRunningObjectTable_Revoke);
828     IRunningObjectTable_Release(pprot);
829
830     hr = CoRegisterClassObject(&CLSID_StdFont, (IUnknown *)&ParseDisplayName, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &pdwReg1);
831     ok_ole_success(hr, CoRegisterClassObject);
832
833     expected_display_name = wszDisplayNameProgId1;
834     hr = MkParseDisplayName(pbc, wszDisplayNameProgId1, &eaten, &pmk);
835     ok_ole_success(hr, MkParseDisplayName);
836     if (pmk)
837     {
838         IMoniker_IsSystemMoniker(pmk, &moniker_type);
839         ok(moniker_type == MKSYS_ANTIMONIKER, "moniker_type was %d instead of MKSYS_ANTIMONIKER\n", moniker_type);
840         IMoniker_Release(pmk);
841     }
842
843     expected_display_name = wszDisplayNameProgId2;
844     hr = MkParseDisplayName(pbc, wszDisplayNameProgId2, &eaten, &pmk);
845     ok_ole_success(hr, MkParseDisplayName);
846     if (pmk)
847     {
848         IMoniker_IsSystemMoniker(pmk, &moniker_type);
849         ok(moniker_type == MKSYS_ANTIMONIKER, "moniker_type was %d instead of MKSYS_ANTIMONIKER\n", moniker_type);
850         IMoniker_Release(pmk);
851     }
852
853     hr = MkParseDisplayName(pbc, wszDisplayNameProgIdFail, &eaten, &pmk);
854     ok(hr == MK_E_SYNTAX || hr == MK_E_CANTOPENFILE /* Win9x */,
855         "MkParseDisplayName with ProgId without marker should fail with MK_E_SYNTAX or MK_E_CANTOPENFILE instead of 0x%08x\n", hr);
856
857     hr = CoRevokeClassObject(pdwReg1);
858     ok_ole_success(hr, CoRevokeClassObject);
859
860     GetSystemDirectoryA(szDisplayNameFile, sizeof(szDisplayNameFile));
861     strcat(szDisplayNameFile, "\\kernel32.dll");
862     MultiByteToWideChar(CP_ACP, 0, szDisplayNameFile, -1, wszDisplayNameFile, sizeof(wszDisplayNameFile)/sizeof(wszDisplayNameFile[0]));
863     hr = MkParseDisplayName(pbc, wszDisplayNameFile, &eaten, &pmk);
864     ok_ole_success(hr, MkParseDisplayName);
865     if (pmk)
866     {
867         IMoniker_IsSystemMoniker(pmk, &moniker_type);
868         ok(moniker_type == MKSYS_FILEMONIKER, "moniker_type was %d instead of MKSYS_FILEMONIKER\n", moniker_type);
869         IMoniker_Release(pmk);
870     }
871
872     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
873     ok_ole_success(hr, MkParseDisplayName);
874
875     if (pmk)
876     {
877         hr = IMoniker_BindToObject(pmk, pbc, NULL, &IID_IUnknown, (LPVOID*)&object);
878         ok_ole_success(hr, IMoniker_BindToObject);
879
880         IUnknown_Release(object);
881     }
882     IBindCtx_Release(pbc);
883
884     /* Test the EnumMoniker interface */
885     hr = CreateBindCtx(0, &pbc);
886     ok_ole_success(hr, CreateBindCtx);
887
888     hr = CreateFileMoniker(wszFileName1, &pmk1);
889     ok(hr==0, "CreateFileMoniker for file hr=%08x\n", hr);
890     hr = CreateFileMoniker(wszFileName2, &pmk2);
891     ok(hr==0, "CreateFileMoniker for file hr=%08x\n", hr);
892     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
893     ok(hr==0, "IBindCtx_GetRunningObjectTable hr=%08x\n", hr);
894
895     /* Check EnumMoniker before registering */
896     hr = IRunningObjectTable_EnumRunning(pprot, &spEM1);
897     ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr);
898     hr = IEnumMoniker_QueryInterface(spEM1, &IID_IUnknown, (void*) &lpEM1);
899     /* Register a couple of Monikers and check is ok */
900     ok(hr==0, "IEnumMoniker_QueryInterface hr %08x %p\n", hr, lpEM1);
901     hr = MK_E_NOOBJECT;
902     
903     matchCnt = count_moniker_matches(pbc, spEM1);
904     trace("Number of matches is %i\n", matchCnt);
905
906     grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE;
907     hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk1, &pdwReg1);
908     ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n",
909         hr, pprot, grflags, lpEM1, pmk1, pdwReg1);
910
911     trace("IROT::Register\n");
912     grflags=0;
913     grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE;
914     hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk2, &pdwReg2);
915     ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n", hr,
916        pprot, grflags, lpEM1, pmk2, pdwReg2);
917
918     hr = IRunningObjectTable_EnumRunning(pprot, &spEM2);
919     ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr);
920
921     matchCnt = count_moniker_matches(pbc, spEM2);
922     ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
923
924     trace("IEnumMoniker::Clone\n");
925     IEnumMoniker_Clone(spEM2, &spEM3);
926
927     matchCnt = count_moniker_matches(pbc, spEM3);
928     ok(matchCnt==0, "Number of matches should be equal to 0 not %i\n", matchCnt);
929     trace("IEnumMoniker::Reset\n");
930     IEnumMoniker_Reset(spEM3);
931
932     matchCnt = count_moniker_matches(pbc, spEM3);
933     ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
934
935     IRunningObjectTable_Revoke(pprot,pdwReg1);
936     IRunningObjectTable_Revoke(pprot,pdwReg2);
937     IEnumMoniker_Release(spEM1);
938     IEnumMoniker_Release(spEM1);
939     IEnumMoniker_Release(spEM2);
940     IEnumMoniker_Release(spEM3);
941     IMoniker_Release(pmk1);
942     IMoniker_Release(pmk2);
943     IRunningObjectTable_Release(pprot);
944
945     IBindCtx_Release(pbc);
946 }
947
948 static const LARGE_INTEGER llZero;
949
950 static const BYTE expected_class_moniker_marshal_data[] =
951 {
952     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
953     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
954     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
955     0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
956     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
957     0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
958     0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
959     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
960     0x00,0x00,0x00,0x00,
961 };
962
963 static const BYTE expected_class_moniker_saved_data[] =
964 {
965      0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
966      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
967      0x00,0x00,0x00,0x00,
968 };
969
970 static const BYTE expected_class_moniker_comparison_data[] =
971 {
972      0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
973      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
974      0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
975      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
976 };
977
978 static const WCHAR expected_class_moniker_display_name[] =
979 {
980     'c','l','s','i','d',':','0','0','0','2','E','0','0','5','-','0','0','0',
981     '0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0',
982     '0','0','0','0','4','6',':',0
983 };
984
985 static const BYTE expected_item_moniker_comparison_data[] =
986 {
987      0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
988      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
989      0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00,
990      0x54,0x00,0x00,0x00,
991 };
992
993 static const BYTE expected_item_moniker_saved_data[] =
994 {
995      0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
996      0x00,0x00,0x54,0x65,0x73,0x74,0x00,
997 };
998
999 static const BYTE expected_item_moniker_marshal_data[] =
1000 {
1001      0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1002      0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1003      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1004      0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1005      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1006      0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
1007      0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
1008      0x00,0x00,0x54,0x65,0x73,0x74,0x00,
1009 };
1010
1011 static const BYTE expected_anti_moniker_marshal_data[] =
1012 {
1013     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1014     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1015     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1016     0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1017     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1018     0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
1019     0x01,0x00,0x00,0x00,
1020 };
1021
1022 static const BYTE expected_anti_moniker_saved_data[] =
1023 {
1024     0x01,0x00,0x00,0x00,
1025 };
1026
1027 static const BYTE expected_anti_moniker_comparison_data[] =
1028 {
1029     0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1030     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1031     0x01,0x00,0x00,0x00,
1032 };
1033
1034 static const BYTE expected_gc_moniker_marshal_data[] =
1035 {
1036     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1037     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1038     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1039     0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1040     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1041     0x00,0x00,0x00,0x00,0x2c,0x01,0x00,0x00,
1042     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1043     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1044     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1045     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1046     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1047     0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
1048     0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
1049     0x00,0x00,0x54,0x65,0x73,0x74,0x00,0x4d,
1050     0x45,0x4f,0x57,0x04,0x00,0x00,0x00,0x0f,
1051     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
1052     0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x04,
1053     0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
1054     0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,
1055     0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x02,
1056     0x00,0x00,0x00,0x23,0x00,0x05,0x00,0x00,
1057     0x00,0x57,0x69,0x6e,0x65,0x00,
1058 };
1059
1060 static const BYTE expected_gc_moniker_saved_data[] =
1061 {
1062     0x02,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
1063     0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
1064     0x00,0x00,0x00,0x46,0x02,0x00,0x00,0x00,
1065     0x21,0x00,0x05,0x00,0x00,0x00,0x54,0x65,
1066     0x73,0x74,0x00,0x04,0x03,0x00,0x00,0x00,
1067     0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,
1068     0x00,0x00,0x46,0x02,0x00,0x00,0x00,0x23,
1069     0x00,0x05,0x00,0x00,0x00,0x57,0x69,0x6e,
1070     0x65,0x00,
1071 };
1072
1073 static const BYTE expected_gc_moniker_comparison_data[] =
1074 {
1075     0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1076     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1077     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1078     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1079     0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00,
1080     0x54,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
1081     0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
1082     0x00,0x00,0x00,0x46,0x23,0x00,0x57,0x00,
1083     0x49,0x00,0x4e,0x00,0x45,0x00,0x00,0x00,
1084 };
1085
1086 static void test_moniker(
1087     const char *testname, IMoniker *moniker,
1088     const BYTE *expected_moniker_marshal_data, unsigned int sizeof_expected_moniker_marshal_data,
1089     const BYTE *expected_moniker_saved_data, unsigned int sizeof_expected_moniker_saved_data,
1090     const BYTE *expected_moniker_comparison_data, unsigned int sizeof_expected_moniker_comparison_data,
1091     LPCWSTR expected_display_name)
1092 {
1093     IStream * stream;
1094     IROTData * rotdata;
1095     HRESULT hr;
1096     HGLOBAL hglobal;
1097     LPBYTE moniker_data;
1098     DWORD moniker_size;
1099     DWORD i;
1100     BOOL same = TRUE;
1101     BYTE buffer[128];
1102     IMoniker * moniker_proxy;
1103     LPOLESTR display_name;
1104     IBindCtx *bindctx;
1105
1106     hr = IMoniker_IsDirty(moniker);
1107     ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr);
1108
1109     /* Display Name */
1110
1111     hr = CreateBindCtx(0, &bindctx);
1112     ok_ole_success(hr, CreateBindCtx);
1113
1114     hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
1115     ok_ole_success(hr, IMoniker_GetDisplayName);
1116     ok(!lstrcmpW(display_name, expected_display_name), "%s: display name wasn't what was expected\n", testname);
1117
1118     CoTaskMemFree(display_name);
1119     IBindCtx_Release(bindctx);
1120
1121     hr = IMoniker_IsDirty(moniker);
1122     ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr);
1123
1124     /* IROTData::GetComparisonData test */
1125
1126     hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
1127     ok_ole_success(hr, IMoniker_QueryInterface_IID_IROTData);
1128
1129     hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &moniker_size);
1130     ok_ole_success(hr, IROTData_GetComparisonData);
1131
1132     if (hr != S_OK) moniker_size = 0;
1133
1134     /* first check we have the right amount of data */
1135     ok(moniker_size == sizeof_expected_moniker_comparison_data,
1136         "%s: Size of comparison data differs (expected %d, actual %d)\n",
1137         testname, sizeof_expected_moniker_comparison_data, moniker_size);
1138
1139     /* then do a byte-by-byte comparison */
1140     for (i = 0; i < min(moniker_size, sizeof_expected_moniker_comparison_data); i++)
1141     {
1142         if (expected_moniker_comparison_data[i] != buffer[i])
1143         {
1144             same = FALSE;
1145             break;
1146         }
1147     }
1148
1149     ok(same, "%s: Comparison data differs\n", testname);
1150     if (!same)
1151     {
1152         for (i = 0; i < moniker_size; i++)
1153         {
1154             if (i % 8 == 0) printf("     ");
1155             printf("0x%02x,", buffer[i]);
1156             if (i % 8 == 7) printf("\n");
1157         }
1158         printf("\n");
1159     }
1160
1161     IROTData_Release(rotdata);
1162   
1163     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1164   
1165     /* Saving */
1166
1167     hr = IMoniker_Save(moniker, stream, TRUE);
1168     ok_ole_success(hr, IMoniker_Save);
1169
1170     hr = GetHGlobalFromStream(stream, &hglobal);
1171     ok_ole_success(hr, GetHGlobalFromStream);
1172
1173     moniker_size = GlobalSize(hglobal);
1174
1175     moniker_data = GlobalLock(hglobal);
1176
1177     /* first check we have the right amount of data */
1178     ok(moniker_size == sizeof_expected_moniker_saved_data,
1179         "%s: Size of saved data differs (expected %d, actual %d)\n",
1180         testname, sizeof_expected_moniker_saved_data, moniker_size);
1181
1182     /* then do a byte-by-byte comparison */
1183     for (i = 0; i < min(moniker_size, sizeof_expected_moniker_saved_data); i++)
1184     {
1185         if (expected_moniker_saved_data[i] != moniker_data[i])
1186         {
1187             same = FALSE;
1188             break;
1189         }
1190     }
1191
1192     ok(same, "%s: Saved data differs\n", testname);
1193     if (!same)
1194     {
1195         for (i = 0; i < moniker_size; i++)
1196         {
1197             if (i % 8 == 0) printf("     ");
1198             printf("0x%02x,", moniker_data[i]);
1199             if (i % 8 == 7) printf("\n");
1200         }
1201         printf("\n");
1202     }
1203
1204     GlobalUnlock(hglobal);
1205
1206     IStream_Release(stream);
1207
1208     /* Marshaling tests */
1209
1210     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1211     ok_ole_success(hr, CreateStreamOnHGlobal);
1212
1213     hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1214     ok_ole_success(hr, CoMarshalInterface);
1215
1216     hr = GetHGlobalFromStream(stream, &hglobal);
1217     ok_ole_success(hr, GetHGlobalFromStream);
1218
1219     moniker_size = GlobalSize(hglobal);
1220
1221     moniker_data = GlobalLock(hglobal);
1222
1223     /* first check we have the right amount of data */
1224     ok(moniker_size == sizeof_expected_moniker_marshal_data,
1225         "%s: Size of marshaled data differs (expected %d, actual %d)\n",
1226         testname, sizeof_expected_moniker_marshal_data, moniker_size);
1227
1228     /* then do a byte-by-byte comparison */
1229     if (expected_moniker_marshal_data)
1230     {
1231         for (i = 0; i < min(moniker_size, sizeof_expected_moniker_marshal_data); i++)
1232         {
1233             if (expected_moniker_marshal_data[i] != moniker_data[i])
1234             {
1235                 same = FALSE;
1236                 break;
1237             }
1238         }
1239     }
1240
1241     ok(same, "%s: Marshaled data differs\n", testname);
1242     if (!same)
1243     {
1244         for (i = 0; i < moniker_size; i++)
1245         {
1246             if (i % 8 == 0) printf("     ");
1247             printf("0x%02x,", moniker_data[i]);
1248             if (i % 8 == 7) printf("\n");
1249         }
1250         printf("\n");
1251     }
1252
1253     GlobalUnlock(hglobal);
1254
1255     IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
1256     hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker_proxy);
1257     ok_ole_success(hr, CoUnmarshalInterface);
1258
1259     IStream_Release(stream);
1260     IMoniker_Release(moniker_proxy);
1261 }
1262
1263 static void test_class_moniker(void)
1264 {
1265     HRESULT hr;
1266     IMoniker *moniker;
1267     DWORD moniker_type;
1268     DWORD hash;
1269     IBindCtx *bindctx;
1270     IMoniker *inverse;
1271     IUnknown *unknown;
1272     FILETIME filetime;
1273
1274     hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker);
1275     ok_ole_success(hr, CreateClassMoniker);
1276     if (!moniker) return;
1277
1278     test_moniker("class moniker", moniker, 
1279         expected_class_moniker_marshal_data, sizeof(expected_class_moniker_marshal_data),
1280         expected_class_moniker_saved_data, sizeof(expected_class_moniker_saved_data),
1281         expected_class_moniker_comparison_data, sizeof(expected_class_moniker_comparison_data),
1282         expected_class_moniker_display_name);
1283
1284     /* Hashing */
1285
1286     hr = IMoniker_Hash(moniker, &hash);
1287     ok_ole_success(hr, IMoniker_Hash);
1288
1289     ok(hash == CLSID_StdComponentCategoriesMgr.Data1,
1290         "Hash value != Data1 field of clsid, instead was 0x%08x\n",
1291         hash);
1292
1293     /* IsSystemMoniker test */
1294
1295     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1296     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1297
1298     ok(moniker_type == MKSYS_CLASSMONIKER,
1299         "dwMkSys != MKSYS_CLASSMONIKER, instead was 0x%08x\n",
1300         moniker_type);
1301
1302     hr = CreateBindCtx(0, &bindctx);
1303     ok_ole_success(hr, CreateBindCtx);
1304
1305     /* IsRunning test */
1306     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1307     ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08x\n", hr);
1308
1309     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1310     ok(hr == MK_E_UNAVAILABLE, "IMoniker_GetTimeOfLastChange should return MK_E_UNAVAILABLE, not 0x%08x\n", hr);
1311
1312     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1313     ok_ole_success(hr, IMoniker_BindToStorage);
1314     IUnknown_Release(unknown);
1315
1316     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1317     ok_ole_success(hr, IMoniker_BindToStorage);
1318     IUnknown_Release(unknown);
1319
1320     IBindCtx_Release(bindctx);
1321
1322     hr = IMoniker_Inverse(moniker, &inverse);
1323     ok_ole_success(hr, IMoniker_Inverse);
1324     IMoniker_Release(inverse);
1325
1326     IMoniker_Release(moniker);
1327 }
1328
1329 static void test_file_moniker(WCHAR* path)
1330 {
1331     IStream *stream;
1332     IMoniker *moniker1 = NULL, *moniker2 = NULL;
1333     HRESULT hr;
1334
1335     hr = CreateFileMoniker(path, &moniker1);
1336     ok_ole_success(hr, CreateFileMoniker); 
1337
1338     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1339
1340     /* Marshal */
1341     hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker1, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1342     ok_ole_success(hr, CoMarshalInterface);
1343     
1344     /* Rewind */
1345     hr = IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
1346     ok_ole_success(hr, IStream_Seek);
1347
1348     /* Unmarshal */
1349     hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void**)&moniker2);
1350     ok_ole_success(hr, CoUnmarshalInterface);
1351
1352     hr = IMoniker_IsEqual(moniker1, moniker2);
1353     ok_ole_success(hr, IsEqual);
1354
1355     IStream_Release(stream);
1356     if (moniker1) 
1357         IMoniker_Release(moniker1);
1358     if (moniker2) 
1359         IMoniker_Release(moniker2);
1360 }
1361
1362 static void test_file_monikers(void)
1363 {
1364     static WCHAR wszFile[][30] = {
1365         {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0},
1366         {'\\', '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},
1367         /* These map to themselves in Windows-1252 & 932 (Shift-JIS) */
1368         {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0},
1369         /* U+2020 = DAGGER     = 0x86 (1252) = 0x813f (932)
1370          * U+20AC = EURO SIGN  = 0x80 (1252) =  undef (932)
1371          * U+0100 .. = Latin extended-A
1372          */ 
1373         {0x20ac, 0x2020, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c,  0},
1374         };
1375
1376     int i; 
1377
1378     trace("ACP is %u\n", GetACP());
1379
1380     for (i = 0; i < COUNTOF(wszFile); ++i)
1381     {
1382         int j ;
1383         for (j = lstrlenW(wszFile[i]); j > 0; --j)
1384         {
1385             wszFile[i][j] = 0;
1386             test_file_moniker(wszFile[i]);
1387         }
1388     }
1389 }
1390
1391 static void test_item_moniker(void)
1392 {
1393     HRESULT hr;
1394     IMoniker *moniker;
1395     DWORD moniker_type;
1396     DWORD hash;
1397     IBindCtx *bindctx;
1398     IMoniker *inverse;
1399     IUnknown *unknown;
1400     static const WCHAR wszDelimeter[] = {'!',0};
1401     static const WCHAR wszObjectName[] = {'T','e','s','t',0};
1402     static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 };
1403
1404     hr = CreateItemMoniker(wszDelimeter, wszObjectName, &moniker);
1405     ok_ole_success(hr, CreateItemMoniker);
1406
1407     test_moniker("item moniker", moniker, 
1408         expected_item_moniker_marshal_data, sizeof(expected_item_moniker_marshal_data),
1409         expected_item_moniker_saved_data, sizeof(expected_item_moniker_saved_data),
1410         expected_item_moniker_comparison_data, sizeof(expected_item_moniker_comparison_data),
1411         expected_display_name);
1412
1413     /* Hashing */
1414
1415     hr = IMoniker_Hash(moniker, &hash);
1416     ok_ole_success(hr, IMoniker_Hash);
1417
1418     ok(hash == 0x73c,
1419         "Hash value != 0x73c, instead was 0x%08x\n",
1420         hash);
1421
1422     /* IsSystemMoniker test */
1423
1424     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1425     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1426
1427     ok(moniker_type == MKSYS_ITEMMONIKER,
1428         "dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n",
1429         moniker_type);
1430
1431     hr = CreateBindCtx(0, &bindctx);
1432     ok_ole_success(hr, CreateBindCtx);
1433
1434     /* IsRunning test */
1435     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1436     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1437
1438     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1439     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
1440
1441     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1442     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
1443
1444     IBindCtx_Release(bindctx);
1445
1446     hr = IMoniker_Inverse(moniker, &inverse);
1447     ok_ole_success(hr, IMoniker_Inverse);
1448     IMoniker_Release(inverse);
1449
1450     IMoniker_Release(moniker);
1451 }
1452
1453 static void test_anti_moniker(void)
1454 {
1455     HRESULT hr;
1456     IMoniker *moniker;
1457     DWORD moniker_type;
1458     DWORD hash;
1459     IBindCtx *bindctx;
1460     FILETIME filetime;
1461     IMoniker *inverse;
1462     IUnknown *unknown;
1463     static const WCHAR expected_display_name[] = { '\\','.','.',0 };
1464
1465     hr = CreateAntiMoniker(&moniker);
1466     ok_ole_success(hr, CreateAntiMoniker);
1467     if (!moniker) return;
1468
1469     test_moniker("anti moniker", moniker, 
1470         expected_anti_moniker_marshal_data, sizeof(expected_anti_moniker_marshal_data),
1471         expected_anti_moniker_saved_data, sizeof(expected_anti_moniker_saved_data),
1472         expected_anti_moniker_comparison_data, sizeof(expected_anti_moniker_comparison_data),
1473         expected_display_name);
1474
1475     /* Hashing */
1476     hr = IMoniker_Hash(moniker, &hash);
1477     ok_ole_success(hr, IMoniker_Hash);
1478     ok(hash == 0x80000001,
1479         "Hash value != 0x80000001, instead was 0x%08x\n",
1480         hash);
1481
1482     /* IsSystemMoniker test */
1483     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1484     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1485     ok(moniker_type == MKSYS_ANTIMONIKER,
1486         "dwMkSys != MKSYS_ANTIMONIKER, instead was 0x%08x\n",
1487         moniker_type);
1488
1489     hr = IMoniker_Inverse(moniker, &inverse);
1490     ok(hr == MK_E_NOINVERSE, "IMoniker_Inverse should have returned MK_E_NOINVERSE instead of 0x%08x\n", hr);
1491     ok(inverse == NULL, "inverse should have been set to NULL instead of %p\n", inverse);
1492
1493     hr = CreateBindCtx(0, &bindctx);
1494     ok_ole_success(hr, CreateBindCtx);
1495
1496     /* IsRunning test */
1497     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1498     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1499
1500     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1501     ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr);
1502
1503     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1504     ok(hr == E_NOTIMPL, "IMoniker_BindToObject should return E_NOTIMPL, not 0x%08x\n", hr);
1505
1506     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1507     ok(hr == E_NOTIMPL, "IMoniker_BindToStorage should return E_NOTIMPL, not 0x%08x\n", hr);
1508
1509     IBindCtx_Release(bindctx);
1510
1511     IMoniker_Release(moniker);
1512 }
1513
1514 static void test_generic_composite_moniker(void)
1515 {
1516     HRESULT hr;
1517     IMoniker *moniker;
1518     IMoniker *moniker1;
1519     IMoniker *moniker2;
1520     DWORD moniker_type;
1521     DWORD hash;
1522     IBindCtx *bindctx;
1523     FILETIME filetime;
1524     IMoniker *inverse;
1525     IUnknown *unknown;
1526     static const WCHAR wszDelimeter1[] = {'!',0};
1527     static const WCHAR wszObjectName1[] = {'T','e','s','t',0};
1528     static const WCHAR wszDelimeter2[] = {'#',0};
1529     static const WCHAR wszObjectName2[] = {'W','i','n','e',0};
1530     static const WCHAR expected_display_name[] = { '!','T','e','s','t','#','W','i','n','e',0 };
1531
1532     hr = CreateItemMoniker(wszDelimeter1, wszObjectName1, &moniker1);
1533     ok_ole_success(hr, CreateItemMoniker);
1534     hr = CreateItemMoniker(wszDelimeter2, wszObjectName2, &moniker2);
1535     ok_ole_success(hr, CreateItemMoniker);
1536     hr = CreateGenericComposite(moniker1, moniker2, &moniker);
1537     ok_ole_success(hr, CreateGenericComposite);
1538
1539     test_moniker("generic composite moniker", moniker, 
1540         expected_gc_moniker_marshal_data, sizeof(expected_gc_moniker_marshal_data),
1541         expected_gc_moniker_saved_data, sizeof(expected_gc_moniker_saved_data),
1542         expected_gc_moniker_comparison_data, sizeof(expected_gc_moniker_comparison_data),
1543         expected_display_name);
1544
1545     /* Hashing */
1546
1547     hr = IMoniker_Hash(moniker, &hash);
1548     ok_ole_success(hr, IMoniker_Hash);
1549
1550     ok(hash == 0xd87,
1551         "Hash value != 0xd87, instead was 0x%08x\n",
1552         hash);
1553
1554     /* IsSystemMoniker test */
1555
1556     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1557     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1558
1559     ok(moniker_type == MKSYS_GENERICCOMPOSITE,
1560         "dwMkSys != MKSYS_GENERICCOMPOSITE, instead was 0x%08x\n",
1561         moniker_type);
1562
1563     hr = CreateBindCtx(0, &bindctx);
1564     ok_ole_success(hr, CreateBindCtx);
1565
1566     /* IsRunning test */
1567     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1568     todo_wine
1569     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1570
1571     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1572     ok(hr == MK_E_NOTBINDABLE, "IMoniker_GetTimeOfLastChange should return MK_E_NOTBINDABLE, not 0x%08x\n", hr);
1573
1574     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1575     todo_wine
1576     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
1577
1578     todo_wine
1579     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1580     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
1581
1582     IBindCtx_Release(bindctx);
1583
1584     hr = IMoniker_Inverse(moniker, &inverse);
1585     ok_ole_success(hr, IMoniker_Inverse);
1586     IMoniker_Release(inverse);
1587
1588     IMoniker_Release(moniker);
1589 }
1590
1591 static void test_bind_context(void)
1592 {
1593     HRESULT hr;
1594     IBindCtx *pBindCtx;
1595     IEnumString *pEnumString;
1596     BIND_OPTS2 bind_opts;
1597     HeapUnknown *unknown;
1598     HeapUnknown *unknown2;
1599     IUnknown *param_obj;
1600     ULONG refs;
1601     static const WCHAR wszParamName[] = {'G','e','m','m','a',0};
1602     static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
1603
1604     hr = CreateBindCtx(0, NULL);
1605     ok(hr == E_INVALIDARG, "CreateBindCtx with NULL ppbc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1606
1607     hr = CreateBindCtx(0xdeadbeef, &pBindCtx);
1608     ok(hr == E_INVALIDARG, "CreateBindCtx with reserved value non-zero should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1609
1610     hr = CreateBindCtx(0, &pBindCtx);
1611     ok_ole_success(hr, "CreateBindCtx");
1612
1613     bind_opts.cbStruct = -1;
1614     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1615     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1616     ok(bind_opts.cbStruct == sizeof(bind_opts), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1617
1618     bind_opts.cbStruct = sizeof(BIND_OPTS);
1619     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1620     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1621     ok(bind_opts.cbStruct == sizeof(BIND_OPTS), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1622
1623     bind_opts.cbStruct = sizeof(bind_opts);
1624     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1625     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1626     ok(bind_opts.cbStruct == sizeof(bind_opts), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1627     ok(bind_opts.grfFlags == 0, "bind_opts.grfFlags was 0x%x instead of 0\n", bind_opts.grfFlags);
1628     ok(bind_opts.grfMode == STGM_READWRITE, "bind_opts.grfMode was 0x%x instead of STGM_READWRITE\n", bind_opts.grfMode);
1629     ok(bind_opts.dwTickCountDeadline == 0, "bind_opts.dwTickCountDeadline was %d instead of 0\n", bind_opts.dwTickCountDeadline);
1630     ok(bind_opts.dwTrackFlags == 0, "bind_opts.dwTrackFlags was 0x%x instead of 0\n", bind_opts.dwTrackFlags);
1631     ok(bind_opts.dwClassContext == (CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER),
1632         "bind_opts.dwClassContext should have been 0x15 instead of 0x%x\n", bind_opts.dwClassContext);
1633     ok(bind_opts.locale == GetThreadLocale(), "bind_opts.locale should have been 0x%x instead of 0x%x\n", GetThreadLocale(), bind_opts.locale);
1634     ok(bind_opts.pServerInfo == NULL, "bind_opts.pServerInfo should have been NULL instead of %p\n", bind_opts.pServerInfo);
1635
1636     bind_opts.cbStruct = -1;
1637     hr = IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1638     ok(hr == E_INVALIDARG, "IBindCtx_SetBindOptions with bad cbStruct should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1639
1640     hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, NULL);
1641     ok(hr == E_INVALIDARG, "IBindCtx_RegisterObjectParam should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1642
1643     unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
1644     unknown->lpVtbl = &HeapUnknown_Vtbl;
1645     unknown->refs = 1;
1646     hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, (IUnknown *)&unknown->lpVtbl);
1647     ok_ole_success(hr, "IBindCtx_RegisterObjectParam");
1648
1649     hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszParamName, &param_obj);
1650     ok_ole_success(hr, "IBindCtx_GetObjectParam");
1651     IUnknown_Release(param_obj);
1652
1653     hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszNonExistent, &param_obj);
1654     ok(hr == E_FAIL, "IBindCtx_GetObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08x\n", hr);
1655     ok(param_obj == NULL, "IBindCtx_GetObjectParam with nonexistent key should have set output parameter to NULL instead of %p\n", param_obj);
1656
1657     hr = IBindCtx_RevokeObjectParam(pBindCtx, (WCHAR *)wszNonExistent);
1658     ok(hr == E_FAIL, "IBindCtx_RevokeObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08x\n", hr);
1659
1660     hr = IBindCtx_EnumObjectParam(pBindCtx, &pEnumString);
1661     ok(hr == E_NOTIMPL, "IBindCtx_EnumObjectParam should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1662     ok(!pEnumString, "pEnumString should be NULL\n");
1663
1664     hr = IBindCtx_RegisterObjectBound(pBindCtx, NULL);
1665     ok_ole_success(hr, "IBindCtx_RegisterObjectBound(NULL)");
1666
1667     hr = IBindCtx_RevokeObjectBound(pBindCtx, NULL);
1668     ok(hr == E_INVALIDARG, "IBindCtx_RevokeObjectBound(NULL) should have return E_INVALIDARG instead of 0x%08x\n", hr);
1669
1670     unknown2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
1671     unknown2->lpVtbl = &HeapUnknown_Vtbl;
1672     unknown2->refs = 1;
1673     hr = IBindCtx_RegisterObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1674     ok_ole_success(hr, "IBindCtx_RegisterObjectBound");
1675
1676     hr = IBindCtx_RevokeObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1677     ok_ole_success(hr, "IBindCtx_RevokeObjectBound");
1678
1679     hr = IBindCtx_RevokeObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1680     ok(hr == MK_E_NOTBOUND, "IBindCtx_RevokeObjectBound with not bound object should have returned MK_E_NOTBOUND instead of 0x%08x\n", hr);
1681
1682     IBindCtx_Release(pBindCtx);
1683
1684     refs = IUnknown_Release((IUnknown *)&unknown->lpVtbl);
1685     ok(!refs, "object param should have been destroyed, instead of having %d refs\n", refs);
1686
1687     refs = IUnknown_Release((IUnknown *)&unknown2->lpVtbl);
1688     ok(!refs, "bound object should have been destroyed, instead of having %d refs\n", refs);
1689 }
1690
1691 START_TEST(moniker)
1692 {
1693     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1694
1695     test_ROT();
1696     test_MkParseDisplayName();
1697     test_class_moniker();
1698     test_file_monikers();
1699     test_item_moniker();
1700     test_anti_moniker();
1701     test_generic_composite_moniker();
1702
1703     /* FIXME: test moniker creation funcs and parsing other moniker formats */
1704
1705     test_bind_context();
1706
1707     CoUninitialize();
1708 }