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