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