hlink/tests: Add hres checks for the IHlink_GetMonikerReference calls (clang).
[wine] / dlls / hlink / tests / hlink.c
1 /*
2  * Implementation of hyperlinking (hlink.dll)
3  *
4  * Copyright 2006 Mike McCormack
5  * Copyright 2007-2008 Jacek Caban for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23
24 #include <stdio.h>
25
26 #include <initguid.h>
27 #include <hlink.h>
28 #include <hlguids.h>
29
30 #include "wine/test.h"
31
32 #define DEFINE_EXPECT(func) \
33     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
34
35 #define SET_EXPECT(func) \
36     expect_ ## func = TRUE
37
38 #define CHECK_EXPECT2(func) \
39     do { \
40         ok(expect_ ##func, "unexpected call " #func "\n"); \
41         called_ ## func = TRUE; \
42     }while(0)
43
44 #define CHECK_EXPECT(func) \
45     do { \
46         CHECK_EXPECT2(func); \
47         expect_ ## func = FALSE; \
48     }while(0)
49
50 #define CHECK_CALLED(func) \
51     do { \
52         ok(called_ ## func, "expected " #func "\n"); \
53         expect_ ## func = called_ ## func = FALSE; \
54     }while(0)
55
56 DEFINE_EXPECT(IsSystemMoniker);
57 DEFINE_EXPECT(BindToStorage);
58 DEFINE_EXPECT(GetDisplayName);
59
60 DEFINE_EXPECT(ComposeWith);
61 DEFINE_EXPECT(OnNavigationComplete);
62 DEFINE_EXPECT(Enum);
63 DEFINE_EXPECT(Reduce);
64
65 DEFINE_EXPECT(GetClassID);
66 DEFINE_EXPECT(Save);
67
68 static const char *debugstr_guid(REFIID riid)
69 {
70     static char buf[50];
71
72     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
73             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
74             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
75             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
76
77     return buf;
78 }
79
80 static void test_HlinkIsShortcut(void)
81 {
82     UINT i;
83     HRESULT hres;
84
85     static const WCHAR file0[] = {'f','i','l','e',0};
86     static const WCHAR file1[] = {'f','i','l','e','.','u','r','l',0};
87     static const WCHAR file2[] = {'f','i','l','e','.','l','n','k',0};
88     static const WCHAR file3[] = {'f','i','l','e','.','u','R','l',0};
89     static const WCHAR file4[] = {'f','i','l','e','u','r','l',0};
90     static const WCHAR file5[] = {'c',':','\\','f','i','l','e','.','u','r','l',0};
91     static const WCHAR file6[] = {'c',':','\\','f','i','l','e','.','l','n','k',0};
92     static const WCHAR file7[] = {'.','u','r','l',0};
93
94     static struct {
95         LPCWSTR file;
96         HRESULT hres;
97     } shortcut_test[] = {
98         {file0, S_FALSE},
99         {file1, S_OK},
100         {file2, S_FALSE},
101         {file3, S_OK},
102         {file4, S_FALSE},
103         {file5, S_OK},
104         {file6, S_FALSE},
105         {file7, S_OK},
106         {NULL,  E_INVALIDARG}
107     };
108
109     for(i=0; i<sizeof(shortcut_test)/sizeof(shortcut_test[0]); i++) {
110         hres = HlinkIsShortcut(shortcut_test[i].file);
111         ok(hres == shortcut_test[i].hres, "[%d] HlinkIsShortcut returned %08x, expected %08x\n",
112            i, hres, shortcut_test[i].hres);
113     }
114 }
115
116 static void test_reference(void)
117 {
118     HRESULT r;
119     IHlink *lnk = NULL;
120     IMoniker *mk = NULL;
121     const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
122     const WCHAR url2[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/',0 };
123     LPWSTR str = NULL;
124
125     r = HlinkCreateFromString(url, NULL, NULL, NULL,
126                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
127     ok(r == S_OK, "failed to create link\n");
128     if (FAILED(r))
129         return;
130
131     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
132     ok(r == S_OK, "failed\n");
133
134     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, &mk, &str);
135     ok(r == S_OK, "failed\n");
136     ok(mk != NULL, "no moniker\n");
137     ok(str == NULL, "string should be null\n");
138
139     r = IMoniker_Release(mk);
140     ok( r == 1, "moniker refcount wrong\n");
141
142     r = IHlink_GetStringReference(lnk, -1, &str, NULL);
143     ok(r == S_OK, "failed\n");
144     CoTaskMemFree(str);
145
146     r = IHlink_GetStringReference(lnk, -1, NULL, NULL);
147     ok(r == S_OK, "failed, r=%08x\n", r);
148
149     r = IHlink_GetStringReference(lnk, -1, NULL, &str);
150     ok(r == S_OK, "failed, r=%08x\n", r);
151     ok(str == NULL, "string should be null\n");
152
153     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, &str, NULL);
154     ok(r == S_OK, "failed\n");
155     ok(!lstrcmpW(str, url2), "url wrong\n");
156     CoTaskMemFree(str);
157
158     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
159     ok(r == S_OK, "failed\n");
160
161     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, &str);
162     ok(r == S_OK, "failed\n");
163     ok(str == NULL, "string should be null\n");
164
165     /* Unimplented functions checks */
166     r = IHlink_GetAdditionalParams(lnk, NULL);
167     ok(r == E_NOTIMPL, "failed\n");
168
169     r = IHlink_SetAdditionalParams(lnk, NULL);
170     ok(r == E_NOTIMPL, "failed\n");
171
172     IHlink_Release(lnk);
173 }
174
175 /* url only */
176 static const unsigned char expected_hlink_data[] =
177 {
178     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
179     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
180     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
181     0x26,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
182     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
183     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
184     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
185     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
186     0x00,0x00,
187 };
188
189 /* url only (IE7) */
190 static const unsigned char expected_hlink_data_ie7[] =
191 {
192     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
193     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
194     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
195     0x3e,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
196     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
197     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
198     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
199     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
200     0x00,0x00,0x79,0x58,0x81,0xf4,0x3b,0x1d,
201     0x7f,0x48,0xaf,0x2c,0x82,0x5d,0xc4,0x85,
202     0x27,0x63,0x00,0x00,0x00,0x00,0xa5,0xab,
203     0x00,0x00,
204 };
205
206 /* url + friendly name */
207 static const unsigned char expected_hlink_data2[] =
208 {
209     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
210     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
211     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
212     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
213     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
214     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
215     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
216     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
217     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
218     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
219     0x67,0x00,0x2f,0x00,0x00,0x00,
220 };
221
222 /* url + friendly name (IE7) */
223 static const unsigned char expected_hlink_data2_ie7[] =
224 {
225     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
226     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
227     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
228     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
229     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
230     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
231     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
232     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
233     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
234     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
235     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
236     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
237     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
238     0x00,0x00,0xa5,0xab,0x00,0x00,
239 };
240
241 /* url + friendly name + location */
242 static const unsigned char expected_hlink_data3[] =
243 {
244     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
245     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
246     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
247     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
248     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
249     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
250     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
251     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
252     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
253     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
254     0x67,0x00,0x2f,0x00,0x00,0x00,0x07,0x00,
255     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
256     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
257 };
258
259 /* url + friendly name + location (IE7) */
260 static const unsigned char expected_hlink_data3_ie7[] =
261 {
262     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
263     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
264     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
265     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
266     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
267     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
268     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
269     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
270     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
271     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
272     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
273     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
274     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
275     0x00,0x00,0xa5,0xab,0x00,0x00,0x07,0x00,
276     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
277     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
278 };
279
280 /* relative url */
281 static const unsigned char expected_hlink_data4[] =
282 {
283     0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
284     0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
285     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
286     0x00,0x00,0x0b,0x00,0x00,0x00,0x69,0x6e,
287     0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,
288     0x00,0xff,0xff,0xad,0xde,0x00,0x00,0x00,
289     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
290     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
291     0x00,0x00,0x00,0x00,0x00,
292 };
293
294 /* url + target frame name */
295 static const unsigned char expected_hlink_data5[] =
296 {
297     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
298     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
299     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
300     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
301     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
302     0xa9,0x0b,0x26,0x00,0x00,0x00,0x68,0x00,
303     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
304     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
305     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
306     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
307     0x2f,0x00,0x00,0x00,
308 };
309
310 /* url + target frame name (IE7) */
311 static const unsigned char expected_hlink_data5_ie7[] =
312 {
313     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
314     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
315     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
316     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
317     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
318     0xa9,0x0b,0x3e,0x00,0x00,0x00,0x68,0x00,
319     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
320     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
321     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
322     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
323     0x2f,0x00,0x00,0x00,0x79,0x58,0x81,0xf4,
324     0x3b,0x1d,0x7f,0x48,0xaf,0x2c,0x82,0x5d,
325     0xc4,0x85,0x27,0x63,0x00,0x00,0x00,0x00,
326     0xa5,0xab,0x00,0x00,
327 };
328
329 /* filename */
330 static const unsigned char expected_hlink_data6[] =
331 {
332      0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
333      0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
334      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
335      0x00,0x00,0x04,0x00,0x00,0x00,0x63,0x3a,
336      0x5c,0x00,0xff,0xff,0xad,0xde,0x00,0x00,
337      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
338      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
339      0x00,0x00,0x0c,0x00,0x00,0x00,0x06,0x00,
340      0x00,0x00,0x03,0x00,0x63,0x00,0x3a,0x00,
341      0x5c,0x00,
342 };
343
344 static void test_persist_save_data(const char *testname, IHlink *lnk,
345                                    const unsigned char *expected_data,
346                                    unsigned int expected_data_size,
347                                    const unsigned char *expected_data_alt,
348                                    unsigned int expected_data_alt_size)
349 {
350     HRESULT hr;
351     IStream *stream;
352     IPersistStream *ps;
353     HGLOBAL hglobal;
354     DWORD data_size;
355     const unsigned char *data;
356     DWORD i;
357     BOOL same;
358     unsigned int expected_data_win9x_size = 0;
359
360     hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
361     ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
362
363     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
364     ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
365
366     hr = IPersistStream_Save(ps, stream, TRUE);
367     ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
368
369     hr = GetHGlobalFromStream(stream, &hglobal);
370     ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
371
372     data_size = GlobalSize(hglobal);
373
374     data = GlobalLock(hglobal);
375
376     if (expected_data_size % 4)
377         expected_data_win9x_size =  4 * ((expected_data_size / 4) + 1);
378
379     /* first check we have the right amount of data */
380     ok((data_size == expected_data_size) ||
381        (data_size == expected_data_alt_size) ||
382        broken(data_size == expected_data_win9x_size), /* Win9x and WinMe */
383        "%s: Size of saved data differs (expected %d or %d, actual %d)\n",
384        testname, expected_data_size, expected_data_alt_size, data_size);
385
386     same = TRUE;
387     /* then do a byte-by-byte comparison */
388     for (i = 0; i < min(data_size, expected_data_size); i++)
389     {
390         if ((expected_data[i] != data[i]) &&
391             (((expected_data != expected_hlink_data2) &&
392               (expected_data != expected_hlink_data3)) ||
393              ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
394         {
395             same = FALSE;
396             break;
397         }
398     }
399
400     if (!same && (expected_data_alt != expected_data))
401     {
402         /* then try the alternate data */
403         same = TRUE;
404         for (i = 0; i < min(data_size, expected_data_alt_size); i++)
405         {
406             if ((expected_data_alt[i] != data[i]) &&
407                 (((expected_data_alt != expected_hlink_data2) &&
408                   (expected_data_alt != expected_hlink_data3)) ||
409                  ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
410             {
411                 same = FALSE;
412                 break;
413             }
414         }
415     }
416
417     ok(same, "%s: Saved data differs\n", testname);
418     if (!same)
419     {
420         for (i = 0; i < data_size; i++)
421         {
422             if (i % 8 == 0) printf("    ");
423             printf("0x%02x,", data[i]);
424             if (i % 8 == 7) printf("\n");
425         }
426         printf("\n");
427     }
428
429     GlobalUnlock(hglobal);
430
431     IStream_Release(stream);
432     IPersistStream_Release(ps);
433 }
434
435 static void test_persist(void)
436 {
437     static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
438     static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
439     static const WCHAR filename[] = { 'c',':','\\',0 };
440     static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
441     static const WCHAR location[] = { '_','b','l','a','n','k',0 };
442     static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
443     HRESULT hr;
444     IHlink *lnk;
445
446     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
447                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
448     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
449     if (!lnk) {
450         skip("Can't create lnk, skipping test_persist.\n");
451         return;
452     }
453     test_persist_save_data("url only", lnk,
454         expected_hlink_data, sizeof(expected_hlink_data),
455         expected_hlink_data_ie7, sizeof(expected_hlink_data_ie7));
456     IHlink_Release(lnk);
457
458     hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
459                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
460     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
461     test_persist_save_data("url + friendly name", lnk,
462         expected_hlink_data2, sizeof(expected_hlink_data2),
463         expected_hlink_data2_ie7, sizeof(expected_hlink_data2_ie7));
464     IHlink_Release(lnk);
465
466     hr = HlinkCreateFromString(url, location, friendly_name, NULL,
467                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
468     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
469     test_persist_save_data("url + friendly_name + location", lnk,
470         expected_hlink_data3, sizeof(expected_hlink_data3),
471         expected_hlink_data3_ie7, sizeof(expected_hlink_data3_ie7));
472     IHlink_Release(lnk);
473
474     hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
475                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
476     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
477     test_persist_save_data("relative url", lnk,
478         expected_hlink_data4, sizeof(expected_hlink_data4),
479         expected_hlink_data4, sizeof(expected_hlink_data4));
480     IHlink_Release(lnk);
481
482     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
483                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
484     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
485     hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
486     ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
487     test_persist_save_data("url + target frame name", lnk,
488         expected_hlink_data5, sizeof(expected_hlink_data5),
489         expected_hlink_data5_ie7, sizeof(expected_hlink_data5_ie7));
490     IHlink_Release(lnk);
491
492     hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
493                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
494     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
495     test_persist_save_data("filename", lnk,
496         expected_hlink_data6, sizeof(expected_hlink_data6),
497         expected_hlink_data6, sizeof(expected_hlink_data6));
498     IHlink_Release(lnk);
499 }
500
501 static void test_special_reference(void)
502 {
503     LPWSTR ref;
504     HRESULT hres;
505
506     hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
507     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
508     ok(ref != NULL, "ref == NULL\n");
509     CoTaskMemFree(ref);
510
511     hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
512     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
513     ok(ref != NULL, "ref == NULL\n");
514     CoTaskMemFree(ref);
515
516     ref = (void*)0xdeadbeef;
517     hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
518     ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
519     ok(ref == NULL, "ref=%p\n", ref);
520
521     ref = (void*)0xdeadbeef;
522     hres = HlinkGetSpecialReference(4, &ref);
523     ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
524     ok(ref == NULL, "ref=%p\n", ref);
525 }
526
527 static void test_HlinkCreateExtensionServices(void)
528 {
529     IAuthenticate *authenticate;
530     IHttpNegotiate *http_negotiate;
531     LPWSTR password, username, headers;
532     HWND hwnd;
533     HRESULT hres;
534
535     static const WCHAR usernameW[] = {'u','s','e','r',0};
536     static const WCHAR passwordW[] = {'p','a','s','s',0};
537     static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
538     static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
539
540     hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
541                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
542     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
543     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
544
545     password = username = (void*)0xdeadbeef;
546     hwnd = (void*)0xdeadbeef;
547     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
548     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
549     ok(!hwnd, "hwnd != NULL\n");
550     ok(!username, "username != NULL\n");
551     ok(!password, "password != NULL\n");
552
553     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
554     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
555
556     headers = (void*)0xdeadbeef;
557     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
558                                                0, &headers);
559     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
560     ok(headers == NULL, "headers != NULL\n");
561
562     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
563                                                0, NULL);
564     ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
565
566     headers = (void*)0xdeadbeef;
567     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
568     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
569     ok(headers == NULL, "headers != NULL\n");
570
571     IHttpNegotiate_Release(http_negotiate);
572     IAuthenticate_Release(authenticate);
573
574
575     hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
576                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
577     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
578     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
579
580     password = username = NULL;
581     hwnd = NULL;
582     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
583     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
584     ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
585     ok(!lstrcmpW(username, usernameW), "unexpected username\n");
586     ok(!lstrcmpW(password, passwordW), "unexpected password\n");
587     CoTaskMemFree(username);
588     CoTaskMemFree(password);
589
590     password = username = (void*)0xdeadbeef;
591     hwnd = (void*)0xdeadbeef;
592     hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
593     ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
594     ok(password == (void*)0xdeadbeef, "password = %p\n", password);
595     ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
596
597     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
598     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
599
600     headers = (void*)0xdeadbeef;
601     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
602                                                0, &headers);
603     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
604     ok(!lstrcmpW(headers, headersexW), "unexpected headers %s\n", wine_dbgstr_w(headers));
605     CoTaskMemFree(headers);
606
607     headers = (void*)0xdeadbeef;
608     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
609     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
610     ok(headers == NULL, "unexpected headers %s\n", wine_dbgstr_w(headers));
611
612     IHttpNegotiate_Release(http_negotiate);
613     IAuthenticate_Release(authenticate);
614 }
615
616 static void test_HlinkParseDisplayName(void)
617 {
618     IMoniker *mon = NULL;
619     LPWSTR name;
620     DWORD issys;
621     ULONG eaten = 0;
622     IBindCtx *bctx;
623     HRESULT hres;
624
625     static const WCHAR winehq_urlW[] =
626             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
627              '/','s','i','t','e','/','a','b','o','u','t',0};
628     static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
629     static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':',
630             '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8',
631             '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0};
632
633     CreateBindCtx(0, &bctx);
634
635     hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon);
636     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
637     ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
638     ok(mon != NULL, "mon == NULL\n");
639
640     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
641     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
642     ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
643     CoTaskMemFree(name);
644
645     hres = IMoniker_IsSystemMoniker(mon, &issys);
646     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
647     ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys);
648
649     IMoniker_Release(mon);
650
651     hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon);
652     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
653     ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
654     ok(mon != NULL, "mon == NULL\n");
655
656     hres = IMoniker_IsSystemMoniker(mon, &issys);
657     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
658     ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys);
659
660     IMoniker_Release(mon);
661
662     hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon);
663      ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
664     ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
665     ok(mon != NULL, "mon == NULL\n");
666
667     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
668     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
669     ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
670     CoTaskMemFree(name);
671
672     hres = IMoniker_IsSystemMoniker(mon, &issys);
673     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
674     ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys);
675
676     IMoniker_Release(mon);
677     IBindCtx_Release(bctx);
678 }
679
680 static IBindCtx *_bctx;
681
682 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
683 {
684     ok(0, "unexpected call\n");
685     return E_NOINTERFACE;
686 }
687
688 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
689 {
690     return 2;
691 }
692
693 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
694 {
695     return 1;
696 }
697
698 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
699         REFGUID guidService, REFIID riid, void **ppv)
700 {
701     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
702     return E_NOINTERFACE;
703 }
704
705 static IServiceProviderVtbl ServiceProviderVtbl = {
706     ServiceProvider_QueryInterface,
707     ServiceProvider_AddRef,
708     ServiceProvider_Release,
709     ServiceProvider_QueryService
710 };
711
712 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
713
714 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
715 {
716     *ppv = NULL;
717
718     if(IsEqualGUID(riid, &IID_IServiceProvider)) {
719         *ppv = &ServiceProvider;
720         return S_OK;
721     }
722
723     ok(0, "unexpected interface %s\n", debugstr_guid(riid));
724     return E_NOINTERFACE;
725 }
726
727 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
728 {
729     return 2;
730 }
731
732 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
733 {
734     return 1;
735 }
736
737 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
738         IBinding *pib)
739 {
740     ok(0, "unexpected call\n");
741     return E_NOTIMPL;
742 }
743
744 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
745 {
746     ok(0, "unexpected call\n");
747     return E_NOTIMPL;
748 }
749
750 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
751 {
752     ok(0, "unexpected call\n");
753     return E_NOTIMPL;
754 }
755
756 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
757         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
758 {
759     ok(0, "unexpected call\n");
760     return E_NOTIMPL;
761 }
762
763 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
764 {
765     ok(0, "unexpected call\n");
766     return E_NOTIMPL;
767 }
768
769 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
770 {
771     ok(0, "unexpected call\n");
772     return E_NOTIMPL;
773 }
774
775 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
776         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
777 {
778     ok(0, "unexpected call\n");
779     return E_NOTIMPL;
780 }
781
782 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
783 {
784     ok(0, "unexpected call\n");
785     return E_NOTIMPL;
786 }
787
788 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
789     BindStatusCallback_QueryInterface,
790     BindStatusCallback_AddRef,
791     BindStatusCallback_Release,
792     BindStatusCallback_OnStartBinding,
793     BindStatusCallback_GetPriority,
794     BindStatusCallback_OnLowResource,
795     BindStatusCallback_OnProgress,
796     BindStatusCallback_OnStopBinding,
797     BindStatusCallback_GetBindInfo,
798     BindStatusCallback_OnDataAvailable,
799     BindStatusCallback_OnObjectAvailable
800 };
801
802 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
803
804 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
805 {
806     *ppv = NULL;
807
808     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
809     return E_NOINTERFACE;
810 }
811
812 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
813 {
814     return 2;
815 }
816
817 static ULONG WINAPI Moniker_Release(IMoniker *iface)
818 {
819     return 1;
820 }
821
822 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
823 {
824     CHECK_EXPECT(GetClassID);
825     *pClassID = IID_IUnknown; /* not a valid CLSID */
826     return S_OK;
827 }
828
829 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
830 {
831     ok(0, "unexpected call\n");
832     return E_NOTIMPL;
833 }
834
835 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
836 {
837     ok(0, "unexpected call\n");
838     return E_NOTIMPL;
839 }
840
841 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
842 {
843     CHECK_EXPECT(Save);
844     return S_OK;
845 }
846
847 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
848 {
849     ok(0, "unexpected call\n");
850     return E_NOTIMPL;
851 }
852
853 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft,
854         REFIID riidResult, void **ppvResult)
855 {
856     ok(0, "unexpected call\n");
857     return E_NOTIMPL;
858 }
859
860 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
861         REFIID riid, void **ppv)
862 {
863     IUnknown *unk;
864     HRESULT hres;
865
866     static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
867
868     CHECK_EXPECT(BindToStorage);
869
870     ok(pbc == _bctx, "pbc != _bctx\n");
871     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
872     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
873     ok(ppv != NULL, "ppv == NULL\n");
874     ok(*ppv == NULL, "*ppv=%p\n", *ppv);
875
876     hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
877     ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
878     ok(unk != NULL, "unk == NULL\n");
879
880     IUnknown_Release(unk);
881
882     return S_OK;
883 }
884
885 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
886         IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
887 {
888     CHECK_EXPECT(Reduce);
889     return E_NOTIMPL;
890 }
891
892 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
893         BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
894 {
895     ok(0, "unexpected call\n");
896     return E_NOTIMPL;
897 }
898
899 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
900 {
901     CHECK_EXPECT(Enum);
902     return E_NOTIMPL;
903 }
904
905 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
906 {
907     ok(0, "unexpected call\n");
908     return E_NOTIMPL;
909 }
910
911 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
912 {
913     ok(0, "unexpected call\n");
914     return E_NOTIMPL;
915 }
916
917 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
918         IMoniker *pmkNewlyRunning)
919 {
920     ok(0, "unexpected call\n");
921     return E_NOTIMPL;
922 }
923
924 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
925         IMoniker *pmkToLeft, FILETIME *pFileTime)
926 {
927     ok(0, "unexpected call\n");
928     return E_NOTIMPL;
929 }
930
931 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
932 {
933     ok(0, "unexpected call\n");
934     return E_NOTIMPL;
935 }
936
937 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
938         IMoniker **ppmkPrefix)
939 {
940     ok(0, "unexpected call\n");
941     return E_NOTIMPL;
942 }
943
944 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
945         IMoniker **pmkRelPath)
946 {
947     ok(0, "unexpected call\n");
948     return E_NOTIMPL;
949 }
950
951 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
952         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
953 {
954     static const WCHAR winehq_urlW[] =
955             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
956              '/','s','i','t','e','/','a','b','o','u','t',0};
957
958     CHECK_EXPECT(GetDisplayName);
959
960     ok(pbc != NULL, "pbc == NULL\n");
961     ok(pbc != _bctx, "pbc == _bctx\n");
962     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
963
964     *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
965     memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
966     return S_OK;
967 }
968
969 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
970         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
971 {
972     ok(0, "unexpected call\n");
973     return E_NOTIMPL;
974 }
975
976 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
977 {
978     CHECK_EXPECT2(IsSystemMoniker);
979
980     *pdwMksys = MKSYS_URLMONIKER;
981     return S_OK;
982 }
983
984 static IMonikerVtbl MonikerVtbl = {
985     Moniker_QueryInterface,
986     Moniker_AddRef,
987     Moniker_Release,
988     Moniker_GetClassID,
989     Moniker_IsDirty,
990     Moniker_Load,
991     Moniker_Save,
992     Moniker_GetSizeMax,
993     Moniker_BindToObject,
994     Moniker_BindToStorage,
995     Moniker_Reduce,
996     Moniker_ComposeWith,
997     Moniker_Enum,
998     Moniker_IsEqual,
999     Moniker_Hash,
1000     Moniker_IsRunning,
1001     Moniker_GetTimeOfLastChange,
1002     Moniker_Inverse,
1003     Moniker_CommonPrefixWith,
1004     Moniker_RelativePathTo,
1005     Moniker_GetDisplayName,
1006     Moniker_ParseDisplayName,
1007     Moniker_IsSystemMoniker
1008 };
1009
1010 static IMoniker Moniker = { &MonikerVtbl };
1011
1012 static void test_HlinkResolveMonikerForData(void)
1013 {
1014     IBindCtx *bctx;
1015     HRESULT hres;
1016
1017     CreateBindCtx(0, &bctx);
1018     _bctx = bctx;
1019
1020     SET_EXPECT(IsSystemMoniker);
1021     SET_EXPECT(GetDisplayName);
1022     SET_EXPECT(BindToStorage);
1023
1024     hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
1025     ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
1026
1027     CHECK_CALLED(IsSystemMoniker);
1028     CHECK_CALLED(GetDisplayName);
1029     CHECK_CALLED(BindToStorage);
1030
1031     IBindCtx_Release(bctx);
1032 }
1033
1034 static void test_HlinkGetSetMonikerReference(void)
1035 {
1036     IMoniker *found_trgt, *dummy, *dummy2;
1037     IHlink *hlink;
1038     HRESULT hres;
1039     const WCHAR one[] = {'1',0};
1040     const WCHAR two[] = {'2',0};
1041     const WCHAR name[] = {'a',0};
1042     WCHAR *found_loc;
1043
1044     /* create two dummy monikers to use as targets */
1045     hres = CreateItemMoniker(one, one, &dummy);
1046     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1047
1048     hres = CreateItemMoniker(two, two, &dummy2);
1049     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1050
1051     /* create a new hlink: target => dummy, location => one */
1052     hres = HlinkCreateFromMoniker(dummy, one, name, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1053     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1054
1055     /* validate the target and location */
1056     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1057     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1058     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1059     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1060     IMoniker_Release(found_trgt);
1061     CoTaskMemFree(found_loc);
1062
1063     /* set location => two */
1064     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_LOCATION, dummy2, two);
1065     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1066
1067     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1068     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1069     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1070     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1071     IMoniker_Release(found_trgt);
1072     CoTaskMemFree(found_loc);
1073
1074     /* set target => dummy2 */
1075     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, dummy2, one);
1076     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1077
1078     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1079     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1080     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1081     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1082     IMoniker_Release(found_trgt);
1083     CoTaskMemFree(found_loc);
1084
1085     /* set target => dummy, location => one */
1086     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, dummy, one);
1087     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1088
1089     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1090     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1091     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1092     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1093     IMoniker_Release(found_trgt);
1094     CoTaskMemFree(found_loc);
1095
1096     /* no HLINKSETF flags */
1097     hres = IHlink_SetMonikerReference(hlink, 0, dummy2, two);
1098     ok(hres == E_INVALIDARG, "IHlink_SetMonikerReference should've failed with E_INVALIDARG (0x%08x), failed with 0x%08x\n", E_INVALIDARG, hres);
1099
1100     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1101     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1102     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1103     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1104     IMoniker_Release(found_trgt);
1105     CoTaskMemFree(found_loc);
1106
1107     /* invalid HLINKSETF flags */
1108     hres = IHlink_SetMonikerReference(hlink, 12, dummy2, two);
1109     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1110     if (0) ok(hres == 12, "IHlink_SetMonikerReference should've failed with 0x%08x, failed with 0x%08x\n", 12, hres);
1111
1112     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1113     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1114     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1115     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1116     IMoniker_Release(found_trgt);
1117     CoTaskMemFree(found_loc);
1118
1119     /* valid & invalid HLINKSETF flags */
1120     hres = IHlink_SetMonikerReference(hlink, 12 | HLINKSETF_TARGET, dummy2, two);
1121     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1122
1123     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1124     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1125     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1126     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1127     IMoniker_Release(found_trgt);
1128     CoTaskMemFree(found_loc);
1129
1130     /* NULL args */
1131     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, NULL, NULL);
1132     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1133
1134     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1135     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1136     ok(found_trgt == NULL, "Found target should've been %p, was: %p\n", NULL, found_trgt);
1137     ok(found_loc == NULL, "Found location should've been %s, was: %s\n", wine_dbgstr_w(NULL), wine_dbgstr_w(found_loc));
1138     if(found_trgt)
1139         IMoniker_Release(found_trgt);
1140
1141     IHlink_Release(hlink);
1142     IMoniker_Release(dummy2);
1143     IMoniker_Release(dummy);
1144 }
1145
1146 static void test_HlinkGetSetStringReference(void)
1147 {
1148     IHlink *link;
1149     static const WCHAR one[] = {'1',0};
1150     static const WCHAR two[] = {'2',0};
1151     static const WCHAR three[] = {'3',0};
1152     static const WCHAR empty[] = {0};
1153     WCHAR *fnd_tgt, *fnd_loc;
1154     HRESULT hres;
1155
1156     /* create a new hlink: target => NULL, location => one */
1157     hres = HlinkCreateFromMoniker(NULL, one, empty, NULL, 0, NULL, &IID_IHlink, (void**)&link);
1158     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1159
1160     /* test setting/getting location */
1161     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1162     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1163     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1164     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1165     CoTaskMemFree(fnd_tgt);
1166     CoTaskMemFree(fnd_loc);
1167
1168     hres = IHlink_SetStringReference(link, HLINKSETF_LOCATION, one, two);
1169     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1170
1171     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1172     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1173     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1174     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1175     CoTaskMemFree(fnd_tgt);
1176     CoTaskMemFree(fnd_loc);
1177
1178     hres = IHlink_SetStringReference(link, -HLINKSETF_LOCATION, two, one);
1179     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1180
1181     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1182     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1183     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1184     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1185     CoTaskMemFree(fnd_tgt);
1186     CoTaskMemFree(fnd_loc);
1187
1188     /* test setting/getting target */
1189     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET, two, three);
1190     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1191
1192     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1193     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1194     ok(!lstrcmpW(fnd_tgt, two), "Found target should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_tgt));
1195     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1196     CoTaskMemFree(fnd_tgt);
1197     CoTaskMemFree(fnd_loc);
1198
1199     hres = IHlink_SetStringReference(link, -HLINKSETF_TARGET, three, two);
1200     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1201
1202     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1203     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1204     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1205     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1206     CoTaskMemFree(fnd_tgt);
1207     CoTaskMemFree(fnd_loc);
1208
1209     /* test setting/getting both */
1210     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET | HLINKSETF_LOCATION, one, two);
1211     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1212
1213     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1214     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1215     ok(!lstrcmpW(fnd_tgt, one), "Found target should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_tgt));
1216     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1217     CoTaskMemFree(fnd_tgt);
1218     CoTaskMemFree(fnd_loc);
1219
1220     hres = IHlink_SetStringReference(link, -(HLINKSETF_TARGET | HLINKSETF_LOCATION), three, one);
1221     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1222
1223     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1224     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1225     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1226     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1227     CoTaskMemFree(fnd_tgt);
1228     CoTaskMemFree(fnd_loc);
1229
1230     /* test invalid flags/params */
1231     hres = IHlink_GetStringReference(link, 4, &fnd_tgt, &fnd_loc);
1232     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1233            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1234     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1235     ok(fnd_loc == NULL, "Found location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1236     CoTaskMemFree(fnd_tgt);
1237     CoTaskMemFree(fnd_loc);
1238
1239     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, NULL);
1240     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1241            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1242     CoTaskMemFree(fnd_tgt);
1243
1244     hres = IHlink_GetStringReference(link, -1, NULL, NULL);
1245     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1246
1247     hres = IHlink_GetStringReference(link, -1, NULL, &fnd_loc);
1248     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1249     CoTaskMemFree(fnd_loc);
1250
1251     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, &fnd_loc);
1252     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1253            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1254     CoTaskMemFree(fnd_tgt);
1255     CoTaskMemFree(fnd_loc);
1256
1257     hres = IHlink_GetStringReference(link, -2, &fnd_tgt, &fnd_loc);
1258     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1259            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1260     CoTaskMemFree(fnd_tgt);
1261     CoTaskMemFree(fnd_loc);
1262
1263     hres = IHlink_SetStringReference(link, 4, NULL, NULL);
1264     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1265     if (0) ok(hres == 4, "IHlink_SetStringReference should have failed with 0x4, instead: 0x%08x\n", hres);
1266
1267     hres = IHlink_SetStringReference(link, -4, NULL, NULL);
1268     if (0) ok(hres == -4, "IHlink_SetStringReference should have failed with 0xFFFFFFFC, instead: 0x%08x\n", hres);
1269
1270     IHlink_Release(link);
1271 }
1272
1273 #define setStringRef(h,f,t,l) r_setStringRef(__LINE__,h,f,t,l)
1274 static void r_setStringRef(unsigned line, IHlink *hlink, DWORD flags, const WCHAR *tgt, const WCHAR *loc)
1275 {
1276     HRESULT hres;
1277     hres = IHlink_SetStringReference(hlink, flags, tgt, loc);
1278     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1279 }
1280
1281 #define getStringRef(h,t,l) r_getStringRef(__LINE__,h,t,l)
1282 static void r_getStringRef(unsigned line, IHlink *hlink, const WCHAR *exp_tgt, const WCHAR *exp_loc)
1283 {
1284     HRESULT hres;
1285     WCHAR *fnd_tgt, *fnd_loc;
1286
1287     hres = IHlink_GetStringReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1288     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1289
1290     if(exp_tgt)
1291         ok_(__FILE__,line) (!lstrcmpW(fnd_tgt, exp_tgt), "Found string target should have been %s, was: %s\n", wine_dbgstr_w(exp_tgt), wine_dbgstr_w(fnd_tgt));
1292     else
1293         ok_(__FILE__,line) (fnd_tgt == NULL, "Found string target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1294
1295     if(exp_loc)
1296         ok_(__FILE__,line) (!lstrcmpW(fnd_loc, exp_loc), "Found string location should have been %s, was: %s\n", wine_dbgstr_w(exp_loc), wine_dbgstr_w(fnd_loc));
1297     else
1298         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1299
1300     CoTaskMemFree(fnd_tgt);
1301     CoTaskMemFree(fnd_loc);
1302 }
1303
1304 #define setMonikerRef(h,f,t,l) r_setMonikerRef(__LINE__,h,f,t,l)
1305 static void r_setMonikerRef(unsigned line, IHlink *hlink, DWORD flags, IMoniker *tgt, const WCHAR *loc)
1306 {
1307     HRESULT hres;
1308     hres = IHlink_SetMonikerReference(hlink, flags, tgt, loc);
1309     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1310 }
1311
1312 /* passing 0xFFFFFFFF as exp_tgt will return the retrieved target & not test it */
1313 #define getMonikerRef(h,t,l) r_getMonikerRef(__LINE__,h,t,l)
1314 static IMoniker *r_getMonikerRef(unsigned line, IHlink *hlink, IMoniker *exp_tgt, const WCHAR *exp_loc)
1315 {
1316     HRESULT hres;
1317     IMoniker *fnd_tgt;
1318     WCHAR *fnd_loc;
1319
1320     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1321     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1322
1323     if(exp_loc)
1324         ok_(__FILE__,line) (!lstrcmpW(fnd_loc, exp_loc), "Found string location should have been %s, was: %s\n", wine_dbgstr_w(exp_loc), wine_dbgstr_w(fnd_loc));
1325     else
1326         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1327
1328     CoTaskMemFree(fnd_loc);
1329
1330     if(exp_tgt == (IMoniker*)0xFFFFFFFF)
1331         return fnd_tgt;
1332
1333     ok_(__FILE__,line) (fnd_tgt == exp_tgt, "Found moniker target should have been %p, was: %p\n", exp_tgt, fnd_tgt);
1334
1335     if(fnd_tgt)
1336         IMoniker_Release(fnd_tgt);
1337
1338     return NULL;
1339 }
1340
1341 static void test_HlinkMoniker(void)
1342 {
1343     IHlink *hlink;
1344     IMoniker *aMon, *file_mon;
1345     static const WCHAR emptyW[] = {0};
1346     static const WCHAR wordsW[] = {'w','o','r','d','s',0};
1347     static const WCHAR aW[] = {'a',0};
1348     static const WCHAR bW[] = {'b',0};
1349     HRESULT hres;
1350
1351     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1352     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1353     getStringRef(hlink, NULL, NULL);
1354     getMonikerRef(hlink, NULL, NULL);
1355
1356     /* setting a string target creates a moniker reference */
1357     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, aW, wordsW);
1358     getStringRef(hlink, aW, wordsW);
1359     aMon = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, wordsW);
1360     ok(aMon != NULL, "Moniker from %s target should not be NULL\n", wine_dbgstr_w(aW));
1361     if(aMon)
1362         IMoniker_Release(aMon);
1363
1364     /* setting target & location to the empty string deletes the moniker
1365      * reference */
1366     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, emptyW, emptyW);
1367     getStringRef(hlink, NULL, NULL);
1368     getMonikerRef(hlink, NULL, NULL);
1369
1370     /* setting a moniker target also sets the target string to that moniker's
1371      * display name */
1372     hres = CreateFileMoniker(bW, &file_mon);
1373     ok(hres == S_OK, "CreateFileMoniker failed: 0x%08x\n", hres);
1374
1375     setMonikerRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, file_mon, wordsW);
1376     getStringRef(hlink, bW, wordsW);
1377     getMonikerRef(hlink, file_mon, wordsW);
1378
1379     IMoniker_Release(file_mon);
1380
1381     IHlink_Release(hlink);
1382 }
1383
1384 static void test_HashLink(void)
1385 {
1386     IHlink *hlink;
1387     IMoniker *pmk;
1388     const WCHAR hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r',0};
1389     const WCHAR two_hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1390     const WCHAR hash_no_tgtW[] = {'#','a','n','a','n','c','h','o','r',0};
1391     const WCHAR tgt_partW[] = {'a','f','i','l','e',0};
1392     const WCHAR loc_partW[] = {'a','n','a','n','c','h','o','r',0};
1393     const WCHAR two_hash_loc_partW[] = {'a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1394     const WCHAR test_locW[] = {'t','e','s','t','l','o','c',0};
1395     HRESULT hres;
1396
1397     /* simple single hash test */
1398     hres = HlinkCreateFromString(hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1399     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1400     ok(hlink != NULL, "Didn't get an hlink\n");
1401
1402     if(hlink){
1403         getStringRef(hlink, tgt_partW, loc_partW);
1404         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1405         ok(pmk != NULL, "Found moniker should not be NULL\n");
1406         if(pmk)
1407             IMoniker_Release(pmk);
1408
1409         setStringRef(hlink, HLINKSETF_TARGET, hash_targetW, NULL);
1410         getStringRef(hlink, hash_targetW, loc_partW);
1411
1412         IHlink_Release(hlink);
1413     }
1414
1415     /* two hashes in the target */
1416     hres = HlinkCreateFromString(two_hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1417     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1418     ok(hlink != NULL, "Didn't get an hlink\n");
1419
1420     if(hlink){
1421         getStringRef(hlink, tgt_partW, two_hash_loc_partW);
1422         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, two_hash_loc_partW);
1423         ok(pmk != NULL, "Found moniker should not be NULL\n");
1424         if(pmk)
1425             IMoniker_Release(pmk);
1426
1427         IHlink_Release(hlink);
1428     }
1429
1430     /* target with hash plus a location string */
1431     hres = HlinkCreateFromString(hash_targetW, test_locW, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1432     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1433     ok(hlink != NULL, "Didn't get an hlink\n");
1434
1435     if(hlink){
1436         getStringRef(hlink, tgt_partW, test_locW);
1437         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, test_locW);
1438         ok(pmk != NULL, "Found moniker should not be NULL\n");
1439         if(pmk)
1440             IMoniker_Release(pmk);
1441
1442         IHlink_Release(hlink);
1443     }
1444
1445     /* target with hash containing no "target part" */
1446     hres = HlinkCreateFromString(hash_no_tgtW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1447     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1448     ok(hlink != NULL, "Didn't get an hlink\n");
1449
1450     if(hlink){
1451         getStringRef(hlink, NULL, loc_partW);
1452         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1453         ok(pmk == NULL, "Found moniker should be NULL\n");
1454         if(pmk)
1455             IMoniker_Release(pmk);
1456
1457         IHlink_Release(hlink);
1458     }
1459 }
1460
1461 static WCHAR site_monikerW[] = {'S','I','T','E','_','M','O','N','I','K','E','R',0};
1462 static WCHAR ref_monikerW[] = {'R','E','F','_','M','O','N','I','K','E','R',0};
1463
1464 static HRESULT WINAPI hls_test_Moniker_BindToStorage(IMoniker *iface,
1465         IBindCtx *pbc, IMoniker *toLeft, REFIID riid, void **obj)
1466 {
1467     ok(0, "BTS: %p %p %p %p %p\n", iface, pbc, toLeft, riid, obj);
1468     return E_NOTIMPL;
1469 }
1470
1471 static HRESULT WINAPI hls_site_Moniker_ComposeWith(IMoniker *iface,
1472         IMoniker *right, BOOL onlyIfNotGeneric, IMoniker **composite)
1473 {
1474     LPOLESTR rightName;
1475     HRESULT hres;
1476
1477     ok(onlyIfNotGeneric == 0, "Expected onlyIfNotGeneric to be FALSE\n");
1478
1479     CHECK_EXPECT(ComposeWith);
1480
1481     hres = IMoniker_GetDisplayName(right, NULL, NULL, &rightName);
1482     ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres);
1483     ok(!lstrcmpW(rightName, ref_monikerW),
1484             "Expected to get moniker set via SetMonikerReference, instead got: %s\n",
1485             wine_dbgstr_w(rightName));
1486     CoTaskMemFree(rightName);
1487
1488     *composite = NULL;
1489
1490     /* unlikely error code to verify this return result is used */
1491     return E_OUTOFMEMORY;
1492 }
1493
1494 static HRESULT WINAPI hls_site_Moniker_GetDisplayName(IMoniker *iface,
1495         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1496 {
1497     *displayName = CoTaskMemAlloc(sizeof(site_monikerW));
1498     memcpy(*displayName, site_monikerW, sizeof(site_monikerW));
1499     return S_OK;
1500 }
1501
1502 static HRESULT WINAPI hls_ref_Moniker_GetDisplayName(IMoniker *iface,
1503         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1504 {
1505     *displayName = CoTaskMemAlloc(sizeof(ref_monikerW));
1506     memcpy(*displayName, ref_monikerW, sizeof(ref_monikerW));
1507     return S_OK;
1508 }
1509
1510 static HRESULT WINAPI hls_test_Moniker_IsSystemMoniker(IMoniker *iface,
1511         DWORD *mksys)
1512 {
1513     return S_FALSE;
1514 }
1515
1516 static IMonikerVtbl hls_site_MonikerVtbl = {
1517     Moniker_QueryInterface,
1518     Moniker_AddRef,
1519     Moniker_Release,
1520     Moniker_GetClassID,
1521     Moniker_IsDirty,
1522     Moniker_Load,
1523     Moniker_Save,
1524     Moniker_GetSizeMax,
1525     Moniker_BindToObject,
1526     hls_test_Moniker_BindToStorage,
1527     Moniker_Reduce,
1528     hls_site_Moniker_ComposeWith,
1529     Moniker_Enum,
1530     Moniker_IsEqual,
1531     Moniker_Hash,
1532     Moniker_IsRunning,
1533     Moniker_GetTimeOfLastChange,
1534     Moniker_Inverse,
1535     Moniker_CommonPrefixWith,
1536     Moniker_RelativePathTo,
1537     hls_site_Moniker_GetDisplayName,
1538     Moniker_ParseDisplayName,
1539     hls_test_Moniker_IsSystemMoniker
1540 };
1541
1542 static IMonikerVtbl hls_ref_MonikerVtbl = {
1543     Moniker_QueryInterface,
1544     Moniker_AddRef,
1545     Moniker_Release,
1546     Moniker_GetClassID,
1547     Moniker_IsDirty,
1548     Moniker_Load,
1549     Moniker_Save,
1550     Moniker_GetSizeMax,
1551     Moniker_BindToObject,
1552     hls_test_Moniker_BindToStorage,
1553     Moniker_Reduce,
1554     Moniker_ComposeWith,
1555     Moniker_Enum,
1556     Moniker_IsEqual,
1557     Moniker_Hash,
1558     Moniker_IsRunning,
1559     Moniker_GetTimeOfLastChange,
1560     Moniker_Inverse,
1561     Moniker_CommonPrefixWith,
1562     Moniker_RelativePathTo,
1563     hls_ref_Moniker_GetDisplayName,
1564     Moniker_ParseDisplayName,
1565     hls_test_Moniker_IsSystemMoniker
1566 };
1567
1568 static IMoniker hls_site_Moniker = { &hls_site_MonikerVtbl };
1569 static IMoniker hls_ref_Moniker = { &hls_ref_MonikerVtbl };
1570
1571 static HRESULT WINAPI hls_QueryInterface(IHlinkSite *iface, REFGUID iid,
1572         void **obj)
1573 {
1574     ok(0, "QI: %p %s %p\n", iface, debugstr_guid(iid), obj);
1575     return E_NOTIMPL;
1576 }
1577
1578 static ULONG WINAPI hls_AddRef(IHlinkSite *iface)
1579 {
1580     return 2;
1581 }
1582
1583 static ULONG WINAPI hls_Release(IHlinkSite *iface)
1584 {
1585     return 1;
1586 }
1587
1588 static HRESULT WINAPI hls_QueryService(IHlinkSite *iface, DWORD siteData,
1589         REFGUID service, REFIID riid, IUnknown **punk)
1590 {
1591     ok(0, "QS: %p %x %s %s %p\n", iface, siteData, debugstr_guid(service),
1592             debugstr_guid(riid), punk);
1593     return E_NOTIMPL;
1594 }
1595
1596 static HRESULT WINAPI hls_GetMoniker(IHlinkSite *iface, DWORD siteData,
1597         DWORD assign, DWORD which, IMoniker **pmk)
1598 {
1599     ok(siteData == 17, "Expected siteData == 17, got: %d\n", siteData);
1600     *pmk = &hls_site_Moniker;
1601     return S_OK;
1602 }
1603
1604 static HRESULT WINAPI hls_ReadyToNavigate(IHlinkSite *iface, DWORD siteData,
1605         DWORD reserved)
1606 {
1607     ok(0, "RTN: %p %x %x\n", iface, siteData, reserved);
1608     return E_NOTIMPL;
1609 }
1610
1611 static HRESULT WINAPI hls_OnNavigationComplete(IHlinkSite *iface,
1612         DWORD siteData, DWORD reserved, HRESULT error, LPCWSTR errorStr)
1613 {
1614     CHECK_EXPECT(OnNavigationComplete);
1615     ok(siteData == 17, "Expected siteData == 17, got: %d\n", siteData);
1616     ok(error == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", error);
1617     return E_NOTIMPL;
1618 }
1619
1620 static IHlinkSiteVtbl HlinkSiteVtbl = {
1621     hls_QueryInterface,
1622     hls_AddRef,
1623     hls_Release,
1624     hls_QueryService,
1625     hls_GetMoniker,
1626     hls_ReadyToNavigate,
1627     hls_OnNavigationComplete
1628 };
1629
1630 static IHlinkSite HlinkSite = { &HlinkSiteVtbl };
1631
1632 static void test_HlinkSite(void)
1633 {
1634     IHlink *hl;
1635     IMoniker *mon_ref;
1636     IBindCtx *pbc;
1637     HRESULT hres;
1638
1639     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
1640             &IID_IHlink, (LPVOID*)&hl);
1641     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
1642     getMonikerRef(hl, NULL, NULL);
1643
1644     hres = IHlink_SetHlinkSite(hl, &HlinkSite, 17);
1645     ok(hres == S_OK, "SetHlinkSite failed: %08x\n", hres);
1646     getMonikerRef(hl, NULL, NULL);
1647     getStringRef(hl, NULL, NULL);
1648
1649     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1650     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1651     ok(mon_ref == NULL, "Didn't get expected moniker, instead: %p\n", mon_ref);
1652
1653     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1654     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1655     ok(mon_ref == &hls_site_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1656
1657     SET_EXPECT(Reduce);
1658     SET_EXPECT(Enum);
1659     hres = IHlink_SetMonikerReference(hl, HLINKSETF_TARGET, &hls_ref_Moniker, NULL);
1660     ok(hres == S_OK, "SetMonikerReference failed: %08x\n", hres);
1661     todo_wine CHECK_CALLED(Reduce);
1662     todo_wine CHECK_CALLED(Enum);
1663
1664     getMonikerRef(hl, &hls_ref_Moniker, NULL);
1665
1666     SET_EXPECT(Enum);
1667     getStringRef(hl, ref_monikerW, NULL);
1668     todo_wine CHECK_CALLED(Enum);
1669
1670     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1671     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1672     ok(mon_ref == &hls_ref_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1673     IMoniker_Release(mon_ref);
1674
1675     SET_EXPECT(ComposeWith);
1676     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1677     ok(hres == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", hres);
1678     ok(mon_ref == NULL, "Shouldn't have got a Moniker, got: %p\n", mon_ref);
1679     CHECK_CALLED(ComposeWith);
1680
1681     hres = CreateBindCtx(0, &pbc);
1682     ok(hres == S_OK, "CreateBindCtx failed: %08x\n", hres);
1683
1684     SET_EXPECT(ComposeWith);
1685     SET_EXPECT(OnNavigationComplete);
1686     hres = IHlink_Navigate(hl, 0, pbc, NULL, NULL);
1687     ok(hres == E_OUTOFMEMORY, "Navigate should've failed: %08x\n", hres);
1688     CHECK_CALLED(ComposeWith);
1689     CHECK_CALLED(OnNavigationComplete);
1690
1691     IBindCtx_Release(pbc);
1692     IHlink_Release(hl);
1693
1694     SET_EXPECT(Reduce);
1695     SET_EXPECT(Enum);
1696     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, NULL, NULL, &HlinkSite, 17,
1697             NULL, &IID_IHlink, (LPVOID*)&hl);
1698     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1699     todo_wine CHECK_CALLED(Reduce);
1700     todo_wine CHECK_CALLED(Enum);
1701     getMonikerRef(hl, &hls_ref_Moniker, NULL);
1702     IHlink_Release(hl);
1703
1704     hres = HlinkCreateFromMoniker(NULL, NULL, NULL, &HlinkSite, 17,
1705             NULL, &IID_IHlink, (LPVOID*)&hl);
1706     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1707     getMonikerRef(hl, NULL, NULL);
1708     IHlink_Release(hl);
1709 }
1710
1711 static void test_HlinkClone(void)
1712 {
1713     HRESULT hres;
1714     IHlink *hl, *cloned = NULL;
1715     IMoniker *dummy, *fnd_mk;
1716     IHlinkSite *fnd_site;
1717     WCHAR *fnd_name;
1718     DWORD fnd_data;
1719     const WCHAR one[] = {'1',0};
1720     const WCHAR two[] = {'2',0};
1721     const WCHAR name[] = {'a',0};
1722
1723     hres = HlinkClone(NULL, NULL, NULL, 0, NULL);
1724     ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1725
1726     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
1727             &IID_IHlink, (void**)&hl);
1728     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
1729
1730     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, NULL);
1731     ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1732
1733     if(0){ /* crash on Windows XP */
1734         hres = HlinkClone(hl, NULL, NULL, 0, NULL);
1735         ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1736
1737         hres = HlinkClone(hl, NULL, NULL, 0, (void**)&cloned);
1738         ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1739     }
1740
1741     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1742     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1743     ok(cloned != NULL, "Didn't get a clone\n");
1744     getMonikerRef(cloned, NULL, NULL);
1745     IHlink_Release(cloned);
1746
1747     IHlink_Release(hl);
1748
1749     SET_EXPECT(Reduce);
1750     SET_EXPECT(Enum);
1751     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, two, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hl);
1752     todo_wine CHECK_CALLED(Reduce);
1753     todo_wine CHECK_CALLED(Enum);
1754     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1755     getMonikerRef(hl, &hls_ref_Moniker, two);
1756
1757     SET_EXPECT(Save);
1758     SET_EXPECT(GetClassID);
1759     cloned = (IHlink*)0xdeadbeef;
1760     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1761     /* fails because of invalid CLSID given by Moniker_GetClassID */
1762     ok(hres == REGDB_E_CLASSNOTREG, "Wrong error code: %08x\n", hres);
1763     ok(cloned == NULL, "Shouldn't have gotten a clone\n");
1764     CHECK_CALLED(Save);
1765     CHECK_CALLED(GetClassID);
1766
1767     IHlink_Release(hl);
1768
1769     hres = CreateItemMoniker(one, one, &dummy);
1770     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1771
1772     hres = HlinkCreateFromMoniker(dummy, two, name, &HlinkSite, 17, NULL, &IID_IHlink, (void**)&hl);
1773     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1774     getMonikerRef(hl, dummy, two);
1775
1776     cloned = NULL;
1777     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1778     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1779     ok(cloned != NULL, "Should have gotten a clone\n");
1780
1781     fnd_mk = getMonikerRef(cloned, (IMoniker*)0xFFFFFFFF, two);
1782     ok(fnd_mk != NULL, "Expected non-null Moniker\n");
1783     ok(fnd_mk != dummy, "Expected a new Moniker to be created\n");
1784
1785     fnd_name = NULL;
1786     hres = IHlink_GetFriendlyName(cloned, HLFNAMEF_DEFAULT, &fnd_name);
1787     ok(hres == S_OK, "GetFriendlyName failed: %08x\n", hres);
1788     ok(fnd_name != NULL, "Expected friendly name to be non-NULL\n");
1789     ok(lstrcmpW(fnd_name, name) == 0, "Expected friendly name to be %s, was %s\n",
1790             wine_dbgstr_w(name), wine_dbgstr_w(fnd_name));
1791     CoTaskMemFree(fnd_name);
1792
1793     fnd_site = (IHlinkSite*)0xdeadbeef;
1794     fnd_data = 4;
1795     hres = IHlink_GetHlinkSite(cloned, &fnd_site, &fnd_data);
1796     ok(hres == S_OK, "GetHlinkSite failed: %08x\n", hres);
1797     ok(fnd_site == NULL, "Expected NULL site\n");
1798     ok(fnd_data == 4, "Expected site data to be 4, was: %d\n", fnd_data);
1799
1800     IHlink_Release(cloned);
1801     IHlink_Release(hl);
1802
1803     hres = HlinkCreateFromMoniker(dummy, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hl);
1804     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1805     getMonikerRef(hl, dummy, NULL);
1806
1807     cloned = NULL;
1808     hres = HlinkClone(hl, &IID_IHlink, &HlinkSite, 17, (void**)&cloned);
1809     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1810     ok(cloned != NULL, "Should have gotten a clone\n");
1811
1812     fnd_mk = getMonikerRef(cloned, (IMoniker*)0xFFFFFFFF, NULL);
1813     ok(fnd_mk != NULL, "Expected non-null Moniker\n");
1814     ok(fnd_mk != dummy, "Expected a new Moniker to be created\n");
1815
1816     fnd_site = (IHlinkSite*)0xdeadbeef;
1817     fnd_data = 4;
1818     hres = IHlink_GetHlinkSite(cloned, &fnd_site, &fnd_data);
1819     ok(hres == S_OK, "GetHlinkSite failed: %08x\n", hres);
1820     ok(fnd_site == &HlinkSite, "Expected found site to be HlinkSite, was: %p\n", fnd_site);
1821     ok(fnd_data == 17, "Expected site data to be 17, was: %d\n", fnd_data);
1822
1823     IHlink_Release(cloned);
1824     IHlink_Release(hl);
1825
1826     IMoniker_Release(dummy);
1827 }
1828
1829 START_TEST(hlink)
1830 {
1831     CoInitialize(NULL);
1832
1833     test_HlinkIsShortcut();
1834     test_reference();
1835     test_persist();
1836     test_special_reference();
1837     test_HlinkCreateExtensionServices();
1838     test_HlinkParseDisplayName();
1839     test_HlinkResolveMonikerForData();
1840     test_HlinkGetSetMonikerReference();
1841     test_HlinkGetSetStringReference();
1842     test_HlinkMoniker();
1843     test_HashLink();
1844     test_HlinkSite();
1845     test_HlinkClone();
1846
1847     CoUninitialize();
1848 }