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