mshtml: Added IHTMLWindow2::focus implementation.
[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     hr = MK_E_NOOBJECT;
1016     
1017     matchCnt = count_moniker_matches(pbc, spEM1);
1018     trace("Number of matches is %i\n", matchCnt);
1019
1020     grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE;
1021     hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk1, &pdwReg1);
1022     ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n",
1023         hr, pprot, grflags, lpEM1, pmk1, pdwReg1);
1024
1025     trace("IROT::Register\n");
1026     grflags=0;
1027     grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE;
1028     hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk2, &pdwReg2);
1029     ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n", hr,
1030        pprot, grflags, lpEM1, pmk2, pdwReg2);
1031
1032     hr = IRunningObjectTable_EnumRunning(pprot, &spEM2);
1033     ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr);
1034
1035     matchCnt = count_moniker_matches(pbc, spEM2);
1036     ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
1037
1038     trace("IEnumMoniker::Clone\n");
1039     IEnumMoniker_Clone(spEM2, &spEM3);
1040
1041     matchCnt = count_moniker_matches(pbc, spEM3);
1042     ok(matchCnt==0, "Number of matches should be equal to 0 not %i\n", matchCnt);
1043     trace("IEnumMoniker::Reset\n");
1044     IEnumMoniker_Reset(spEM3);
1045
1046     matchCnt = count_moniker_matches(pbc, spEM3);
1047     ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
1048
1049     IRunningObjectTable_Revoke(pprot,pdwReg1);
1050     IRunningObjectTable_Revoke(pprot,pdwReg2);
1051     IUnknown_Release(lpEM1);
1052     IEnumMoniker_Release(spEM1);
1053     IEnumMoniker_Release(spEM2);
1054     IEnumMoniker_Release(spEM3);
1055     IMoniker_Release(pmk1);
1056     IMoniker_Release(pmk2);
1057     IRunningObjectTable_Release(pprot);
1058
1059     IBindCtx_Release(pbc);
1060 }
1061
1062 static const LARGE_INTEGER llZero;
1063
1064 static const BYTE expected_class_moniker_marshal_data[] =
1065 {
1066     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1067     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1068     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1069     0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1070     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1071     0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
1072     0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
1073     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1074     0x00,0x00,0x00,0x00,
1075 };
1076
1077 static const BYTE expected_class_moniker_saved_data[] =
1078 {
1079      0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
1080      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1081      0x00,0x00,0x00,0x00,
1082 };
1083
1084 static const BYTE expected_class_moniker_comparison_data[] =
1085 {
1086      0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1087      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1088      0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
1089      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1090 };
1091
1092 static const WCHAR expected_class_moniker_display_name[] =
1093 {
1094     'c','l','s','i','d',':','0','0','0','2','E','0','0','5','-','0','0','0',
1095     '0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0',
1096     '0','0','0','0','4','6',':',0
1097 };
1098
1099 static const BYTE expected_item_moniker_comparison_data[] =
1100 {
1101      0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1102      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1103      0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00,
1104      0x54,0x00,0x00,0x00,
1105 };
1106
1107 static const BYTE expected_item_moniker_saved_data[] =
1108 {
1109      0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
1110      0x00,0x00,0x54,0x65,0x73,0x74,0x00,
1111 };
1112
1113 static const BYTE expected_item_moniker_marshal_data[] =
1114 {
1115      0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1116      0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1117      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1118      0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1119      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1120      0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
1121      0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
1122      0x00,0x00,0x54,0x65,0x73,0x74,0x00,
1123 };
1124
1125 static const BYTE expected_anti_moniker_marshal_data[] =
1126 {
1127     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1128     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1129     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1130     0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1131     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1132     0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
1133     0x01,0x00,0x00,0x00,
1134 };
1135
1136 static const BYTE expected_anti_moniker_saved_data[] =
1137 {
1138     0x01,0x00,0x00,0x00,
1139 };
1140
1141 static const BYTE expected_anti_moniker_comparison_data[] =
1142 {
1143     0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1144     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1145     0x01,0x00,0x00,0x00,
1146 };
1147
1148 static const BYTE expected_gc_moniker_marshal_data[] =
1149 {
1150     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1151     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1152     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1153     0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1154     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1155     0x00,0x00,0x00,0x00,0x2c,0x01,0x00,0x00,
1156     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
1157     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1158     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1159     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1160     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1161     0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
1162     0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
1163     0x00,0x00,0x54,0x65,0x73,0x74,0x00,0x4d,
1164     0x45,0x4f,0x57,0x04,0x00,0x00,0x00,0x0f,
1165     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
1166     0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x04,
1167     0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
1168     0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,
1169     0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x02,
1170     0x00,0x00,0x00,0x23,0x00,0x05,0x00,0x00,
1171     0x00,0x57,0x69,0x6e,0x65,0x00,
1172 };
1173
1174 static const BYTE expected_gc_moniker_saved_data[] =
1175 {
1176     0x02,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
1177     0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
1178     0x00,0x00,0x00,0x46,0x02,0x00,0x00,0x00,
1179     0x21,0x00,0x05,0x00,0x00,0x00,0x54,0x65,
1180     0x73,0x74,0x00,0x04,0x03,0x00,0x00,0x00,
1181     0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,
1182     0x00,0x00,0x46,0x02,0x00,0x00,0x00,0x23,
1183     0x00,0x05,0x00,0x00,0x00,0x57,0x69,0x6e,
1184     0x65,0x00,
1185 };
1186
1187 static const BYTE expected_gc_moniker_comparison_data[] =
1188 {
1189     0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1190     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1191     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
1192     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
1193     0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00,
1194     0x54,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
1195     0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
1196     0x00,0x00,0x00,0x46,0x23,0x00,0x57,0x00,
1197     0x49,0x00,0x4e,0x00,0x45,0x00,0x00,0x00,
1198 };
1199
1200 static void test_moniker(
1201     const char *testname, IMoniker *moniker,
1202     const BYTE *expected_moniker_marshal_data, unsigned int sizeof_expected_moniker_marshal_data,
1203     const BYTE *expected_moniker_saved_data, unsigned int sizeof_expected_moniker_saved_data,
1204     const BYTE *expected_moniker_comparison_data, unsigned int sizeof_expected_moniker_comparison_data,
1205     LPCWSTR expected_display_name)
1206 {
1207     IStream * stream;
1208     IROTData * rotdata;
1209     HRESULT hr;
1210     HGLOBAL hglobal;
1211     LPBYTE moniker_data;
1212     DWORD moniker_size;
1213     DWORD i;
1214     BOOL same;
1215     BYTE buffer[128];
1216     IMoniker * moniker_proxy;
1217     LPOLESTR display_name;
1218     IBindCtx *bindctx;
1219
1220     hr = IMoniker_IsDirty(moniker);
1221     ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr);
1222
1223     /* Display Name */
1224
1225     hr = CreateBindCtx(0, &bindctx);
1226     ok_ole_success(hr, CreateBindCtx);
1227
1228     hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
1229     ok_ole_success(hr, IMoniker_GetDisplayName);
1230     ok(!lstrcmpW(display_name, expected_display_name), "%s: display name wasn't what was expected\n", testname);
1231
1232     CoTaskMemFree(display_name);
1233     IBindCtx_Release(bindctx);
1234
1235     hr = IMoniker_IsDirty(moniker);
1236     ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr);
1237
1238     /* IROTData::GetComparisonData test */
1239
1240     hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
1241     ok_ole_success(hr, IMoniker_QueryInterface_IID_IROTData);
1242
1243     hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &moniker_size);
1244     ok_ole_success(hr, IROTData_GetComparisonData);
1245
1246     if (hr != S_OK) moniker_size = 0;
1247
1248     /* first check we have the right amount of data */
1249     ok(moniker_size == sizeof_expected_moniker_comparison_data,
1250         "%s: Size of comparison data differs (expected %d, actual %d)\n",
1251         testname, sizeof_expected_moniker_comparison_data, moniker_size);
1252
1253     /* then do a byte-by-byte comparison */
1254     same = TRUE;
1255     for (i = 0; i < min(moniker_size, sizeof_expected_moniker_comparison_data); i++)
1256     {
1257         if (expected_moniker_comparison_data[i] != buffer[i])
1258         {
1259             same = FALSE;
1260             break;
1261         }
1262     }
1263
1264     ok(same, "%s: Comparison data differs\n", testname);
1265     if (!same)
1266     {
1267         for (i = 0; i < moniker_size; i++)
1268         {
1269             if (i % 8 == 0) printf("     ");
1270             printf("0x%02x,", buffer[i]);
1271             if (i % 8 == 7) printf("\n");
1272         }
1273         printf("\n");
1274     }
1275
1276     IROTData_Release(rotdata);
1277   
1278     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
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
1460     /* Marshal */
1461     hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker1, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
1462     ok_ole_success(hr, CoMarshalInterface);
1463     
1464     /* Rewind */
1465     hr = IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
1466     ok_ole_success(hr, IStream_Seek);
1467
1468     /* Unmarshal */
1469     hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void**)&moniker2);
1470     ok_ole_success(hr, CoUnmarshalInterface);
1471
1472     hr = IMoniker_IsEqual(moniker1, moniker2);
1473     ok_ole_success(hr, IsEqual);
1474
1475     IStream_Release(stream);
1476     if (moniker1) 
1477         IMoniker_Release(moniker1);
1478     if (moniker2) 
1479         IMoniker_Release(moniker2);
1480 }
1481
1482 static void test_file_monikers(void)
1483 {
1484     static WCHAR wszFile[][30] = {
1485         {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0},
1486         {'\\', '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},
1487         /* These map to themselves in Windows-1252 & 932 (Shift-JIS) */
1488         {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0},
1489         /* U+2020 = DAGGER     = 0x86 (1252) = 0x813f (932)
1490          * U+20AC = EURO SIGN  = 0x80 (1252) =  undef (932)
1491          * U+0100 .. = Latin extended-A
1492          */ 
1493         {0x20ac, 0x2020, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c,  0},
1494         };
1495
1496     int i; 
1497
1498     trace("ACP is %u\n", GetACP());
1499
1500     for (i = 0; i < COUNTOF(wszFile); ++i)
1501     {
1502         int j ;
1503         if (i == 2)
1504         {
1505             BOOL used;
1506             WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, wszFile[i], -1, NULL, 0, NULL, &used );
1507             if (used)
1508             {
1509                 skip("string 2 doesn't round trip in codepage %u\n", GetACP() );
1510                 continue;
1511             }
1512         }
1513         for (j = lstrlenW(wszFile[i]); j > 0; --j)
1514         {
1515             wszFile[i][j] = 0;
1516             test_file_moniker(wszFile[i]);
1517         }
1518     }
1519 }
1520
1521 static void test_item_moniker(void)
1522 {
1523     HRESULT hr;
1524     IMoniker *moniker;
1525     DWORD moniker_type;
1526     DWORD hash;
1527     IBindCtx *bindctx;
1528     IMoniker *inverse;
1529     IUnknown *unknown;
1530     static const WCHAR wszDelimeter[] = {'!',0};
1531     static const WCHAR wszObjectName[] = {'T','e','s','t',0};
1532     static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 };
1533
1534     hr = CreateItemMoniker(wszDelimeter, wszObjectName, &moniker);
1535     ok_ole_success(hr, CreateItemMoniker);
1536
1537     test_moniker("item moniker", moniker, 
1538         expected_item_moniker_marshal_data, sizeof(expected_item_moniker_marshal_data),
1539         expected_item_moniker_saved_data, sizeof(expected_item_moniker_saved_data),
1540         expected_item_moniker_comparison_data, sizeof(expected_item_moniker_comparison_data),
1541         expected_display_name);
1542
1543     /* Hashing */
1544
1545     hr = IMoniker_Hash(moniker, &hash);
1546     ok_ole_success(hr, IMoniker_Hash);
1547
1548     ok(hash == 0x73c,
1549         "Hash value != 0x73c, instead was 0x%08x\n",
1550         hash);
1551
1552     /* IsSystemMoniker test */
1553
1554     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1555     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1556
1557     ok(moniker_type == MKSYS_ITEMMONIKER,
1558         "dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n",
1559         moniker_type);
1560
1561     hr = CreateBindCtx(0, &bindctx);
1562     ok_ole_success(hr, CreateBindCtx);
1563
1564     /* IsRunning test */
1565     hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
1566     ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr);
1567
1568     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1569     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1570
1571     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1572     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
1573
1574     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1575     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
1576
1577     IBindCtx_Release(bindctx);
1578
1579     hr = IMoniker_Inverse(moniker, &inverse);
1580     ok_ole_success(hr, IMoniker_Inverse);
1581     IMoniker_Release(inverse);
1582
1583     IMoniker_Release(moniker);
1584 }
1585
1586 static void test_anti_moniker(void)
1587 {
1588     HRESULT hr;
1589     IMoniker *moniker;
1590     DWORD moniker_type;
1591     DWORD hash;
1592     IBindCtx *bindctx;
1593     FILETIME filetime;
1594     IMoniker *inverse;
1595     IUnknown *unknown;
1596     static const WCHAR expected_display_name[] = { '\\','.','.',0 };
1597
1598     hr = CreateAntiMoniker(&moniker);
1599     ok_ole_success(hr, CreateAntiMoniker);
1600     if (!moniker) return;
1601
1602     test_moniker("anti moniker", moniker, 
1603         expected_anti_moniker_marshal_data, sizeof(expected_anti_moniker_marshal_data),
1604         expected_anti_moniker_saved_data, sizeof(expected_anti_moniker_saved_data),
1605         expected_anti_moniker_comparison_data, sizeof(expected_anti_moniker_comparison_data),
1606         expected_display_name);
1607
1608     /* Hashing */
1609     hr = IMoniker_Hash(moniker, &hash);
1610     ok_ole_success(hr, IMoniker_Hash);
1611     ok(hash == 0x80000001,
1612         "Hash value != 0x80000001, instead was 0x%08x\n",
1613         hash);
1614
1615     /* IsSystemMoniker test */
1616     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1617     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1618     ok(moniker_type == MKSYS_ANTIMONIKER,
1619         "dwMkSys != MKSYS_ANTIMONIKER, instead was 0x%08x\n",
1620         moniker_type);
1621
1622     hr = IMoniker_Inverse(moniker, &inverse);
1623     ok(hr == MK_E_NOINVERSE, "IMoniker_Inverse should have returned MK_E_NOINVERSE instead of 0x%08x\n", hr);
1624     ok(inverse == NULL, "inverse should have been set to NULL instead of %p\n", inverse);
1625
1626     hr = CreateBindCtx(0, &bindctx);
1627     ok_ole_success(hr, CreateBindCtx);
1628
1629     /* IsRunning test */
1630     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1631     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1632
1633     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1634     ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr);
1635
1636     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1637     ok(hr == E_NOTIMPL, "IMoniker_BindToObject should return E_NOTIMPL, not 0x%08x\n", hr);
1638
1639     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1640     ok(hr == E_NOTIMPL, "IMoniker_BindToStorage should return E_NOTIMPL, not 0x%08x\n", hr);
1641
1642     IBindCtx_Release(bindctx);
1643
1644     IMoniker_Release(moniker);
1645 }
1646
1647 static void test_generic_composite_moniker(void)
1648 {
1649     HRESULT hr;
1650     IMoniker *moniker;
1651     IMoniker *moniker1;
1652     IMoniker *moniker2;
1653     DWORD moniker_type;
1654     DWORD hash;
1655     IBindCtx *bindctx;
1656     FILETIME filetime;
1657     IMoniker *inverse;
1658     IUnknown *unknown;
1659     static const WCHAR wszDelimeter1[] = {'!',0};
1660     static const WCHAR wszObjectName1[] = {'T','e','s','t',0};
1661     static const WCHAR wszDelimeter2[] = {'#',0};
1662     static const WCHAR wszObjectName2[] = {'W','i','n','e',0};
1663     static const WCHAR expected_display_name[] = { '!','T','e','s','t','#','W','i','n','e',0 };
1664
1665     hr = CreateItemMoniker(wszDelimeter1, wszObjectName1, &moniker1);
1666     ok_ole_success(hr, CreateItemMoniker);
1667     hr = CreateItemMoniker(wszDelimeter2, wszObjectName2, &moniker2);
1668     ok_ole_success(hr, CreateItemMoniker);
1669     hr = CreateGenericComposite(moniker1, moniker2, &moniker);
1670     ok_ole_success(hr, CreateGenericComposite);
1671
1672     test_moniker("generic composite moniker", moniker, 
1673         expected_gc_moniker_marshal_data, sizeof(expected_gc_moniker_marshal_data),
1674         expected_gc_moniker_saved_data, sizeof(expected_gc_moniker_saved_data),
1675         expected_gc_moniker_comparison_data, sizeof(expected_gc_moniker_comparison_data),
1676         expected_display_name);
1677
1678     /* Hashing */
1679
1680     hr = IMoniker_Hash(moniker, &hash);
1681     ok_ole_success(hr, IMoniker_Hash);
1682
1683     ok(hash == 0xd87,
1684         "Hash value != 0xd87, instead was 0x%08x\n",
1685         hash);
1686
1687     /* IsSystemMoniker test */
1688
1689     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1690     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1691
1692     ok(moniker_type == MKSYS_GENERICCOMPOSITE,
1693         "dwMkSys != MKSYS_GENERICCOMPOSITE, instead was 0x%08x\n",
1694         moniker_type);
1695
1696     hr = CreateBindCtx(0, &bindctx);
1697     ok_ole_success(hr, CreateBindCtx);
1698
1699     /* IsRunning test */
1700     hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
1701     ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr);
1702
1703     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1704     todo_wine
1705     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
1706
1707     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1708     ok(hr == MK_E_NOTBINDABLE, "IMoniker_GetTimeOfLastChange should return MK_E_NOTBINDABLE, not 0x%08x\n", hr);
1709
1710     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1711     todo_wine
1712     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
1713
1714     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1715     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
1716
1717     IBindCtx_Release(bindctx);
1718
1719     hr = IMoniker_Inverse(moniker, &inverse);
1720     ok_ole_success(hr, IMoniker_Inverse);
1721     IMoniker_Release(inverse);
1722
1723     IMoniker_Release(moniker);
1724 }
1725
1726 static void test_pointer_moniker(void)
1727 {
1728     HRESULT hr;
1729     IMoniker *moniker;
1730     DWORD moniker_type;
1731     DWORD hash;
1732     IBindCtx *bindctx;
1733     FILETIME filetime;
1734     IMoniker *inverse;
1735     IUnknown *unknown;
1736     IStream *stream;
1737     IROTData *rotdata;
1738     LPOLESTR display_name;
1739
1740     cLocks = 0;
1741
1742     hr = CreatePointerMoniker((IUnknown *)&Test_ClassFactory, NULL);
1743     ok(hr == E_INVALIDARG, "CreatePointerMoniker(x, NULL) should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1744
1745     hr = CreatePointerMoniker((IUnknown *)&Test_ClassFactory, &moniker);
1746     ok_ole_success(hr, CreatePointerMoniker);
1747     if (!moniker) return;
1748
1749     ok_more_than_one_lock();
1750
1751     /* Display Name */
1752
1753     hr = CreateBindCtx(0, &bindctx);
1754     ok_ole_success(hr, CreateBindCtx);
1755
1756     hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
1757     ok(hr == E_NOTIMPL, "IMoniker_GetDisplayName should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1758
1759     IBindCtx_Release(bindctx);
1760
1761     hr = IMoniker_IsDirty(moniker);
1762     ok(hr == S_FALSE, "IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", hr);
1763
1764     /* IROTData::GetComparisonData test */
1765
1766     hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
1767     ok(hr == E_NOINTERFACE, "IMoniker_QueryInterface(IID_IROTData) should have returned E_NOINTERFACE instead of 0x%08x\n", hr);
1768
1769     /* Saving */
1770
1771     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
1772     ok_ole_success(hr, CreateStreamOnHGlobal);
1773
1774     hr = IMoniker_Save(moniker, stream, TRUE);
1775     ok(hr == E_NOTIMPL, "IMoniker_Save should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1776
1777     IStream_Release(stream);
1778
1779     /* Hashing */
1780     hr = IMoniker_Hash(moniker, &hash);
1781     ok_ole_success(hr, IMoniker_Hash);
1782     ok(hash == (DWORD)&Test_ClassFactory,
1783         "Hash value should have been 0x%08x, instead of 0x%08x\n",
1784         (DWORD)&Test_ClassFactory, hash);
1785
1786     /* IsSystemMoniker test */
1787     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
1788     ok_ole_success(hr, IMoniker_IsSystemMoniker);
1789     ok(moniker_type == MKSYS_POINTERMONIKER,
1790         "dwMkSys != MKSYS_POINTERMONIKER, instead was 0x%08x\n",
1791         moniker_type);
1792
1793     hr = IMoniker_Inverse(moniker, &inverse);
1794     ok_ole_success(hr, IMoniker_Inverse);
1795     IMoniker_Release(inverse);
1796
1797     hr = CreateBindCtx(0, &bindctx);
1798     ok_ole_success(hr, CreateBindCtx);
1799
1800     /* IsRunning test */
1801     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
1802     ok(hr == S_OK, "IMoniker_IsRunning should return S_OK, not 0x%08x\n", hr);
1803
1804     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
1805     ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr);
1806
1807     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1808     ok_ole_success(hr, IMoniker_BindToObject);
1809     IUnknown_Release(unknown);
1810
1811     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1812     ok_ole_success(hr, IMoniker_BindToStorage);
1813     IUnknown_Release(unknown);
1814
1815     IMoniker_Release(moniker);
1816
1817     ok_no_locks();
1818
1819     hr = CreatePointerMoniker(NULL, &moniker);
1820     ok_ole_success(hr, CreatePointerMoniker);
1821
1822     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1823     ok(hr == E_UNEXPECTED, "IMoniker_BindToObject should have returned E_UNEXPECTED instead of 0x%08x\n", hr);
1824
1825     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
1826     ok(hr == E_UNEXPECTED, "IMoniker_BindToStorage should have returned E_UNEXPECTED instead of 0x%08x\n", hr);
1827
1828     IBindCtx_Release(bindctx);
1829
1830     IMoniker_Release(moniker);
1831 }
1832
1833 static void test_bind_context(void)
1834 {
1835     HRESULT hr;
1836     IBindCtx *pBindCtx;
1837     IEnumString *pEnumString;
1838     BIND_OPTS2 bind_opts;
1839     HeapUnknown *unknown;
1840     HeapUnknown *unknown2;
1841     IUnknown *param_obj;
1842     ULONG refs;
1843     static const WCHAR wszParamName[] = {'G','e','m','m','a',0};
1844     static const WCHAR wszNonExistent[] = {'N','o','n','E','x','i','s','t','e','n','t',0};
1845
1846     hr = CreateBindCtx(0, NULL);
1847     ok(hr == E_INVALIDARG, "CreateBindCtx with NULL ppbc should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1848
1849     hr = CreateBindCtx(0xdeadbeef, &pBindCtx);
1850     ok(hr == E_INVALIDARG, "CreateBindCtx with reserved value non-zero should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1851
1852     hr = CreateBindCtx(0, &pBindCtx);
1853     ok_ole_success(hr, "CreateBindCtx");
1854
1855     bind_opts.cbStruct = -1;
1856     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1857     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1858     ok(bind_opts.cbStruct == sizeof(bind_opts) ||
1859        bind_opts.cbStruct == sizeof(bind_opts) + sizeof(void*), /* Vista */
1860        "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1861
1862     bind_opts.cbStruct = sizeof(BIND_OPTS);
1863     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1864     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1865     ok(bind_opts.cbStruct == sizeof(BIND_OPTS), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1866
1867     bind_opts.cbStruct = sizeof(bind_opts);
1868     hr = IBindCtx_GetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1869     ok_ole_success(hr, "IBindCtx_GetBindOptions");
1870     ok(bind_opts.cbStruct == sizeof(bind_opts), "bind_opts.cbStruct was %d\n", bind_opts.cbStruct);
1871     ok(bind_opts.grfFlags == 0, "bind_opts.grfFlags was 0x%x instead of 0\n", bind_opts.grfFlags);
1872     ok(bind_opts.grfMode == STGM_READWRITE, "bind_opts.grfMode was 0x%x instead of STGM_READWRITE\n", bind_opts.grfMode);
1873     ok(bind_opts.dwTickCountDeadline == 0, "bind_opts.dwTickCountDeadline was %d instead of 0\n", bind_opts.dwTickCountDeadline);
1874     ok(bind_opts.dwTrackFlags == 0, "bind_opts.dwTrackFlags was 0x%x instead of 0\n", bind_opts.dwTrackFlags);
1875     ok(bind_opts.dwClassContext == (CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER|CLSCTX_REMOTE_SERVER),
1876         "bind_opts.dwClassContext should have been 0x15 instead of 0x%x\n", bind_opts.dwClassContext);
1877     ok(bind_opts.locale == GetThreadLocale(), "bind_opts.locale should have been 0x%x instead of 0x%x\n", GetThreadLocale(), bind_opts.locale);
1878     ok(bind_opts.pServerInfo == NULL, "bind_opts.pServerInfo should have been NULL instead of %p\n", bind_opts.pServerInfo);
1879
1880     bind_opts.cbStruct = -1;
1881     hr = IBindCtx_SetBindOptions(pBindCtx, (BIND_OPTS *)&bind_opts);
1882     ok(hr == E_INVALIDARG, "IBindCtx_SetBindOptions with bad cbStruct should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1883
1884     hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, NULL);
1885     ok(hr == E_INVALIDARG, "IBindCtx_RegisterObjectParam should have returned E_INVALIDARG instead of 0x%08x\n", hr);
1886
1887     unknown = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
1888     unknown->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
1889     unknown->refs = 1;
1890     hr = IBindCtx_RegisterObjectParam(pBindCtx, (WCHAR *)wszParamName, &unknown->IUnknown_iface);
1891     ok_ole_success(hr, "IBindCtx_RegisterObjectParam");
1892
1893     hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszParamName, &param_obj);
1894     ok_ole_success(hr, "IBindCtx_GetObjectParam");
1895     IUnknown_Release(param_obj);
1896
1897     hr = IBindCtx_GetObjectParam(pBindCtx, (WCHAR *)wszNonExistent, &param_obj);
1898     ok(hr == E_FAIL, "IBindCtx_GetObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08x\n", hr);
1899     ok(param_obj == NULL, "IBindCtx_GetObjectParam with nonexistent key should have set output parameter to NULL instead of %p\n", param_obj);
1900
1901     hr = IBindCtx_RevokeObjectParam(pBindCtx, (WCHAR *)wszNonExistent);
1902     ok(hr == E_FAIL, "IBindCtx_RevokeObjectParam with nonexistent key should have failed with E_FAIL instead of 0x%08x\n", hr);
1903
1904     hr = IBindCtx_EnumObjectParam(pBindCtx, &pEnumString);
1905     ok(hr == E_NOTIMPL, "IBindCtx_EnumObjectParam should have returned E_NOTIMPL instead of 0x%08x\n", hr);
1906     ok(!pEnumString, "pEnumString should be NULL\n");
1907
1908     hr = IBindCtx_RegisterObjectBound(pBindCtx, NULL);
1909     ok_ole_success(hr, "IBindCtx_RegisterObjectBound(NULL)");
1910
1911     hr = IBindCtx_RevokeObjectBound(pBindCtx, NULL);
1912     ok(hr == E_INVALIDARG, "IBindCtx_RevokeObjectBound(NULL) should have return E_INVALIDARG instead of 0x%08x\n", hr);
1913
1914     unknown2 = HeapAlloc(GetProcessHeap(), 0, sizeof(*unknown));
1915     unknown2->IUnknown_iface.lpVtbl = &HeapUnknown_Vtbl;
1916     unknown2->refs = 1;
1917     hr = IBindCtx_RegisterObjectBound(pBindCtx, &unknown2->IUnknown_iface);
1918     ok_ole_success(hr, "IBindCtx_RegisterObjectBound");
1919
1920     hr = IBindCtx_RevokeObjectBound(pBindCtx, &unknown2->IUnknown_iface);
1921     ok_ole_success(hr, "IBindCtx_RevokeObjectBound");
1922
1923     hr = IBindCtx_RevokeObjectBound(pBindCtx, &unknown2->IUnknown_iface);
1924     ok(hr == MK_E_NOTBOUND, "IBindCtx_RevokeObjectBound with not bound object should have returned MK_E_NOTBOUND instead of 0x%08x\n", hr);
1925
1926     IBindCtx_Release(pBindCtx);
1927
1928     refs = IUnknown_Release(&unknown->IUnknown_iface);
1929     ok(!refs, "object param should have been destroyed, instead of having %d refs\n", refs);
1930
1931     refs = IUnknown_Release(&unknown2->IUnknown_iface);
1932     ok(!refs, "bound object should have been destroyed, instead of having %d refs\n", refs);
1933 }
1934
1935 static void test_save_load_filemoniker(void)
1936 {
1937     IMoniker* pMk;
1938     IStream* pStm;
1939     HRESULT hr;
1940     ULARGE_INTEGER size;
1941     LARGE_INTEGER zero_pos, dead_pos, nulls_pos;
1942     DWORD some_val = 0xFEDCBA98;
1943     int i;
1944
1945     /* see FileMonikerImpl_Save docs */
1946     zero_pos.QuadPart = 0;
1947     dead_pos.QuadPart = sizeof(WORD) + sizeof(DWORD) + (lstrlenW(wszFileName1) + 1) + sizeof(WORD);
1948     nulls_pos.QuadPart = dead_pos.QuadPart + sizeof(WORD);
1949
1950     /* create the stream we're going to write to */
1951     hr = CreateStreamOnHGlobal(NULL, TRUE, &pStm);
1952     ok_ole_success(hr, "CreateStreamOnHGlobal");
1953
1954     size.u.LowPart = 128;
1955     hr = IStream_SetSize(pStm, size);
1956     ok_ole_success(hr, "IStream_SetSize");
1957
1958     /* create and save a moniker */
1959     hr = CreateFileMoniker(wszFileName1, &pMk);
1960     ok_ole_success(hr, "CreateFileMoniker");
1961
1962     hr = IMoniker_Save(pMk, pStm, TRUE);
1963     ok_ole_success(hr, "IMoniker_Save");
1964
1965     hr = IMoniker_Release(pMk);
1966     ok_ole_success(hr, "IMoniker_Release");
1967
1968     /* overwrite the constants with various values */
1969     hr = IStream_Seek(pStm, zero_pos, STREAM_SEEK_SET, NULL);
1970     ok_ole_success(hr, "IStream_Seek");
1971     hr = IStream_Write(pStm, &some_val, sizeof(WORD), NULL);
1972     ok_ole_success(hr, "IStream_Write");
1973
1974     hr = IStream_Seek(pStm, dead_pos, STREAM_SEEK_SET, NULL);
1975     ok_ole_success(hr, "IStream_Seek");
1976     hr = IStream_Write(pStm, &some_val, sizeof(WORD), NULL);
1977     ok_ole_success(hr, "IStream_Write");
1978
1979     hr = IStream_Seek(pStm, nulls_pos, STREAM_SEEK_SET, NULL);
1980     ok_ole_success(hr, "IStream_Seek");
1981     for(i = 0; i < 5; ++i){
1982         hr = IStream_Write(pStm, &some_val, sizeof(DWORD), NULL);
1983         ok_ole_success(hr, "IStream_Write");
1984     }
1985
1986     /* go back to the start of the stream */
1987     hr = IStream_Seek(pStm, zero_pos, STREAM_SEEK_SET, NULL);
1988     ok_ole_success(hr, "IStream_Seek");
1989
1990     /* create a new moniker and load into it */
1991     hr = CreateFileMoniker(wszFileName1, &pMk);
1992     ok_ole_success(hr, "CreateFileMoniker");
1993
1994     hr = IMoniker_Load(pMk, pStm);
1995     ok_ole_success(hr, "IMoniker_Load");
1996
1997     hr = IMoniker_Release(pMk);
1998     ok_ole_success(hr, "IMoniker_Release");
1999
2000     hr = IStream_Release(pStm);
2001     ok_ole_success(hr, "IStream_Release");
2002 }
2003
2004 START_TEST(moniker)
2005 {
2006     if (!GetProcAddress(GetModuleHandleA("ole32.dll"), "CoRegisterSurrogateEx")) {
2007         win_skip("skipping test on win9x\n");
2008         return;
2009     }
2010
2011     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2012
2013     test_ROT();
2014     test_ROT_multiple_entries();
2015     test_MkParseDisplayName();
2016     test_class_moniker();
2017     test_file_monikers();
2018     test_item_moniker();
2019     test_anti_moniker();
2020     test_generic_composite_moniker();
2021     test_pointer_moniker();
2022     test_save_load_filemoniker();
2023
2024     /* FIXME: test moniker creation funcs and parsing other moniker formats */
2025
2026     test_bind_context();
2027
2028     CoUninitialize();
2029 }