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