ole32/tests: Skip a string that may not round-trip in all codepages.
[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         if (i == 2)
1436         {
1437             BOOL used;
1438             WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, wszFile[i], -1, NULL, 0, NULL, &used );
1439             if (used)
1440             {
1441                 skip("string 2 doesn't round trip in codepage %u\n", GetACP() );
1442                 continue;
1443             }
1444         }
1445         for (j = lstrlenW(wszFile[i]); j > 0; --j)
1446         {
1447             wszFile[i][j] = 0;
1448             test_file_moniker(wszFile[i]);
1449         }
1450     }
1451 }
1452
1453 static void test_item_moniker(void)
1454 {
1455     HRESULT hr;
1456     IMoniker *moniker;
1457     DWORD moniker_type;
1458     DWORD hash;
1459     IBindCtx *bindctx;
1460     IMoniker *inverse;
1461     IUnknown *unknown;
1462     static const WCHAR wszDelimeter[] = {'!',0};
1463     static const WCHAR wszObjectName[] = {'T','e','s','t',0};
1464     static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 };
1465
1466     hr = CreateItemMoniker(wszDelimeter, wszObjectName, &moniker);
1467     ok_ole_success(hr, CreateItemMoniker);
1468
1469     test_moniker("item moniker", moniker, 
1470         expected_item_moniker_marshal_data, sizeof(expected_item_moniker_marshal_data),
1471         expected_item_moniker_saved_data, sizeof(expected_item_moniker_saved_data),
1472         expected_item_moniker_comparison_data, sizeof(expected_item_moniker_comparison_data),
1473         expected_display_name);
1474
1475     /* Hashing */
1476
1477     hr = IMoniker_Hash(moniker, &hash);
1478     ok_ole_success(hr, IMoniker_Hash);
1479
1480     ok(hash == 0x73c,
1481         "Hash value != 0x73c, instead was 0x%08x\n",
1482         hash);
1483
1484     /* IsSystemMoniker test */
1485
1486     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1487     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1488
1489     ok(moniker_type == MKSYS_ITEMMONIKER,
1490         "dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n",
1491         moniker_type);
1492
1493     hr = CreateBindCtx(0, &bindctx);
1494     ok_ole_success(hr, CreateBindCtx);
1495
1496     /* IsRunning test */
1497     hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
1498     todo_wine
1499     ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr);
1500
1501     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1502     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1503
1504     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1505     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
1506
1507     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1508     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
1509
1510     IBindCtx_Release(bindctx);
1511
1512     hr = IMoniker_Inverse(moniker, &inverse);
1513     ok_ole_success(hr, IMoniker_Inverse);
1514     IMoniker_Release(inverse);
1515
1516     IMoniker_Release(moniker);
1517 }
1518
1519 static void test_anti_moniker(void)
1520 {
1521     HRESULT hr;
1522     IMoniker *moniker;
1523     DWORD moniker_type;
1524     DWORD hash;
1525     IBindCtx *bindctx;
1526     FILETIME filetime;
1527     IMoniker *inverse;
1528     IUnknown *unknown;
1529     static const WCHAR expected_display_name[] = { '\\','.','.',0 };
1530
1531     hr = CreateAntiMoniker(&moniker);
1532     ok_ole_success(hr, CreateAntiMoniker);
1533     if (!moniker) return;
1534
1535     test_moniker("anti moniker", moniker, 
1536         expected_anti_moniker_marshal_data, sizeof(expected_anti_moniker_marshal_data),
1537         expected_anti_moniker_saved_data, sizeof(expected_anti_moniker_saved_data),
1538         expected_anti_moniker_comparison_data, sizeof(expected_anti_moniker_comparison_data),
1539         expected_display_name);
1540
1541     /* Hashing */
1542     hr = IMoniker_Hash(moniker, &hash);
1543     ok_ole_success(hr, IMoniker_Hash);
1544     ok(hash == 0x80000001,
1545         "Hash value != 0x80000001, instead was 0x%08x\n",
1546         hash);
1547
1548     /* IsSystemMoniker test */
1549     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1550     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1551     ok(moniker_type == MKSYS_ANTIMONIKER,
1552         "dwMkSys != MKSYS_ANTIMONIKER, instead was 0x%08x\n",
1553         moniker_type);
1554
1555     hr = IMoniker_Inverse(moniker, &inverse);
1556     ok(hr == MK_E_NOINVERSE, "IMoniker_Inverse should have returned MK_E_NOINVERSE instead of 0x%08x\n", hr);
1557     ok(inverse == NULL, "inverse should have been set to NULL instead of %p\n", inverse);
1558
1559     hr = CreateBindCtx(0, &bindctx);
1560     ok_ole_success(hr, CreateBindCtx);
1561
1562     /* IsRunning test */
1563     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1564     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1565
1566     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1567     ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr);
1568
1569     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1570     ok(hr == E_NOTIMPL, "IMoniker_BindToObject should return E_NOTIMPL, not 0x%08x\n", hr);
1571
1572     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1573     ok(hr == E_NOTIMPL, "IMoniker_BindToStorage should return E_NOTIMPL, not 0x%08x\n", hr);
1574
1575     IBindCtx_Release(bindctx);
1576
1577     IMoniker_Release(moniker);
1578 }
1579
1580 static void test_generic_composite_moniker(void)
1581 {
1582     HRESULT hr;
1583     IMoniker *moniker;
1584     IMoniker *moniker1;
1585     IMoniker *moniker2;
1586     DWORD moniker_type;
1587     DWORD hash;
1588     IBindCtx *bindctx;
1589     FILETIME filetime;
1590     IMoniker *inverse;
1591     IUnknown *unknown;
1592     static const WCHAR wszDelimeter1[] = {'!',0};
1593     static const WCHAR wszObjectName1[] = {'T','e','s','t',0};
1594     static const WCHAR wszDelimeter2[] = {'#',0};
1595     static const WCHAR wszObjectName2[] = {'W','i','n','e',0};
1596     static const WCHAR expected_display_name[] = { '!','T','e','s','t','#','W','i','n','e',0 };
1597
1598     hr = CreateItemMoniker(wszDelimeter1, wszObjectName1, &moniker1);
1599     ok_ole_success(hr, CreateItemMoniker);
1600     hr = CreateItemMoniker(wszDelimeter2, wszObjectName2, &moniker2);
1601     ok_ole_success(hr, CreateItemMoniker);
1602     hr = CreateGenericComposite(moniker1, moniker2, &moniker);
1603     ok_ole_success(hr, CreateGenericComposite);
1604
1605     test_moniker("generic composite moniker", moniker, 
1606         expected_gc_moniker_marshal_data, sizeof(expected_gc_moniker_marshal_data),
1607         expected_gc_moniker_saved_data, sizeof(expected_gc_moniker_saved_data),
1608         expected_gc_moniker_comparison_data, sizeof(expected_gc_moniker_comparison_data),
1609         expected_display_name);
1610
1611     /* Hashing */
1612
1613     hr = IMoniker_Hash(moniker, &hash);
1614     ok_ole_success(hr, IMoniker_Hash);
1615
1616     ok(hash == 0xd87,
1617         "Hash value != 0xd87, instead was 0x%08x\n",
1618         hash);
1619
1620     /* IsSystemMoniker test */
1621
1622     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1623     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1624
1625     ok(moniker_type == MKSYS_GENERICCOMPOSITE,
1626         "dwMkSys != MKSYS_GENERICCOMPOSITE, instead was 0x%08x\n",
1627         moniker_type);
1628
1629     hr = CreateBindCtx(0, &bindctx);
1630     ok_ole_success(hr, CreateBindCtx);
1631
1632     /* IsRunning test */
1633     hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
1634     todo_wine
1635     ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr);
1636
1637     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1638     todo_wine
1639     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1640
1641     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1642     ok(hr == MK_E_NOTBINDABLE, "IMoniker_GetTimeOfLastChange should return MK_E_NOTBINDABLE, not 0x%08x\n", hr);
1643
1644     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1645     todo_wine
1646     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
1647
1648     todo_wine
1649     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1650     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
1651
1652     IBindCtx_Release(bindctx);
1653
1654     hr = IMoniker_Inverse(moniker, &inverse);
1655     ok_ole_success(hr, IMoniker_Inverse);
1656     IMoniker_Release(inverse);
1657
1658     IMoniker_Release(moniker);
1659 }
1660
1661 static void test_pointer_moniker(void)
1662 {
1663     HRESULT hr;
1664     IMoniker *moniker;
1665     DWORD moniker_type;
1666     DWORD hash;
1667     IBindCtx *bindctx;
1668     FILETIME filetime;
1669     IMoniker *inverse;
1670     IUnknown *unknown;
1671     IStream *stream;
1672     IROTData *rotdata;
1673     LPOLESTR display_name;
1674
1675     cLocks = 0;
1676
1677     hr = CreatePointerMoniker((IUnknown *)&Test_ClassFactory, NULL);
1678     ok(hr == E_INVALIDARG, "CreatePointerMoniker(x, NULL) should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1679
1680     hr = CreatePointerMoniker((IUnknown *)&Test_ClassFactory, &moniker);
1681     ok_ole_success(hr, CreatePointerMoniker);
1682     if (!moniker) return;
1683
1684     ok_more_than_one_lock();
1685
1686     /* Display Name */
1687
1688     hr = CreateBindCtx(0, &bindctx);
1689     ok_ole_success(hr, CreateBindCtx);
1690
1691     hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
1692     ok(hr == E_NOTIMPL, "IMoniker_GetDisplayName should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1693
1694     IBindCtx_Release(bindctx);
1695
1696     hr = IMoniker_IsDirty(moniker);
1697     ok(hr == S_FALSE, "IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", hr);
1698
1699     /* IROTData::GetComparisonData test */
1700
1701     hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
1702     ok(hr == E_NOINTERFACE, "IMoniker_QueryInterface(IID_IROTData) should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
1703
1704     /* Saving */
1705
1706     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1707     ok_ole_success(hr, CreateStreamOnHGlobal);
1708
1709     hr = IMoniker_Save(moniker, stream, TRUE);
1710     ok(hr == E_NOTIMPL, "IMoniker_Save should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1711
1712     IStream_Release(stream);
1713
1714     /* Hashing */
1715     hr = IMoniker_Hash(moniker, &hash);
1716     ok_ole_success(hr, IMoniker_Hash);
1717     ok(hash == (DWORD)&Test_ClassFactory,
1718         "Hash value should have been 0x%08x, instead of 0x%08x\n",
1719         (DWORD)&Test_ClassFactory, hash);
1720
1721     /* IsSystemMoniker test */
1722     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1723     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1724     ok(moniker_type == MKSYS_POINTERMONIKER,
1725         "dwMkSys != MKSYS_POINTERMONIKER, instead was 0x%08x\n",
1726         moniker_type);
1727
1728     hr = IMoniker_Inverse(moniker, &inverse);
1729     ok_ole_success(hr, IMoniker_Inverse);
1730     IMoniker_Release(inverse);
1731
1732     hr = CreateBindCtx(0, &bindctx);
1733     ok_ole_success(hr, CreateBindCtx);
1734
1735     /* IsRunning test */
1736     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1737     ok(hr == S_OK, "IMoniker_IsRunning should return S_OK, not 0x%08x\n", hr);
1738
1739     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1740     ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr);
1741
1742     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1743     ok_ole_success(hr, IMoniker_BindToObject);
1744     IUnknown_Release(unknown);
1745
1746     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1747     ok_ole_success(hr, IMoniker_BindToStorage);
1748     IUnknown_Release(unknown);
1749
1750     IMoniker_Release(moniker);
1751
1752     ok_no_locks();
1753
1754     hr = CreatePointerMoniker(NULL, &moniker);
1755     ok_ole_success(hr, CreatePointerMoniker);
1756
1757     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1758     ok(hr == E_UNEXPECTED, "IMoniker_BindToObject should have returned E_UNEXPECTED instead of 0x%08x\n", hr);
1759
1760     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1761     ok(hr == E_UNEXPECTED, "IMoniker_BindToStorage should have returned E_UNEXPECTED instead of 0x%08x\n", hr);
1762
1763     IBindCtx_Release(bindctx);
1764
1765     IMoniker_Release(moniker);
1766 }
1767
1768 static void test_bind_context(void)
1769 {
1770     HRESULT hr;
1771     IBindCtx *pBindCtx;
1772     IEnumString *pEnumString;
1773     BIND_OPTS2 bind_opts;
1774     HeapUnknown *unknown;
1775     HeapUnknown *unknown2;
1776     IUnknown *param_obj;
1777     ULONG refs;
1778     static const WCHAR wszParamName[] = {'G','e','m','m','a',0};
1779     static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
1780
1781     hr = CreateBindCtx(0, NULL);
1782     ok(hr == E_INVALIDARG, "CreateBindCtx with NULL ppbc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1783
1784     hr = CreateBindCtx(0xdeadbeef, &pBindCtx);
1785     ok(hr == E_INVALIDARG, "CreateBindCtx with reserved value non-zero should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1786
1787     hr = CreateBindCtx(0, &pBindCtx);
1788     ok_ole_success(hr, "CreateBindCtx");
1789
1790     bind_opts.cbStruct = -1;
1791     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1792     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1793     ok(bind_opts.cbStruct == sizeof(bind_opts) ||
1794        bind_opts.cbStruct == sizeof(bind_opts) + sizeof(void*), /* Vista */
1795        "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1796
1797     bind_opts.cbStruct = sizeof(BIND_OPTS);
1798     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1799     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1800     ok(bind_opts.cbStruct == sizeof(BIND_OPTS), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1801
1802     bind_opts.cbStruct = sizeof(bind_opts);
1803     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1804     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1805     ok(bind_opts.cbStruct == sizeof(bind_opts), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1806     ok(bind_opts.grfFlags == 0, "bind_opts.grfFlags was 0x%x instead of 0\n", bind_opts.grfFlags);
1807     ok(bind_opts.grfMode == STGM_READWRITE, "bind_opts.grfMode was 0x%x instead of STGM_READWRITE\n", bind_opts.grfMode);
1808     ok(bind_opts.dwTickCountDeadline == 0, "bind_opts.dwTickCountDeadline was %d instead of 0\n", bind_opts.dwTickCountDeadline);
1809     ok(bind_opts.dwTrackFlags == 0, "bind_opts.dwTrackFlags was 0x%x instead of 0\n", bind_opts.dwTrackFlags);
1810     ok(bind_opts.dwClassContext == (CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER),
1811         "bind_opts.dwClassContext should have been 0x15 instead of 0x%x\n", bind_opts.dwClassContext);
1812     ok(bind_opts.locale == GetThreadLocale(), "bind_opts.locale should have been 0x%x instead of 0x%x\n", GetThreadLocale(), bind_opts.locale);
1813     ok(bind_opts.pServerInfo == NULL, "bind_opts.pServerInfo should have been NULL instead of %p\n", bind_opts.pServerInfo);
1814
1815     bind_opts.cbStruct = -1;
1816     hr = IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1817     ok(hr == E_INVALIDARG, "IBindCtx_SetBindOptions with bad cbStruct should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1818
1819     hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, NULL);
1820     ok(hr == E_INVALIDARG, "IBindCtx_RegisterObjectParam should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1821
1822     unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
1823     unknown->lpVtbl = &HeapUnknown_Vtbl;
1824     unknown->refs = 1;
1825     hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, (IUnknown *)&unknown->lpVtbl);
1826     ok_ole_success(hr, "IBindCtx_RegisterObjectParam");
1827
1828     hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszParamName, &param_obj);
1829     ok_ole_success(hr, "IBindCtx_GetObjectParam");
1830     IUnknown_Release(param_obj);
1831
1832     hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszNonExistent, &param_obj);
1833     ok(hr == E_FAIL, "IBindCtx_GetObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08x\n", hr);
1834     ok(param_obj == NULL, "IBindCtx_GetObjectParam with nonexistent key should have set output parameter to NULL instead of %p\n", param_obj);
1835
1836     hr = IBindCtx_RevokeObjectParam(pBindCtx, (WCHAR *)wszNonExistent);
1837     ok(hr == E_FAIL, "IBindCtx_RevokeObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08x\n", hr);
1838
1839     hr = IBindCtx_EnumObjectParam(pBindCtx, &pEnumString);
1840     ok(hr == E_NOTIMPL, "IBindCtx_EnumObjectParam should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1841     ok(!pEnumString, "pEnumString should be NULL\n");
1842
1843     hr = IBindCtx_RegisterObjectBound(pBindCtx, NULL);
1844     ok_ole_success(hr, "IBindCtx_RegisterObjectBound(NULL)");
1845
1846     hr = IBindCtx_RevokeObjectBound(pBindCtx, NULL);
1847     ok(hr == E_INVALIDARG, "IBindCtx_RevokeObjectBound(NULL) should have return E_INVALIDARG instead of 0x%08x\n", hr);
1848
1849     unknown2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
1850     unknown2->lpVtbl = &HeapUnknown_Vtbl;
1851     unknown2->refs = 1;
1852     hr = IBindCtx_RegisterObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1853     ok_ole_success(hr, "IBindCtx_RegisterObjectBound");
1854
1855     hr = IBindCtx_RevokeObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1856     ok_ole_success(hr, "IBindCtx_RevokeObjectBound");
1857
1858     hr = IBindCtx_RevokeObjectBound(pBindCtx, (IUnknown *)&unknown2->lpVtbl);
1859     ok(hr == MK_E_NOTBOUND, "IBindCtx_RevokeObjectBound with not bound object should have returned MK_E_NOTBOUND instead of 0x%08x\n", hr);
1860
1861     IBindCtx_Release(pBindCtx);
1862
1863     refs = IUnknown_Release((IUnknown *)&unknown->lpVtbl);
1864     ok(!refs, "object param should have been destroyed, instead of having %d refs\n", refs);
1865
1866     refs = IUnknown_Release((IUnknown *)&unknown2->lpVtbl);
1867     ok(!refs, "bound object should have been destroyed, instead of having %d refs\n", refs);
1868 }
1869
1870 START_TEST(moniker)
1871 {
1872     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1873
1874     test_ROT();
1875     test_ROT_multiple_entries();
1876     test_MkParseDisplayName();
1877     test_class_moniker();
1878     test_file_monikers();
1879     test_item_moniker();
1880     test_anti_moniker();
1881     test_generic_composite_moniker();
1882     test_pointer_moniker();
1883
1884     /* FIXME: test moniker creation funcs and parsing other moniker formats */
1885
1886     test_bind_context();
1887
1888     CoUninitialize();
1889 }