rsaenh: Cast-qual warning fix.
[wine] / dlls / ole32 / tests / moniker.c
1 /*
2  * Moniker Tests
3  *
4  * Copyright 2004 Robert Shearman
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define _WIN32_DCOM
22 #define COBJMACROS
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "objbase.h"
30 #include "comcat.h"
31
32 #include "wine/test.h"
33
34 #define ok_ole_success(hr, func) ok(hr == S_OK, #func " failed with error 0x%08x\n", hr)
35 #define COUNTOF(x) (sizeof(x) / sizeof(x[0]))
36
37 static const WCHAR wszFileName1[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','1','.','d','o','c',0};
38 static const WCHAR wszFileName2[] = {'c',':','\\','w','i','n','d','o','w','s','\\','t','e','s','t','2','.','d','o','c',0};
39
40 static int count_moniker_matches(IBindCtx * pbc, IEnumMoniker * spEM)
41 {
42     IMoniker * spMoniker;
43     int monCnt=0, matchCnt=0;
44
45     while ((IEnumMoniker_Next(spEM, 1, &spMoniker, NULL)==S_OK))
46     {
47         HRESULT hr;
48         WCHAR * szDisplayn;
49         monCnt++;
50         hr=IMoniker_GetDisplayName(spMoniker, pbc, NULL, &szDisplayn);
51         if (SUCCEEDED(hr))
52         {
53             if (!lstrcmpW(szDisplayn, wszFileName1) || !lstrcmpW(szDisplayn, wszFileName2))
54                 matchCnt++;
55             CoTaskMemFree(szDisplayn);
56         }
57     }
58     trace("Total number of monikers is %i\n", monCnt);
59     return matchCnt;
60 }
61
62 static void test_MkParseDisplayName(void)
63 {
64     IBindCtx * pbc = NULL;
65     HRESULT hr;
66     IMoniker * pmk  = NULL;
67     IMoniker * pmk1 = NULL;
68     IMoniker * pmk2 = NULL;
69     ULONG eaten;
70     int matchCnt;
71     IUnknown * object = NULL;
72
73     IUnknown *lpEM1;
74
75     IEnumMoniker *spEM1  = NULL;
76     IEnumMoniker *spEM2  = NULL;
77     IEnumMoniker *spEM3  = NULL;
78
79     DWORD pdwReg1=0;
80     DWORD grflags=0;
81     DWORD pdwReg2=0;
82     IRunningObjectTable * pprot=NULL;
83
84     /* CLSID of My Computer */
85     static const WCHAR wszDisplayName[] = {'c','l','s','i','d',':',
86         '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};
87
88     hr = CreateBindCtx(0, &pbc);
89     ok_ole_success(hr, CreateBindCtx);
90
91     hr = MkParseDisplayName(pbc, wszDisplayName, &eaten, &pmk);
92     todo_wine { ok_ole_success(hr, MkParseDisplayName); }
93
94     if (object)
95     {
96         hr = IMoniker_BindToObject(pmk, pbc, NULL, &IID_IUnknown, (LPVOID*)&object);
97         ok_ole_success(hr, IMoniker_BindToObject);
98
99         IUnknown_Release(object);
100     }
101     IBindCtx_Release(pbc);
102
103     /* Test the EnumMoniker interface */
104     hr = CreateBindCtx(0, &pbc);
105     ok_ole_success(hr, CreateBindCtx);
106
107     hr = CreateFileMoniker(wszFileName1, &pmk1);
108     ok(hr==0, "CreateFileMoniker for file hr=%08x\n", hr);
109     hr = CreateFileMoniker(wszFileName2, &pmk2);
110     ok(hr==0, "CreateFileMoniker for file hr=%08x\n", hr);
111     hr = IBindCtx_GetRunningObjectTable(pbc, &pprot);
112     ok(hr==0, "IBindCtx_GetRunningObjectTable hr=%08x\n", hr);
113
114     /* Check EnumMoniker before registering */
115     hr = IRunningObjectTable_EnumRunning(pprot, &spEM1);
116     ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr);
117     hr = IEnumMoniker_QueryInterface(spEM1, &IID_IUnknown, (void*) &lpEM1);
118     /* Register a couple of Monikers and check is ok */
119     ok(hr==0, "IEnumMoniker_QueryInterface hr %08x %p\n", hr, lpEM1);
120     hr = MK_E_NOOBJECT;
121     
122     matchCnt = count_moniker_matches(pbc, spEM1);
123     trace("Number of matches is %i\n", matchCnt);
124
125     grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE;
126     hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk1, &pdwReg1);
127     ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n",
128         hr, pprot, grflags, lpEM1, pmk1, pdwReg1);
129
130     trace("IROT::Register\n");
131     grflags=0;
132     grflags= grflags | ROTFLAGS_REGISTRATIONKEEPSALIVE;
133     hr = IRunningObjectTable_Register(pprot, grflags, lpEM1, pmk2, &pdwReg2);
134     ok(hr==0, "IRunningObjectTable_Register hr=%08x %p %08x %p %p %d\n", hr,
135        pprot, grflags, lpEM1, pmk2, pdwReg2);
136
137     hr = IRunningObjectTable_EnumRunning(pprot, &spEM2);
138     ok(hr==0, "IRunningObjectTable_EnumRunning hr=%08x\n", hr);
139
140     matchCnt = count_moniker_matches(pbc, spEM2);
141     ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
142
143     trace("IEnumMoniker::Clone\n");
144     IEnumMoniker_Clone(spEM2, &spEM3);
145
146     matchCnt = count_moniker_matches(pbc, spEM3);
147     ok(matchCnt==0, "Number of matches should be equal to 0 not %i\n", matchCnt);
148     trace("IEnumMoniker::Reset\n");
149     IEnumMoniker_Reset(spEM3);
150
151     matchCnt = count_moniker_matches(pbc, spEM3);
152     ok(matchCnt==2, "Number of matches should be equal to 2 not %i\n", matchCnt);
153
154     IRunningObjectTable_Revoke(pprot,pdwReg1);
155     IRunningObjectTable_Revoke(pprot,pdwReg2);
156     IEnumMoniker_Release(spEM1);
157     IEnumMoniker_Release(spEM1);
158     IEnumMoniker_Release(spEM2);
159     IEnumMoniker_Release(spEM3);
160     IMoniker_Release(pmk1);
161     IMoniker_Release(pmk2);
162     IRunningObjectTable_Release(pprot);
163
164     IBindCtx_Release(pbc);
165 }
166
167 static const LARGE_INTEGER llZero;
168
169 static const BYTE expected_class_moniker_marshal_data[] =
170 {
171     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
172     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
173     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
174     0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
175     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
176     0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
177     0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
178     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
179     0x00,0x00,0x00,0x00,
180 };
181
182 static const BYTE expected_class_moniker_saved_data[] =
183 {
184      0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
185      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
186      0x00,0x00,0x00,0x00,
187 };
188
189 static const BYTE expected_class_moniker_comparison_data[] =
190 {
191      0x1a,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
192      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
193      0x05,0xe0,0x02,0x00,0x00,0x00,0x00,0x00,
194      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
195 };
196
197 static const WCHAR expected_class_moniker_display_name[] =
198 {
199     'c','l','s','i','d',':','0','0','0','2','E','0','0','5','-','0','0','0',
200     '0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0',
201     '0','0','0','0','4','6',':',0
202 };
203
204 static const BYTE expected_item_moniker_comparison_data[] =
205 {
206      0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
207      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
208      0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00,
209      0x54,0x00,0x00,0x00,
210 };
211
212 static const BYTE expected_item_moniker_saved_data[] =
213 {
214      0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
215      0x00,0x00,0x54,0x65,0x73,0x74,0x00,
216 };
217
218 static const BYTE expected_item_moniker_marshal_data[] =
219 {
220      0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
221      0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
222      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
223      0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
224      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
225      0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
226      0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
227      0x00,0x00,0x54,0x65,0x73,0x74,0x00,
228 };
229
230 static const BYTE expected_anti_moniker_marshal_data[] =
231 {
232     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
233     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
234     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
235     0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
236     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
237     0x00,0x00,0x00,0x00,0x14,0x00,0x00,0x00,
238     0x01,0x00,0x00,0x00,
239 };
240
241 static const BYTE expected_anti_moniker_saved_data[] =
242 {
243     0x01,0x00,0x00,0x00,
244 };
245
246 static const BYTE expected_anti_moniker_comparison_data[] =
247 {
248     0x05,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
249     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
250     0x01,0x00,0x00,0x00,
251 };
252
253 static const BYTE expected_gc_moniker_marshal_data[] =
254 {
255     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
256     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
257     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
258     0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
259     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
260     0x00,0x00,0x00,0x00,0x2c,0x01,0x00,0x00,
261     0x4d,0x45,0x4f,0x57,0x04,0x00,0x00,0x00,
262     0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
263     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
264     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
265     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
266     0x00,0x00,0x00,0x00,0x36,0x00,0x00,0x00,
267     0x02,0x00,0x00,0x00,0x21,0x00,0x05,0x00,
268     0x00,0x00,0x54,0x65,0x73,0x74,0x00,0x4d,
269     0x45,0x4f,0x57,0x04,0x00,0x00,0x00,0x0f,
270     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
271     0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x04,
272     0x03,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,
273     0x00,0x00,0x00,0x00,0x00,0x00,0x46,0x00,
274     0x00,0x00,0x00,0x36,0x00,0x00,0x00,0x02,
275     0x00,0x00,0x00,0x23,0x00,0x05,0x00,0x00,
276     0x00,0x57,0x69,0x6e,0x65,0x00,
277 };
278
279 static const BYTE expected_gc_moniker_saved_data[] =
280 {
281     0x02,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
282     0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
283     0x00,0x00,0x00,0x46,0x02,0x00,0x00,0x00,
284     0x21,0x00,0x05,0x00,0x00,0x00,0x54,0x65,
285     0x73,0x74,0x00,0x04,0x03,0x00,0x00,0x00,
286     0x00,0x00,0x00,0xc0,0x00,0x00,0x00,0x00,
287     0x00,0x00,0x46,0x02,0x00,0x00,0x00,0x23,
288     0x00,0x05,0x00,0x00,0x00,0x57,0x69,0x6e,
289     0x65,0x00,
290 };
291
292 static const BYTE expected_gc_moniker_comparison_data[] =
293 {
294     0x09,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
295     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
296     0x04,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
297     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
298     0x21,0x00,0x54,0x00,0x45,0x00,0x53,0x00,
299     0x54,0x00,0x00,0x00,0x04,0x03,0x00,0x00,
300     0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0x00,
301     0x00,0x00,0x00,0x46,0x23,0x00,0x57,0x00,
302     0x49,0x00,0x4e,0x00,0x45,0x00,0x00,0x00,
303 };
304
305 static void test_moniker(
306     const char *testname, IMoniker *moniker,
307     const BYTE *expected_moniker_marshal_data, unsigned int sizeof_expected_moniker_marshal_data,
308     const BYTE *expected_moniker_saved_data, unsigned int sizeof_expected_moniker_saved_data,
309     const BYTE *expected_moniker_comparison_data, unsigned int sizeof_expected_moniker_comparison_data,
310     LPCWSTR expected_display_name)
311 {
312     IStream * stream;
313     IROTData * rotdata;
314     HRESULT hr;
315     HGLOBAL hglobal;
316     LPBYTE moniker_data;
317     DWORD moniker_size;
318     DWORD i;
319     BOOL same = TRUE;
320     BYTE buffer[128];
321     IMoniker * moniker_proxy;
322     LPOLESTR display_name;
323     IBindCtx *bindctx;
324
325     hr = IMoniker_IsDirty(moniker);
326     ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr);
327
328     /* Display Name */
329
330     hr = CreateBindCtx(0, &bindctx);
331     ok_ole_success(hr, CreateBindCtx);
332
333     hr = IMoniker_GetDisplayName(moniker, bindctx, NULL, &display_name);
334     ok_ole_success(hr, IMoniker_GetDisplayName);
335         ok(!lstrcmpW(display_name, expected_display_name), "display name wasn't what was expected\n");
336
337     CoTaskMemFree(display_name);
338     IBindCtx_Release(bindctx);
339
340     hr = IMoniker_IsDirty(moniker);
341     ok(hr == S_FALSE, "%s: IMoniker_IsDirty should return S_FALSE, not 0x%08x\n", testname, hr);
342
343     /* IROTData::GetComparisonData test */
344
345     hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
346     ok_ole_success(hr, IMoniker_QueryInterface_IID_IROTData);
347
348     hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &moniker_size);
349     ok_ole_success(hr, IROTData_GetComparisonData);
350
351     if (hr != S_OK) moniker_size = 0;
352
353     /* first check we have the right amount of data */
354     ok(moniker_size == sizeof_expected_moniker_comparison_data,
355         "%s: Size of comparison data differs (expected %d, actual %d)\n",
356         testname, sizeof_expected_moniker_comparison_data, moniker_size);
357
358     /* then do a byte-by-byte comparison */
359     for (i = 0; i < min(moniker_size, sizeof_expected_moniker_comparison_data); i++)
360     {
361         if (expected_moniker_comparison_data[i] != buffer[i])
362         {
363             same = FALSE;
364             break;
365         }
366     }
367
368     ok(same, "%s: Comparison data differs\n", testname);
369     if (!same)
370     {
371         for (i = 0; i < moniker_size; i++)
372         {
373             if (i % 8 == 0) printf("     ");
374             printf("0x%02x,", buffer[i]);
375             if (i % 8 == 7) printf("\n");
376         }
377         printf("\n");
378     }
379
380     IROTData_Release(rotdata);
381   
382     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
383   
384     /* Saving */
385
386     hr = IMoniker_Save(moniker, stream, TRUE);
387     ok_ole_success(hr, IMoniker_Save);
388
389     hr = GetHGlobalFromStream(stream, &hglobal);
390     ok_ole_success(hr, GetHGlobalFromStream);
391
392     moniker_size = GlobalSize(hglobal);
393
394     moniker_data = GlobalLock(hglobal);
395
396     /* first check we have the right amount of data */
397     ok(moniker_size == sizeof_expected_moniker_saved_data,
398         "%s: Size of saved data differs (expected %d, actual %d)\n",
399         testname, sizeof_expected_moniker_saved_data, moniker_size);
400
401     /* then do a byte-by-byte comparison */
402     for (i = 0; i < min(moniker_size, sizeof_expected_moniker_saved_data); i++)
403     {
404         if (expected_moniker_saved_data[i] != moniker_data[i])
405         {
406             same = FALSE;
407             break;
408         }
409     }
410
411     ok(same, "%s: Saved data differs\n", testname);
412     if (!same)
413     {
414         for (i = 0; i < moniker_size; i++)
415         {
416             if (i % 8 == 0) printf("     ");
417             printf("0x%02x,", moniker_data[i]);
418             if (i % 8 == 7) printf("\n");
419         }
420         printf("\n");
421     }
422
423     GlobalUnlock(hglobal);
424
425     IStream_Release(stream);
426
427     /* Marshaling tests */
428
429     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
430     ok_ole_success(hr, CreateStreamOnHGlobal);
431
432     hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
433     ok_ole_success(hr, CoMarshalInterface);
434
435     hr = GetHGlobalFromStream(stream, &hglobal);
436     ok_ole_success(hr, GetHGlobalFromStream);
437
438     moniker_size = GlobalSize(hglobal);
439
440     moniker_data = GlobalLock(hglobal);
441
442     /* first check we have the right amount of data */
443     ok(moniker_size == sizeof_expected_moniker_marshal_data,
444         "%s: Size of marshaled data differs (expected %d, actual %d)\n",
445         testname, sizeof_expected_moniker_marshal_data, moniker_size);
446
447     /* then do a byte-by-byte comparison */
448     if (expected_moniker_marshal_data)
449     {
450         for (i = 0; i < min(moniker_size, sizeof_expected_moniker_marshal_data); i++)
451         {
452             if (expected_moniker_marshal_data[i] != moniker_data[i])
453             {
454                 same = FALSE;
455                 break;
456             }
457         }
458     }
459
460     ok(same, "%s: Marshaled data differs\n", testname);
461     if (!same)
462     {
463         for (i = 0; i < moniker_size; i++)
464         {
465             if (i % 8 == 0) printf("     ");
466             printf("0x%02x,", moniker_data[i]);
467             if (i % 8 == 7) printf("\n");
468         }
469         printf("\n");
470     }
471
472     GlobalUnlock(hglobal);
473
474     IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
475     hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker_proxy);
476     ok_ole_success(hr, CoUnmarshalInterface);
477
478     IStream_Release(stream);
479     IMoniker_Release(moniker_proxy);
480 }
481
482 static void test_class_moniker(void)
483 {
484     HRESULT hr;
485     IMoniker *moniker;
486     DWORD moniker_type;
487     DWORD hash;
488     IBindCtx *bindctx;
489     IMoniker *inverse;
490     IUnknown *unknown;
491     FILETIME filetime;
492
493     hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker);
494     ok_ole_success(hr, CreateClassMoniker);
495     if (!moniker) return;
496
497     test_moniker("class moniker", moniker, 
498         expected_class_moniker_marshal_data, sizeof(expected_class_moniker_marshal_data),
499         expected_class_moniker_saved_data, sizeof(expected_class_moniker_saved_data),
500         expected_class_moniker_comparison_data, sizeof(expected_class_moniker_comparison_data),
501         expected_class_moniker_display_name);
502
503     /* Hashing */
504
505     hr = IMoniker_Hash(moniker, &hash);
506     ok_ole_success(hr, IMoniker_Hash);
507
508     ok(hash == CLSID_StdComponentCategoriesMgr.Data1,
509         "Hash value != Data1 field of clsid, instead was 0x%08x\n",
510         hash);
511
512     /* IsSystemMoniker test */
513
514     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
515     ok_ole_success(hr, IMoniker_IsSystemMoniker);
516
517     ok(moniker_type == MKSYS_CLASSMONIKER,
518         "dwMkSys != MKSYS_CLASSMONIKER, instead was 0x%08x\n",
519         moniker_type);
520
521     hr = CreateBindCtx(0, &bindctx);
522     ok_ole_success(hr, CreateBindCtx);
523
524     /* IsRunning test */
525     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
526     ok(hr == E_NOTIMPL, "IMoniker_IsRunning should return E_NOTIMPL, not 0x%08x\n", hr);
527
528     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
529     ok(hr == MK_E_UNAVAILABLE, "IMoniker_GetTimeOfLastChange should return MK_E_UNAVAILABLE, not 0x%08x\n", hr);
530
531     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
532     ok_ole_success(hr, IMoniker_BindToStorage);
533     IUnknown_Release(unknown);
534
535     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
536     ok_ole_success(hr, IMoniker_BindToStorage);
537     IUnknown_Release(unknown);
538
539     IBindCtx_Release(bindctx);
540
541     hr = IMoniker_Inverse(moniker, &inverse);
542     ok_ole_success(hr, IMoniker_Inverse);
543     IMoniker_Release(inverse);
544
545     IMoniker_Release(moniker);
546 }
547
548 static void test_file_moniker(WCHAR* path)
549 {
550     IStream *stream;
551     IMoniker *moniker1 = NULL, *moniker2 = NULL;
552     HRESULT hr;
553
554     hr = CreateFileMoniker(path, &moniker1);
555     ok_ole_success(hr, CreateFileMoniker); 
556
557     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
558
559     /* Marshal */
560     hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker1, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
561     ok_ole_success(hr, CoMarshalInterface);
562     
563     /* Rewind */
564     hr = IStream_Seek(stream, llZero, STREAM_SEEK_SET, NULL);
565     ok_ole_success(hr, IStream_Seek);
566
567     /* Unmarshal */
568     hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void**)&moniker2);
569     ok_ole_success(hr, CoUnmarshalInterface);
570
571     hr = IMoniker_IsEqual(moniker1, moniker2);
572     ok_ole_success(hr, IsEqual);
573
574     IStream_Release(stream);
575     if (moniker1) 
576         IMoniker_Release(moniker1);
577     if (moniker2) 
578         IMoniker_Release(moniker2);
579 }
580
581 static void test_file_monikers(void)
582 {
583     static WCHAR wszFile[][30] = {
584         {'\\', 'w','i','n','d','o','w','s','\\','s','y','s','t','e','m','\\','t','e','s','t','1','.','d','o','c',0},
585         {'\\', '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},
586         /* These map to themselves in Windows-1252 & 932 (Shift-JIS) */
587         {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0},
588         /* U+2020 = DAGGER     = 0x86 (1252) = 0x813f (932)
589          * U+20AC = EURO SIGN  = 0x80 (1252) =  undef (932)
590          * U+0100 .. = Latin extended-A
591          */ 
592         {0x20ac, 0x2020, 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10a, 0x10b, 0x10c,  0},
593         };
594
595     int i; 
596
597     trace("ACP is %u\n", GetACP());
598
599     for (i = 0; i < COUNTOF(wszFile); ++i)
600     {
601         int j ;
602         for (j = lstrlenW(wszFile[i]); j > 0; --j)
603         {
604             wszFile[i][j] = 0;
605             test_file_moniker(wszFile[i]);
606         }
607     }
608 }
609
610 static void test_item_moniker(void)
611 {
612     HRESULT hr;
613     IMoniker *moniker;
614     DWORD moniker_type;
615     DWORD hash;
616     IBindCtx *bindctx;
617     IMoniker *inverse;
618     IUnknown *unknown;
619     static const WCHAR wszDelimeter[] = {'!',0};
620     static const WCHAR wszObjectName[] = {'T','e','s','t',0};
621     static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 };
622
623     hr = CreateItemMoniker(wszDelimeter, wszObjectName, &moniker);
624     ok_ole_success(hr, CreateItemMoniker);
625
626     test_moniker("item moniker", moniker, 
627         expected_item_moniker_marshal_data, sizeof(expected_item_moniker_marshal_data),
628         expected_item_moniker_saved_data, sizeof(expected_item_moniker_saved_data),
629         expected_item_moniker_comparison_data, sizeof(expected_item_moniker_comparison_data),
630         expected_display_name);
631
632     /* Hashing */
633
634     hr = IMoniker_Hash(moniker, &hash);
635     ok_ole_success(hr, IMoniker_Hash);
636
637     ok(hash == 0x73c,
638         "Hash value != 0x73c, instead was 0x%08x\n",
639         hash);
640
641     /* IsSystemMoniker test */
642
643     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
644     ok_ole_success(hr, IMoniker_IsSystemMoniker);
645
646     ok(moniker_type == MKSYS_ITEMMONIKER,
647         "dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n",
648         moniker_type);
649
650     hr = CreateBindCtx(0, &bindctx);
651     ok_ole_success(hr, CreateBindCtx);
652
653     /* IsRunning test */
654     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
655     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
656
657     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
658     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
659
660     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
661     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
662
663     IBindCtx_Release(bindctx);
664
665     hr = IMoniker_Inverse(moniker, &inverse);
666     ok_ole_success(hr, IMoniker_Inverse);
667     IMoniker_Release(inverse);
668
669     IMoniker_Release(moniker);
670 }
671
672 static void test_anti_moniker(void)
673 {
674     HRESULT hr;
675     IMoniker *moniker;
676     DWORD moniker_type;
677     DWORD hash;
678     IBindCtx *bindctx;
679     FILETIME filetime;
680     IMoniker *inverse;
681     IUnknown *unknown;
682     static const WCHAR expected_display_name[] = { '\\','.','.',0 };
683
684     hr = CreateAntiMoniker(&moniker);
685     ok_ole_success(hr, CreateAntiMoniker);
686     if (!moniker) return;
687
688     test_moniker("anti moniker", moniker, 
689         expected_anti_moniker_marshal_data, sizeof(expected_anti_moniker_marshal_data),
690         expected_anti_moniker_saved_data, sizeof(expected_anti_moniker_saved_data),
691         expected_anti_moniker_comparison_data, sizeof(expected_anti_moniker_comparison_data),
692         expected_display_name);
693
694     /* Hashing */
695     hr = IMoniker_Hash(moniker, &hash);
696     ok_ole_success(hr, IMoniker_Hash);
697     ok(hash == 0x80000001,
698         "Hash value != 0x80000001, instead was 0x%08x\n",
699         hash);
700
701     /* IsSystemMoniker test */
702     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
703     ok_ole_success(hr, IMoniker_IsSystemMoniker);
704     ok(moniker_type == MKSYS_ANTIMONIKER,
705         "dwMkSys != MKSYS_ANTIMONIKER, instead was 0x%08x\n",
706         moniker_type);
707
708     hr = IMoniker_Inverse(moniker, &inverse);
709     ok(hr == MK_E_NOINVERSE, "IMoniker_Inverse should have returned MK_E_NOINVERSE instead of 0x%08x\n", hr);
710     ok(inverse == NULL, "inverse should have been set to NULL instead of %p\n", inverse);
711
712     hr = CreateBindCtx(0, &bindctx);
713     ok_ole_success(hr, CreateBindCtx);
714
715     /* IsRunning test */
716     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
717     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
718
719     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
720     ok(hr == E_NOTIMPL, "IMoniker_GetTimeOfLastChange should return E_NOTIMPL, not 0x%08x\n", hr);
721
722     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
723     ok(hr == E_NOTIMPL, "IMoniker_BindToObject should return E_NOTIMPL, not 0x%08x\n", hr);
724
725     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
726     ok(hr == E_NOTIMPL, "IMoniker_BindToStorage should return E_NOTIMPL, not 0x%08x\n", hr);
727
728     IBindCtx_Release(bindctx);
729
730     IMoniker_Release(moniker);
731 }
732
733 static void test_generic_composite_moniker(void)
734 {
735     HRESULT hr;
736     IMoniker *moniker;
737     IMoniker *moniker1;
738     IMoniker *moniker2;
739     DWORD moniker_type;
740     DWORD hash;
741     IBindCtx *bindctx;
742     FILETIME filetime;
743     IMoniker *inverse;
744     IUnknown *unknown;
745     static const WCHAR wszDelimeter1[] = {'!',0};
746     static const WCHAR wszObjectName1[] = {'T','e','s','t',0};
747     static const WCHAR wszDelimeter2[] = {'#',0};
748     static const WCHAR wszObjectName2[] = {'W','i','n','e',0};
749     static const WCHAR expected_display_name[] = { '!','T','e','s','t','#','W','i','n','e',0 };
750
751     hr = CreateItemMoniker(wszDelimeter1, wszObjectName1, &moniker1);
752     ok_ole_success(hr, CreateItemMoniker);
753     hr = CreateItemMoniker(wszDelimeter2, wszObjectName2, &moniker2);
754     ok_ole_success(hr, CreateItemMoniker);
755     hr = CreateGenericComposite(moniker1, moniker2, &moniker);
756     ok_ole_success(hr, CreateGenericComposite);
757
758     test_moniker("generic composite moniker", moniker, 
759         expected_gc_moniker_marshal_data, sizeof(expected_gc_moniker_marshal_data),
760         expected_gc_moniker_saved_data, sizeof(expected_gc_moniker_saved_data),
761         expected_gc_moniker_comparison_data, sizeof(expected_gc_moniker_comparison_data),
762         expected_display_name);
763
764     /* Hashing */
765
766     hr = IMoniker_Hash(moniker, &hash);
767     ok_ole_success(hr, IMoniker_Hash);
768
769     ok(hash == 0xd87,
770         "Hash value != 0xd87, instead was 0x%08x\n",
771         hash);
772
773     /* IsSystemMoniker test */
774
775     hr = IMoniker_IsSystemMoniker(moniker, &moniker_type);
776     ok_ole_success(hr, IMoniker_IsSystemMoniker);
777
778     ok(moniker_type == MKSYS_GENERICCOMPOSITE,
779         "dwMkSys != MKSYS_GENERICCOMPOSITE, instead was 0x%08x\n",
780         moniker_type);
781
782     hr = CreateBindCtx(0, &bindctx);
783     ok_ole_success(hr, CreateBindCtx);
784
785     /* IsRunning test */
786     hr = IMoniker_IsRunning(moniker, bindctx, NULL, NULL);
787     todo_wine
788     ok(hr == S_FALSE, "IMoniker_IsRunning should return S_FALSE, not 0x%08x\n", hr);
789
790     hr = IMoniker_GetTimeOfLastChange(moniker, bindctx, NULL, &filetime);
791     ok(hr == MK_E_NOTBINDABLE, "IMoniker_GetTimeOfLastChange should return MK_E_NOTBINDABLE, not 0x%08x\n", hr);
792
793     hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
794     todo_wine
795     ok(hr == E_INVALIDARG, "IMoniker_BindToObject should return E_INVALIDARG, not 0x%08x\n", hr);
796
797     todo_wine
798     hr = IMoniker_BindToStorage(moniker, bindctx, NULL, &IID_IUnknown, (void **)&unknown);
799     ok(hr == E_INVALIDARG, "IMoniker_BindToStorage should return E_INVALIDARG, not 0x%08x\n", hr);
800
801     IBindCtx_Release(bindctx);
802
803     hr = IMoniker_Inverse(moniker, &inverse);
804     ok_ole_success(hr, IMoniker_Inverse);
805     IMoniker_Release(inverse);
806
807     IMoniker_Release(moniker);
808 }
809
810 START_TEST(moniker)
811 {
812     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
813
814     test_MkParseDisplayName();
815     test_class_moniker();
816     test_file_monikers();
817     test_item_moniker();
818     test_anti_moniker();
819     test_generic_composite_moniker();
820
821     /* FIXME: test moniker creation funcs and parsing other moniker formats */
822
823     CoUninitialize();
824 }