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 "comcat.h"
33 #include "olectl.h"
34 
35 #include "wine/test.h"
36 
37 #define ok_more_than_one_lock() ok(cLocks > 0, "Number of locks should be > 0, but actually is %d\n", cLocks)
38 #define ok_no_locks() ok(cLocks == 0, "Number of locks should be 0, but actually is %d\n", cLocks)
39 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
40 
41 #define CHECK_EXPECTED_METHOD(method_name) \
42 do { \
43     trace("%s\n", method_name); \
44         ok(*expected_method_list != NULL, "Extra method %s called\n", method_name); \
45             if (*expected_method_list) \
46             { \
47                 ok(!strcmp(*expected_method_list, method_name), "Expected %s to be called instead of %s\n", \
48                    *expected_method_list, method_name); \
49                        expected_method_list++; \
50             } \
51 } while(0)
52 
53 static char const * const *expected_method_list;
54 static const WCHAR wszFileName1[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','1','.','d','o','c',0};
55 static const WCHAR wszFileName2[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','2','.','d','o','c',0};
56 
57 static const CLSID CLSID_TestMoniker =
58 { /* b306bfbc-496e-4f53-b93e-2ff9c83223d7 */
59     0xb306bfbc,
60     0x496e,
61     0x4f53,
62     {0xb9, 0x3e, 0x2f, 0xf9, 0xc8, 0x32, 0x23, 0xd7}
63 };
64 
65 static LONG cLocks;
66 
LockModule(void)67 static void LockModule(void)
68 {
69     InterlockedIncrement(&cLocks);
70 }
71 
UnlockModule(void)72 static void UnlockModule(void)
73 {
74     InterlockedDecrement(&cLocks);
75 }
76 
round_global_size(SIZE_T size)77 static SIZE_T round_global_size(SIZE_T size)
78 {
79     static SIZE_T global_size_alignment = -1;
80     if (global_size_alignment == -1)
81     {
82         void *p = GlobalAlloc(GMEM_FIXED, 1);
83         global_size_alignment = GlobalSize(p);
84         GlobalFree(p);
85     }
86 
87     return ((size + global_size_alignment - 1) & ~(global_size_alignment - 1));
88 }
89 
90 static DWORD external_connections;
91 
ExternalConnection_QueryInterface(IExternalConnection * iface,REFIID riid,void ** ppv)92 static HRESULT WINAPI ExternalConnection_QueryInterface(IExternalConnection *iface, REFIID riid, void **ppv)
93 {
94     ok(0, "unexpected call\n");
95     *ppv = NULL;
96     return E_NOINTERFACE;
97 }
98 
ExternalConnection_AddRef(IExternalConnection * iface)99 static ULONG WINAPI ExternalConnection_AddRef(IExternalConnection *iface)
100 {
101     return 2;
102 }
103 
ExternalConnection_Release(IExternalConnection * iface)104 static ULONG WINAPI ExternalConnection_Release(IExternalConnection *iface)
105 {
106     return 1;
107 }
108 
ExternalConnection_AddConnection(IExternalConnection * iface,DWORD extconn,DWORD reserved)109 static DWORD WINAPI ExternalConnection_AddConnection(IExternalConnection *iface, DWORD extconn, DWORD reserved)
110 {
111     trace("add connection\n");
112 
113     ok(extconn == EXTCONN_STRONG, "extconn = %d\n", extconn);
114     ok(!reserved, "reserved = %x\n", reserved);
115     return ++external_connections;
116 }
117 
ExternalConnection_ReleaseConnection(IExternalConnection * iface,DWORD extconn,DWORD reserved,BOOL fLastReleaseCloses)118 static DWORD WINAPI ExternalConnection_ReleaseConnection(IExternalConnection *iface, DWORD extconn,
119         DWORD reserved, BOOL fLastReleaseCloses)
120 {
121     trace("release connection\n");
122 
123     ok(extconn == EXTCONN_STRONG, "extconn = %d\n", extconn);
124     ok(!reserved, "reserved = %x\n", reserved);
125 
126     return --external_connections;
127 }
128 
129 static const IExternalConnectionVtbl ExternalConnectionVtbl = {
130     ExternalConnection_QueryInterface,
131     ExternalConnection_AddRef,
132     ExternalConnection_Release,
133     ExternalConnection_AddConnection,
134     ExternalConnection_ReleaseConnection
135 };
136 
137 static IExternalConnection ExternalConnection = { &ExternalConnectionVtbl };
138 
Test_IClassFactory_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID * ppvObj)139 static HRESULT WINAPI Test_IClassFactory_QueryInterface(
140     LPCLASSFACTORY iface,
141     REFIID riid,
142     LPVOID *ppvObj)
143 {
144     if (ppvObj == NULL) return E_POINTER;
145 
146     if (IsEqualGUID(riid, &IID_IUnknown) ||
147         IsEqualGUID(riid, &IID_IClassFactory))
148     {
149         *ppvObj = iface;
150         IClassFactory_AddRef(iface);
151         return S_OK;
152     }
153 
154     if(IsEqualGUID(riid, &IID_IExternalConnection)) {
155         *ppvObj = &ExternalConnection;
156         return S_OK;
157     }
158 
159     *ppvObj = NULL;
160     return E_NOINTERFACE;
161 }
162 
Test_IClassFactory_AddRef(LPCLASSFACTORY iface)163 static ULONG WINAPI Test_IClassFactory_AddRef(LPCLASSFACTORY iface)
164 {
165     LockModule();
166     return 2; /* non-heap-based object */
167 }
168 
Test_IClassFactory_Release(LPCLASSFACTORY iface)169 static ULONG WINAPI Test_IClassFactory_Release(LPCLASSFACTORY iface)
170 {
171     UnlockModule();
172     return 1; /* non-heap-based object */
173 }
174 
Test_IClassFactory_CreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pUnkOuter,REFIID riid,LPVOID * ppvObj)175 static HRESULT WINAPI Test_IClassFactory_CreateInstance(
176     LPCLASSFACTORY iface,
177     LPUNKNOWN pUnkOuter,
178     REFIID riid,
179     LPVOID *ppvObj)
180 {
181     return E_NOTIMPL;
182 }
183 
Test_IClassFactory_LockServer(LPCLASSFACTORY iface,BOOL fLock)184 static HRESULT WINAPI Test_IClassFactory_LockServer(
185     LPCLASSFACTORY iface,
186     BOOL fLock)
187 {
188     return S_OK;
189 }
190 
191 static const IClassFactoryVtbl TestClassFactory_Vtbl =
192 {
193     Test_IClassFactory_QueryInterface,
194     Test_IClassFactory_AddRef,
195     Test_IClassFactory_Release,
196     Test_IClassFactory_CreateInstance,
197     Test_IClassFactory_LockServer
198 };
199 
200 static IClassFactory Test_ClassFactory = { &TestClassFactory_Vtbl };
201 
202 typedef struct
203 {
204     IUnknown IUnknown_iface;
205     ULONG refs;
206 } HeapUnknown;
207 
impl_from_IUnknown(IUnknown * iface)208 static inline HeapUnknown *impl_from_IUnknown(IUnknown *iface)
209 {
210     return CONTAINING_RECORD(iface, HeapUnknown, IUnknown_iface);
211 }
212 
HeapUnknown_QueryInterface(IUnknown * iface,REFIID riid,void ** ppv)213 static HRESULT WINAPI HeapUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
214 {
215     if (IsEqualIID(riid, &IID_IUnknown))
216     {
217         IUnknown_AddRef(iface);
218         *ppv = iface;
219         return S_OK;
220     }
221     *ppv = NULL;
222     return E_NOINTERFACE;
223 }
224 
HeapUnknown_AddRef(IUnknown * iface)225 static ULONG WINAPI HeapUnknown_AddRef(IUnknown *iface)
226 {
227     HeapUnknown *This = impl_from_IUnknown(iface);
228     return InterlockedIncrement((LONG*)&This->refs);
229 }
230 
HeapUnknown_Release(IUnknown * iface)231 static ULONG WINAPI HeapUnknown_Release(IUnknown *iface)
232 {
233     HeapUnknown *This = impl_from_IUnknown(iface);
234     ULONG refs = InterlockedDecrement((LONG*)&This->refs);
235     if (!refs) HeapFree(GetProcessHeap(), 0, This);
236     return refs;
237 }
238 
239 static const IUnknownVtbl HeapUnknown_Vtbl =
240 {
241     HeapUnknown_QueryInterface,
242     HeapUnknown_AddRef,
243     HeapUnknown_Release
244 };
245 
246 static HRESULT WINAPI
MonikerNoROTData_QueryInterface(IMoniker * iface,REFIID riid,void ** ppvObject)247 MonikerNoROTData_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
248 {
249     if (!ppvObject)
250         return E_INVALIDARG;
251 
252     *ppvObject = 0;
253 
254     if (IsEqualIID(&IID_IUnknown, riid)      ||
255         IsEqualIID(&IID_IPersist, riid)      ||
256         IsEqualIID(&IID_IPersistStream,riid) ||
257         IsEqualIID(&IID_IMoniker, riid))
258         *ppvObject = iface;
259     if (IsEqualIID(&IID_IROTData, riid))
260         CHECK_EXPECTED_METHOD("Moniker_QueryInterface(IID_IROTData)");
261 
262     if ((*ppvObject)==0)
263         return E_NOINTERFACE;
264 
265     IMoniker_AddRef(iface);
266 
267     return S_OK;
268 }
269 
270 static ULONG WINAPI
Moniker_AddRef(IMoniker * iface)271 Moniker_AddRef(IMoniker* iface)
272 {
273     return 2;
274 }
275 
276 static ULONG WINAPI
Moniker_Release(IMoniker * iface)277 Moniker_Release(IMoniker* iface)
278 {
279     return 1;
280 }
281 
282 static HRESULT WINAPI
Moniker_GetClassID(IMoniker * iface,CLSID * pClassID)283 Moniker_GetClassID(IMoniker* iface, CLSID *pClassID)
284 {
285     CHECK_EXPECTED_METHOD("Moniker_GetClassID");
286 
287     *pClassID = CLSID_TestMoniker;
288 
289     return S_OK;
290 }
291 
292 static HRESULT WINAPI
Moniker_IsDirty(IMoniker * iface)293 Moniker_IsDirty(IMoniker* iface)
294 {
295     CHECK_EXPECTED_METHOD("Moniker_IsDirty");
296 
297     return S_FALSE;
298 }
299 
300 static HRESULT WINAPI
Moniker_Load(IMoniker * iface,IStream * pStm)301 Moniker_Load(IMoniker* iface, IStream* pStm)
302 {
303     CHECK_EXPECTED_METHOD("Moniker_Load");
304     return E_NOTIMPL;
305 }
306 
307 static HRESULT WINAPI
Moniker_Save(IMoniker * iface,IStream * pStm,BOOL fClearDirty)308 Moniker_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty)
309 {
310     CHECK_EXPECTED_METHOD("Moniker_Save");
311     return E_NOTIMPL;
312 }
313 
314 static HRESULT WINAPI
Moniker_GetSizeMax(IMoniker * iface,ULARGE_INTEGER * pcbSize)315 Moniker_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize)
316 {
317     CHECK_EXPECTED_METHOD("Moniker_GetSizeMax");
318     return E_NOTIMPL;
319 }
320 
321 static HRESULT WINAPI
Moniker_BindToObject(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,REFIID riid,VOID ** ppvResult)322 Moniker_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
323                              REFIID riid, VOID** ppvResult)
324 {
325     CHECK_EXPECTED_METHOD("Moniker_BindToObject");
326     return E_NOTIMPL;
327 }
328 
329 static HRESULT WINAPI
Moniker_BindToStorage(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,REFIID riid,VOID ** ppvObject)330 Moniker_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
331                               REFIID riid, VOID** ppvObject)
332 {
333     CHECK_EXPECTED_METHOD("Moniker_BindToStorage");
334     return E_NOTIMPL;
335 }
336 
337 static HRESULT WINAPI
Moniker_Reduce(IMoniker * iface,IBindCtx * pbc,DWORD dwReduceHowFar,IMoniker ** ppmkToLeft,IMoniker ** ppmkReduced)338 Moniker_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
339                        IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
340 {
341     CHECK_EXPECTED_METHOD("Moniker_Reduce");
342 
343     if (ppmkReduced==NULL)
344         return E_POINTER;
345 
346     IMoniker_AddRef(iface);
347 
348     *ppmkReduced=iface;
349 
350     return MK_S_REDUCED_TO_SELF;
351 }
352 
353 static HRESULT WINAPI
Moniker_ComposeWith(IMoniker * iface,IMoniker * pmkRight,BOOL fOnlyIfNotGeneric,IMoniker ** ppmkComposite)354 Moniker_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
355                             BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
356 {
357     CHECK_EXPECTED_METHOD("Moniker_ComposeWith");
358     return E_NOTIMPL;
359 }
360 
361 static HRESULT WINAPI
Moniker_Enum(IMoniker * iface,BOOL fForward,IEnumMoniker ** ppenumMoniker)362 Moniker_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
363 {
364     CHECK_EXPECTED_METHOD("Moniker_Enum");
365 
366     if (ppenumMoniker == NULL)
367         return E_POINTER;
368 
369     *ppenumMoniker = NULL;
370 
371     return S_OK;
372 }
373 
374 static HRESULT WINAPI
Moniker_IsEqual(IMoniker * iface,IMoniker * pmkOtherMoniker)375 Moniker_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
376 {
377     CHECK_EXPECTED_METHOD("Moniker_IsEqual");
378     return E_NOTIMPL;
379 }
380 
381 static HRESULT WINAPI
Moniker_Hash(IMoniker * iface,DWORD * pdwHash)382 Moniker_Hash(IMoniker* iface,DWORD* pdwHash)
383 {
384     CHECK_EXPECTED_METHOD("Moniker_Hash");
385     return E_NOTIMPL;
386 }
387 
388 static HRESULT WINAPI
Moniker_IsRunning(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,IMoniker * pmkNewlyRunning)389 Moniker_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
390                           IMoniker* pmkNewlyRunning)
391 {
392     CHECK_EXPECTED_METHOD("Moniker_IsRunning");
393     return E_NOTIMPL;
394 }
395 
396 static HRESULT WINAPI
Moniker_GetTimeOfLastChange(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,FILETIME * pFileTime)397 Moniker_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
398                                     IMoniker* pmkToLeft, FILETIME* pFileTime)
399 {
400     CHECK_EXPECTED_METHOD("Moniker_GetTimeOfLastChange");
401     return E_NOTIMPL;
402 }
403 
404 static HRESULT WINAPI
Moniker_Inverse(IMoniker * iface,IMoniker ** ppmk)405 Moniker_Inverse(IMoniker* iface,IMoniker** ppmk)
406 {
407     CHECK_EXPECTED_METHOD("Moniker_Inverse");
408     return E_NOTIMPL;
409 }
410 
411 static HRESULT WINAPI
Moniker_CommonPrefixWith(IMoniker * iface,IMoniker * pmkOther,IMoniker ** ppmkPrefix)412 Moniker_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
413 {
414     CHECK_EXPECTED_METHOD("Moniker_CommonPrefixWith");
415     return E_NOTIMPL;
416 }
417 
418 static HRESULT WINAPI
Moniker_RelativePathTo(IMoniker * iface,IMoniker * pmOther,IMoniker ** ppmkRelPath)419 Moniker_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
420 {
421     CHECK_EXPECTED_METHOD("Moniker_RelativePathTo");
422     return E_NOTIMPL;
423 }
424 
425 static HRESULT WINAPI
Moniker_GetDisplayName(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,LPOLESTR * ppszDisplayName)426 Moniker_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
427                                IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
428 {
429     static const WCHAR wszDisplayName[] = {'*','*','G','e','m','m','a',0};
430     CHECK_EXPECTED_METHOD("Moniker_GetDisplayName");
431     *ppszDisplayName = CoTaskMemAlloc(sizeof(wszDisplayName));
432     memcpy(*ppszDisplayName, wszDisplayName, sizeof(wszDisplayName));
433     return S_OK;
434 }
435 
436 static HRESULT WINAPI
Moniker_ParseDisplayName(IMoniker * iface,IBindCtx * pbc,IMoniker * pmkToLeft,LPOLESTR pszDisplayName,ULONG * pchEaten,IMoniker ** ppmkOut)437 Moniker_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft,
438                      LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut)
439 {
440     CHECK_EXPECTED_METHOD("Moniker_ParseDisplayName");
441     return E_NOTIMPL;
442 }
443 
444 static HRESULT WINAPI
Moniker_IsSystemMoniker(IMoniker * iface,DWORD * pwdMksys)445 Moniker_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
446 {
447     CHECK_EXPECTED_METHOD("Moniker_IsSystemMoniker");
448 
449     if (!pwdMksys)
450         return E_POINTER;
451 
452     (*pwdMksys)=MKSYS_NONE;
453 
454     return S_FALSE;
455 }
456 
457 static const IMonikerVtbl MonikerNoROTDataVtbl =
458 {
459     MonikerNoROTData_QueryInterface,
460     Moniker_AddRef,
461     Moniker_Release,
462     Moniker_GetClassID,
463     Moniker_IsDirty,
464     Moniker_Load,
465     Moniker_Save,
466     Moniker_GetSizeMax,
467     Moniker_BindToObject,
468     Moniker_BindToStorage,
469     Moniker_Reduce,
470     Moniker_ComposeWith,
471     Moniker_Enum,
472     Moniker_IsEqual,
473     Moniker_Hash,
474     Moniker_IsRunning,
475     Moniker_GetTimeOfLastChange,
476     Moniker_Inverse,
477     Moniker_CommonPrefixWith,
478     Moniker_RelativePathTo,
479     Moniker_GetDisplayName,
480     Moniker_ParseDisplayName,
481     Moniker_IsSystemMoniker
482 };
483 
484 static IMoniker MonikerNoROTData = { &MonikerNoROTDataVtbl };
485 
486 static IMoniker Moniker;
487 
488 static HRESULT WINAPI
ROTData_QueryInterface(IROTData * iface,REFIID riid,VOID ** ppvObject)489 ROTData_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
490 {
491     return IMoniker_QueryInterface(&Moniker, riid, ppvObject);
492 }
493 
494 static ULONG WINAPI
ROTData_AddRef(IROTData * iface)495 ROTData_AddRef(IROTData *iface)
496 {
497     return 2;
498 }
499 
500 static ULONG WINAPI
ROTData_Release(IROTData * iface)501 ROTData_Release(IROTData* iface)
502 {
503     return 1;
504 }
505 
506 static HRESULT WINAPI
ROTData_GetComparisonData(IROTData * iface,BYTE * pbData,ULONG cbMax,ULONG * pcbData)507 ROTData_GetComparisonData(IROTData* iface, BYTE* pbData,
508                                           ULONG cbMax, ULONG* pcbData)
509 {
510     CHECK_EXPECTED_METHOD("ROTData_GetComparisonData");
511 
512     *pcbData = 1;
513     if (cbMax < *pcbData)
514         return E_OUTOFMEMORY;
515 
516     *pbData = 0xde;
517 
518     return S_OK;
519 }
520 
521 static IROTDataVtbl ROTDataVtbl =
522 {
523     ROTData_QueryInterface,
524     ROTData_AddRef,
525     ROTData_Release,
526     ROTData_GetComparisonData
527 };
528 
529 static IROTData ROTData = { &ROTDataVtbl };
530 
531 static HRESULT WINAPI
Moniker_QueryInterface(IMoniker * iface,REFIID riid,void ** ppvObject)532 Moniker_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
533 {
534     if (!ppvObject)
535         return E_INVALIDARG;
536 
537     *ppvObject = 0;
538 
539     if (IsEqualIID(&IID_IUnknown, riid)      ||
540         IsEqualIID(&IID_IPersist, riid)      ||
541         IsEqualIID(&IID_IPersistStream,riid) ||
542         IsEqualIID(&IID_IMoniker, riid))
543         *ppvObject = iface;
544     if (IsEqualIID(&IID_IROTData, riid))
545     {
546         CHECK_EXPECTED_METHOD("Moniker_QueryInterface(IID_IROTData)");
547         *ppvObject = &ROTData;
548     }
549 
550     if ((*ppvObject)==0)
551         return E_NOINTERFACE;
552 
553     IMoniker_AddRef(iface);
554 
555     return S_OK;
556 }
557 
558 static const IMonikerVtbl MonikerVtbl =
559 {
560     Moniker_QueryInterface,
561     Moniker_AddRef,
562     Moniker_Release,
563     Moniker_GetClassID,
564     Moniker_IsDirty,
565     Moniker_Load,
566     Moniker_Save,
567     Moniker_GetSizeMax,
568     Moniker_BindToObject,
569     Moniker_BindToStorage,
570     Moniker_Reduce,
571     Moniker_ComposeWith,
572     Moniker_Enum,
573     Moniker_IsEqual,
574     Moniker_Hash,
575     Moniker_IsRunning,
576     Moniker_GetTimeOfLastChange,
577     Moniker_Inverse,
578     Moniker_CommonPrefixWith,
579     Moniker_RelativePathTo,
580     Moniker_GetDisplayName,
581     Moniker_ParseDisplayName,
582     Moniker_IsSystemMoniker
583 };
584 
585 static IMoniker Moniker = { &MonikerVtbl };
586 
test_ROT(void)587 static void test_ROT(void)
588 {
589     static const WCHAR wszFileName[] = {'B','E','2','0','E','2','F','5','-',
590         '1','9','0','3','-','4','A','A','E','-','B','1','A','F','-',
591         '2','0','4','6','E','5','8','6','C','9','2','5',0};
592     HRESULT hr;
593     IMoniker *pMoniker = NULL;
594     IRunningObjectTable *pROT = NULL;
595     DWORD dwCookie;
596     static const char *methods_register_no_ROTData[] =
597     {
598         "Moniker_Reduce",
599         "Moniker_GetTimeOfLastChange",
600         "Moniker_QueryInterface(IID_IROTData)",
601         "Moniker_GetDisplayName",
602         "Moniker_GetClassID",
603         NULL
604     };
605     static const char *methods_register[] =
606     {
607         "Moniker_Reduce",
608         "Moniker_GetTimeOfLastChange",
609         "Moniker_QueryInterface(IID_IROTData)",
610         "ROTData_GetComparisonData",
611         NULL
612     };
613     static const char *methods_isrunning_no_ROTData[] =
614     {
615         "Moniker_Reduce",
616         "Moniker_QueryInterface(IID_IROTData)",
617         "Moniker_GetDisplayName",
618         "Moniker_GetClassID",
619         NULL
620     };
621     static const char *methods_isrunning[] =
622     {
623         "Moniker_Reduce",
624         "Moniker_QueryInterface(IID_IROTData)",
625         "ROTData_GetComparisonData",
626         NULL
627     };
628 
629     cLocks = 0;
630 
631     hr = GetRunningObjectTable(0, &pROT);
632     ok_ole_success(hr, GetRunningObjectTable);
633 
634     expected_method_list = methods_register_no_ROTData;
635     external_connections = 0;
636     /* try with our own moniker that doesn't support IROTData */
637     hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE,
638         (IUnknown*)&Test_ClassFactory, &MonikerNoROTData, &dwCookie);
639     ok_ole_success(hr, IRunningObjectTable_Register);
640     ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
641     ok(external_connections == 1, "external_connections = %d\n", external_connections);
642 
643     ok_more_than_one_lock();
644 
645     expected_method_list = methods_isrunning_no_ROTData;
646     hr = IRunningObjectTable_IsRunning(pROT, &MonikerNoROTData);
647     ok_ole_success(hr, IRunningObjectTable_IsRunning);
648     ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
649 
650     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
651     ok_ole_success(hr, IRunningObjectTable_Revoke);
652     ok(external_connections == 0, "external_connections = %d\n", external_connections);
653 
654     ok_no_locks();
655 
656     expected_method_list = methods_register;
657     /* try with our own moniker */
658     hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE,
659         (IUnknown*)&Test_ClassFactory, &Moniker, &dwCookie);
660     ok_ole_success(hr, IRunningObjectTable_Register);
661     ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
662 
663     ok_more_than_one_lock();
664 
665     expected_method_list = methods_isrunning;
666     hr = IRunningObjectTable_IsRunning(pROT, &Moniker);
667     ok_ole_success(hr, IRunningObjectTable_IsRunning);
668     ok(!*expected_method_list, "Method sequence starting from %s not called\n", *expected_method_list);
669 
670     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
671     ok_ole_success(hr, IRunningObjectTable_Revoke);
672 
673     ok_no_locks();
674 
675     hr = CreateFileMoniker(wszFileName, &pMoniker);
676     ok_ole_success(hr, CreateClassMoniker);
677 
678     /* test flags: 0 */
679     external_connections = 0;
680     hr = IRunningObjectTable_Register(pROT, 0, (IUnknown*)&Test_ClassFactory,
681                                       pMoniker, &dwCookie);
682     ok_ole_success(hr, IRunningObjectTable_Register);
683     ok(external_connections == 0, "external_connections = %d\n", external_connections);
684 
685     ok_more_than_one_lock();
686 
687     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
688     ok_ole_success(hr, IRunningObjectTable_Revoke);
689 
690     ok_no_locks();
691 
692     /* test flags: ROTFLAGS_REGISTRATIONKEEPSALIVE */
693     hr = IRunningObjectTable_Register(pROT, ROTFLAGS_REGISTRATIONKEEPSALIVE,
694         (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
695     ok_ole_success(hr, IRunningObjectTable_Register);
696 
697     ok_more_than_one_lock();
698 
699     hr = IRunningObjectTable_Revoke(pROT, dwCookie);
700     ok_ole_success(hr, IRunningObjectTable_Revoke);
701 
702     ok_no_locks();
703 
704     /* test flags: ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT */
705     /* only succeeds when process is started by SCM and has LocalService
706      * or RunAs AppId values */
707     hr = IRunningObjectTable_Register(pROT,
708         ROTFLAGS_REGISTRATIONKEEPSALIVE|ROTFLAGS_ALLOWANYCLIENT,
709         (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
710     todo_wine {
711     ok(hr == CO_E_WRONG_SERVER_IDENTITY ||
712        broken(hr == S_OK) /* Win9x */,
713        "IRunningObjectTable_Register should have returned CO_E_WRONG_SERVER_IDENTITY instead of 0x%08x\n", hr);
714     }
715     if (hr == S_OK) IRunningObjectTable_Revoke(pROT, dwCookie);
716 
717     hr = IRunningObjectTable_Register(pROT, 0xdeadbeef,
718         (IUnknown*)&Test_ClassFactory, pMoniker, &dwCookie);
719     ok(hr == E_INVALIDARG, "IRunningObjectTable_Register should have returned E_INVALIDARG instead of 0x%08x\n", hr);
720 
721     IMoniker_Release(pMoniker);
722 
723     IRunningObjectTable_Release(pROT);
724 }
725 
test_ROT_multiple_entries(void)726 static void test_ROT_multiple_entries(void)
727 {
728     HRESULT hr;
729     IMoniker *pMoniker = NULL;
730     IRunningObjectTable *pROT = NULL;
731     DWORD dwCookie1, dwCookie2;
732     IUnknown *pObject = NULL;
733     static const WCHAR moniker_path[] =
734         {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0};
735 
736     hr = GetRunningObjectTable(0, &pROT);
737     ok_ole_success(hr, GetRunningObjectTable);
738 
739     hr = CreateFileMoniker(moniker_path, &pMoniker);
740     ok_ole_success(hr, CreateFileMoniker);
741 
742     hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&Test_ClassFactory, pMoniker, &dwCookie1);
743     ok_ole_success(hr, IRunningObjectTable_Register);
744 
745     hr = IRunningObjectTable_Register(pROT, 0, (IUnknown *)&Test_ClassFactory, pMoniker, &dwCookie2);
746     ok(hr == MK_S_MONIKERALREADYREGISTERED, "IRunningObjectTable_Register should have returned MK_S_MONIKERALREADYREGISTERED instead of 0x%08x\n", hr);
747 
748     ok(dwCookie1 != dwCookie2, "cookie returned for registering duplicate object shouldn't match cookie of original object (0x%x)\n", dwCookie1);
749 
750     hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject);
751     ok_ole_success(hr, IRunningObjectTable_GetObject);
752     IUnknown_Release(pObject);
753 
754     hr = IRunningObjectTable_Revoke(pROT, dwCookie1);
755     ok_ole_success(hr, IRunningObjectTable_Revoke);
756 
757     hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject);
758     ok_ole_success(hr, IRunningObjectTable_GetObject);
759     IUnknown_Release(pObject);
760 
761     hr = IRunningObjectTable_Revoke(pROT, dwCookie2);
762     ok_ole_success(hr, IRunningObjectTable_Revoke);
763 
764     IMoniker_Release(pMoniker);
765 
766     IRunningObjectTable_Release(pROT);
767 }
768 
ParseDisplayName_QueryInterface(IParseDisplayName * iface,REFIID riid,void ** ppv)769 static HRESULT WINAPI ParseDisplayName_QueryInterface(IParseDisplayName *iface, REFIID riid, void **ppv)
770 {
771     if (IsEqualIID(riid, &IID_IUnknown) ||
772         IsEqualIID(riid, &IID_IParseDisplayName))
773     {
774         *ppv = iface;
775         IParseDisplayName_AddRef(iface);
776         return S_OK;
777     }
778     *ppv = NULL;
779     return E_NOINTERFACE;
780 }
781 
ParseDisplayName_AddRef(IParseDisplayName * iface)782 static ULONG WINAPI ParseDisplayName_AddRef(IParseDisplayName *iface)
783 {
784     return 2;
785 }
786 
ParseDisplayName_Release(IParseDisplayName * iface)787 static ULONG WINAPI ParseDisplayName_Release(IParseDisplayName *iface)
788 {
789     return 1;
790 }
791 
792 static LPCWSTR expected_display_name;
793 
ParseDisplayName_ParseDisplayName(IParseDisplayName * iface,IBindCtx * pbc,LPOLESTR pszDisplayName,ULONG * pchEaten,IMoniker ** ppmkOut)794 static HRESULT WINAPI ParseDisplayName_ParseDisplayName(IParseDisplayName *iface,
795                                                         IBindCtx *pbc,
796                                                         LPOLESTR pszDisplayName,
797                                                         ULONG *pchEaten,
798                                                         IMoniker **ppmkOut)
799 {
800     char display_nameA[256];
801     WideCharToMultiByte(CP_ACP, 0, pszDisplayName, -1, display_nameA, sizeof(display_nameA), NULL, NULL);
802     ok(!lstrcmpW(pszDisplayName, expected_display_name), "unexpected display name \"%s\"\n", display_nameA);
803     ok(pszDisplayName == expected_display_name, "pszDisplayName should be the same pointer as passed into MkParseDisplayName\n");
804     *pchEaten = lstrlenW(pszDisplayName);
805     return CreateAntiMoniker(ppmkOut);
806 }
807 
808 static const IParseDisplayNameVtbl ParseDisplayName_Vtbl =
809 {
810     ParseDisplayName_QueryInterface,
811     ParseDisplayName_AddRef,
812     ParseDisplayName_Release,
813     ParseDisplayName_ParseDisplayName
814 };
815 
816 static IParseDisplayName ParseDisplayName = { &ParseDisplayName_Vtbl };
817 
count_moniker_matches(IBindCtx * pbc,IEnumMoniker * spEM)818 static int count_moniker_matches(IBindCtx * pbc, IEnumMoniker * spEM)
819 {
820     IMoniker * spMoniker;
821     int monCnt=0, matchCnt=0;
822 
823     while ((IEnumMoniker_Next(spEM, 1, &spMoniker, NULL)==S_OK))
824     {
825         HRESULT hr;
826         WCHAR * szDisplayn;
827         monCnt++;
828         hr=IMoniker_GetDisplayName(spMoniker, pbc, NULL, &szDisplayn);
829         if (SUCCEEDED(hr))
830         {
831             if (!lstrcmpiW(szDisplayn, wszFileName1) || !lstrcmpiW(szDisplayn, wszFileName2))
832                 matchCnt++;
833             CoTaskMemFree(szDisplayn);
834         }
835     }
836     trace("Total number of monikers is %i\n", monCnt);
837     return matchCnt;
838 }
839 
test_MkParseDisplayName(void)840 static void test_MkParseDisplayName(void)
841 {
842     IBindCtx * pbc = NULL;
843     HRESULT hr;
844     IMoniker * pmk  = NULL;
845     IMoniker * pmk1 = NULL;
846     IMoniker * pmk2 = NULL;
847     ULONG eaten;
848     int matchCnt;
849     IUnknown * object = NULL;
850 
851     IUnknown *lpEM1;
852 
853     IEnumMoniker *spEM1  = NULL;
854     IEnumMoniker *spEM2  = NULL;
855     IEnumMoniker *spEM3  = NULL;
856 
857     DWORD pdwReg1=0;
858     DWORD grflags=0;
859     DWORD pdwReg2=0;
860     DWORD moniker_type;
861     IRunningObjectTable * pprot=NULL;
862 
863     /* CLSID of My Computer */
864     static const WCHAR wszDisplayName[] = {'c','l','s','i','d',':',
865         '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};
866     static const WCHAR wszDisplayNameClsid[] = {'c','l','s','i','d',':',0};
867     static const WCHAR wszNonExistentProgId[] = {'N','o','n','E','x','i','s','t','e','n','t','P','r','o','g','I','d',':',0};
868     static const WCHAR wszDisplayNameRunning[] = {'W','i','n','e','T','e','s','t','R','u','n','n','i','n','g',0};
869     static const WCHAR wszDisplayNameProgId1[] = {'S','t','d','F','o','n','t',':',0};
870     static const WCHAR wszDisplayNameProgId2[] = {'@','S','t','d','F','o','n','t',0};
871     static const WCHAR wszDisplayNameProgIdFail[] = {'S','t','d','F','o','n','t',0};
872     static const WCHAR wszEmpty[] = {0};
873     char szDisplayNameFile[256];
874     WCHAR wszDisplayNameFile[256];
875     int i, len;
876 
877     const struct
878     {
879         LPBC *ppbc;
880         LPCOLESTR szDisplayName;
881         LPDWORD pchEaten;
882         LPMONIKER *ppmk;
883     } invalid_parameters[] =
884     {
885         {NULL,  NULL,     NULL,   NULL},
886         {NULL,  NULL,     NULL,   &pmk},
887         {NULL,  NULL,     &eaten, NULL},
888         {NULL,  NULL,     &eaten, &pmk},
889         {NULL,  wszEmpty, NULL,   NULL},
890         {NULL,  wszEmpty, NULL,   &pmk},
891         {NULL,  wszEmpty, &eaten, NULL},
892         {NULL,  wszEmpty, &eaten, &pmk},
893         {&pbc,  NULL,     NULL,   NULL},
894         {&pbc,  NULL,     NULL,   &pmk},
895         {&pbc,  NULL,     &eaten, NULL},
896         {&pbc,  NULL,     &eaten, &pmk},
897         {&pbc,  wszEmpty, NULL,   NULL},
898         {&pbc,  wszEmpty, NULL,   &pmk},
899         {&pbc,  wszEmpty, &eaten, NULL},
900         {&pbc,  wszEmpty, &eaten, &pmk},
901     };
902 
903     hr = CreateBindCtx(0, &pbc);
904     ok_ole_success(hr, CreateBindCtx);
905 
906     for (i = 0; i < ARRAY_SIZE(invalid_parameters); i++)
907     {
908         eaten = 0xdeadbeef;
909         pmk = (IMoniker *)0xdeadbeef;
910         hr = MkParseDisplayName(invalid_parameters[i].ppbc ? *invalid_parameters[i].ppbc : NULL,
911                                 invalid_parameters[i].szDisplayName,
912                                 invalid_parameters[i].pchEaten,
913                                 invalid_parameters[i].ppmk);
914         ok(hr == E_INVALIDARG, "[%d] MkParseDisplayName should have failed with E_INVALIDARG instead of 0x%08x\n", i, hr);
915         ok(eaten == 0xdeadbeef, "[%d] Processed character count should have been 0xdeadbeef instead of %u\n", i, eaten);
916         ok(pmk == (IMoniker *)0xdeadbeef, "[%d] Output moniker pointer should have been 0xdeadbeef instead of %p\n", i, pmk);
917     }
918 
919     eaten = 0xdeadbeef;
920     pmk = (IMoniker *)0xdeadbeef;
921     hr = MkParseDisplayName(pbc, wszNonExistentProgId, &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     /* no special handling of "clsid:" without the string form of the clsid
928      * following */
929     eaten = 0xdeadbeef;
930     pmk = (IMoniker *)0xdeadbeef;
931     hr = MkParseDisplayName(pbc, wszDisplayNameClsid, &eaten, &pmk);
932     ok(hr == MK_E_SYNTAX || hr == MK_E_CANTOPENFILE /* Win9x */,
933         "MkParseDisplayName should have failed with MK_E_SYNTAX or MK_E_CANTOPENFILE instead of 0x%08x\n", hr);
934     ok(eaten == 0, "Processed character count should have been 0 instead of %u\n", eaten);
935     ok(pmk == NULL, "Output moniker pointer should have been NULL instead of %p\n", pmk);
936 
937     /* shows clsid has higher precedence than a running object */
938     hr = CreateFileMoniker(wszDisplayName, &pmk);
939     ok_ole_success(hr, CreateFileMoniker);
940     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
941     ok_ole_success(hr, IBindCtx_GetRunningObjectTable);
942     hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&Test_ClassFactory, pmk, &pdwReg1);
943     ok_ole_success(hr, IRunningObjectTable_Register);
944     IMoniker_Release(pmk);
945     pmk = NULL;
946     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
947     ok_ole_success(hr, MkParseDisplayName);
948     ok(eaten == ARRAY_SIZE(wszDisplayName) - 1,
949         "Processed character count should have been 43 instead of %u\n", eaten);
950     if (pmk)
951     {
952         IMoniker_IsSystemMoniker(pmk, &moniker_type);
953         ok(moniker_type == MKSYS_CLASSMONIKER, "moniker_type was %d instead of MKSYS_CLASSMONIKER\n", moniker_type);
954         IMoniker_Release(pmk);
955     }
956     hr = IRunningObjectTable_Revoke(pprot, pdwReg1);
957     ok_ole_success(hr, IRunningObjectTable_Revoke);
958     IRunningObjectTable_Release(pprot);
959 
960     hr = CreateFileMoniker(wszDisplayNameRunning, &pmk);
961     ok_ole_success(hr, CreateFileMoniker);
962     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
963     ok_ole_success(hr, IBindCtx_GetRunningObjectTable);
964     hr = IRunningObjectTable_Register(pprot, 0, (IUnknown *)&Test_ClassFactory, pmk, &pdwReg1);
965     ok_ole_success(hr, IRunningObjectTable_Register);
966     IMoniker_Release(pmk);
967     pmk = NULL;
968     hr = MkParseDisplayName(pbc, wszDisplayNameRunning, &eaten, &pmk);
969     ok_ole_success(hr, MkParseDisplayName);
970     ok(eaten == ARRAY_SIZE(wszDisplayNameRunning) - 1,
971         "Processed character count should have been 15 instead of %u\n", eaten);
972     if (pmk)
973     {
974         IMoniker_IsSystemMoniker(pmk, &moniker_type);
975         ok(moniker_type == MKSYS_FILEMONIKER, "moniker_type was %d instead of MKSYS_FILEMONIKER\n", moniker_type);
976         IMoniker_Release(pmk);
977     }
978     hr = IRunningObjectTable_Revoke(pprot, pdwReg1);
979     ok_ole_success(hr, IRunningObjectTable_Revoke);
980     IRunningObjectTable_Release(pprot);
981 
982     hr = CoRegisterClassObject(&CLSID_StdFont, (IUnknown *)&ParseDisplayName, CLSCTX_INPROC_SERVER, REGCLS_MULTI_SEPARATE, &pdwReg1);
983     ok_ole_success(hr, CoRegisterClassObject);
984 
985     expected_display_name = wszDisplayNameProgId1;
986     hr = MkParseDisplayName(pbc, wszDisplayNameProgId1, &eaten, &pmk);
987     ok_ole_success(hr, MkParseDisplayName);
988     ok(eaten == ARRAY_SIZE(wszDisplayNameProgId1) - 1,
989         "Processed character count should have been 8 instead of %u\n", eaten);
990     if (pmk)
991     {
992         IMoniker_IsSystemMoniker(pmk, &moniker_type);
993         ok(moniker_type == MKSYS_ANTIMONIKER, "moniker_type was %d instead of MKSYS_ANTIMONIKER\n", moniker_type);
994         IMoniker_Release(pmk);
995     }
996 
997     expected_display_name = wszDisplayNameProgId2;
998     hr = MkParseDisplayName(pbc, wszDisplayNameProgId2, &eaten, &pmk);
999     ok_ole_success(hr, MkParseDisplayName);
1000     ok(eaten == ARRAY_SIZE(wszDisplayNameProgId2) - 1,
1001         "Processed character count should have been 8 instead of %u\n", eaten);
1002     if (pmk)
1003     {
1004         IMoniker_IsSystemMoniker(pmk, &moniker_type);
1005         ok(moniker_type == MKSYS_ANTIMONIKER, "moniker_type was %d instead of MKSYS_ANTIMONIKER\n", moniker_type);
1006         IMoniker_Release(pmk);
1007     }
1008 
1009     eaten = 0xdeadbeef;
1010     pmk = (IMoniker *)0xdeadbeef;
1011     hr = MkParseDisplayName(pbc, wszDisplayNameProgIdFail, &eaten, &pmk);
1012     ok(hr == MK_E_SYNTAX || hr == MK_E_CANTOPENFILE /* Win9x */,
1013         "MkParseDisplayName with ProgId without marker should fail with MK_E_SYNTAX or MK_E_CANTOPENFILE instead of 0x%08x\n", hr);
1014     ok(eaten == 0, "Processed character count should have been 0 instead of %u\n", eaten);
1015     ok(pmk == NULL, "Output moniker pointer should have been NULL instead of %p\n", pmk);
1016 
1017     hr = CoRevokeClassObject(pdwReg1);
1018     ok_ole_success(hr, CoRevokeClassObject);
1019 
1020     GetSystemDirectoryA(szDisplayNameFile, sizeof(szDisplayNameFile));
1021     strcat(szDisplayNameFile, "\\kernel32.dll");
1022     len = MultiByteToWideChar(CP_ACP, 0, szDisplayNameFile, -1, wszDisplayNameFile,
1023         ARRAY_SIZE(wszDisplayNameFile));
1024     hr = MkParseDisplayName(pbc, wszDisplayNameFile, &eaten, &pmk);
1025     ok_ole_success(hr, MkParseDisplayName);
1026     ok(eaten == len - 1, "Processed character count should have been %d instead of %u\n", len - 1, eaten);
1027     if (pmk)
1028     {
1029         IMoniker_IsSystemMoniker(pmk, &moniker_type);
1030         ok(moniker_type == MKSYS_FILEMONIKER, "moniker_type was %d instead of MKSYS_FILEMONIKER\n", moniker_type);
1031         IMoniker_Release(pmk);
1032     }
1033 
1034     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
1035     ok_ole_success(hr, MkParseDisplayName);
1036     ok(eaten == ARRAY_SIZE(wszDisplayName) - 1,
1037         "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 
test_moniker(const char * testname,IMoniker * moniker,const BYTE * expected_moniker_marshal_data,unsigned int sizeof_expected_moniker_marshal_data,const BYTE * expected_moniker_saved_data,unsigned int sizeof_expected_moniker_saved_data,const BYTE * expected_moniker_comparison_data,unsigned int sizeof_expected_moniker_comparison_data,LPCWSTR expected_display_name)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 
test_class_moniker(void)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 
test_file_moniker(WCHAR * path)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 
test_file_monikers(void)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 < ARRAY_SIZE(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 
test_item_moniker(void)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 
test_anti_moniker(void)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 
test_generic_composite_moniker(void)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 
test_pointer_moniker(void)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 
test_bind_context(void)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 
test_save_load_filemoniker(void)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 
START_TEST(moniker)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