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