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