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