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