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