include/msvcrt: Define more CPU control word flags.
[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(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1069     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1070     IMoniker_Release(found_trgt);
1071     CoTaskMemFree(found_loc);
1072
1073     /* set target => dummy2 */
1074     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, dummy2, one);
1075     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1076
1077     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1078     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1079     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1080     IMoniker_Release(found_trgt);
1081     CoTaskMemFree(found_loc);
1082
1083     /* set target => dummy, location => one */
1084     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, dummy, one);
1085     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1086
1087     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1088     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1089     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1090     IMoniker_Release(found_trgt);
1091     CoTaskMemFree(found_loc);
1092
1093     /* no HLINKSETF flags */
1094     hres = IHlink_SetMonikerReference(hlink, 0, dummy2, two);
1095     ok(hres == E_INVALIDARG, "IHlink_SetMonikerReference should've failed with E_INVALIDARG (0x%08x), failed with 0x%08x\n", E_INVALIDARG, hres);
1096
1097     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1098     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1099     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1100     IMoniker_Release(found_trgt);
1101     CoTaskMemFree(found_loc);
1102
1103     /* invalid HLINKSETF flags */
1104     hres = IHlink_SetMonikerReference(hlink, 12, dummy2, two);
1105     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1106     if (0) ok(hres == 12, "IHlink_SetMonikerReference should've failed with 0x%08x, failed with 0x%08x\n", 12, hres);
1107
1108     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1109     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1110     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1111     IMoniker_Release(found_trgt);
1112     CoTaskMemFree(found_loc);
1113
1114     /* valid & invalid HLINKSETF flags */
1115     hres = IHlink_SetMonikerReference(hlink, 12 | HLINKSETF_TARGET, dummy2, two);
1116     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1117
1118     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1119     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1120     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1121     IMoniker_Release(found_trgt);
1122     CoTaskMemFree(found_loc);
1123
1124     /* NULL args */
1125     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, NULL, NULL);
1126     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1127
1128     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1129     ok(found_trgt == NULL, "Found target should've been %p, was: %p\n", NULL, found_trgt);
1130     ok(found_loc == NULL, "Found location should've been %s, was: %s\n", wine_dbgstr_w(NULL), wine_dbgstr_w(found_loc));
1131     if(found_trgt)
1132         IMoniker_Release(found_trgt);
1133
1134     IHlink_Release(hlink);
1135     IMoniker_Release(dummy2);
1136     IMoniker_Release(dummy);
1137 }
1138
1139 static void test_HlinkGetSetStringReference(void)
1140 {
1141     IHlink *link;
1142     static const WCHAR one[] = {'1',0};
1143     static const WCHAR two[] = {'2',0};
1144     static const WCHAR three[] = {'3',0};
1145     static const WCHAR empty[] = {0};
1146     WCHAR *fnd_tgt, *fnd_loc;
1147     HRESULT hres;
1148
1149     /* create a new hlink: target => NULL, location => one */
1150     hres = HlinkCreateFromMoniker(NULL, one, empty, NULL, 0, NULL, &IID_IHlink, (void**)&link);
1151     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1152
1153     /* test setting/getting location */
1154     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1155     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1156     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1157     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1158     CoTaskMemFree(fnd_tgt);
1159     CoTaskMemFree(fnd_loc);
1160
1161     hres = IHlink_SetStringReference(link, HLINKSETF_LOCATION, one, two);
1162     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1163
1164     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1165     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1166     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1167     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1168     CoTaskMemFree(fnd_tgt);
1169     CoTaskMemFree(fnd_loc);
1170
1171     hres = IHlink_SetStringReference(link, -HLINKSETF_LOCATION, two, one);
1172     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1173
1174     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1175     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1176     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1177     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1178     CoTaskMemFree(fnd_tgt);
1179     CoTaskMemFree(fnd_loc);
1180
1181     /* test setting/getting target */
1182     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET, two, three);
1183     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1184
1185     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1186     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1187     ok(!lstrcmpW(fnd_tgt, two), "Found target should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_tgt));
1188     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1189     CoTaskMemFree(fnd_tgt);
1190     CoTaskMemFree(fnd_loc);
1191
1192     hres = IHlink_SetStringReference(link, -HLINKSETF_TARGET, three, two);
1193     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1194
1195     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1196     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1197     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1198     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1199     CoTaskMemFree(fnd_tgt);
1200     CoTaskMemFree(fnd_loc);
1201
1202     /* test setting/getting both */
1203     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET | HLINKSETF_LOCATION, one, two);
1204     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1205
1206     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1207     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1208     ok(!lstrcmpW(fnd_tgt, one), "Found target should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_tgt));
1209     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1210     CoTaskMemFree(fnd_tgt);
1211     CoTaskMemFree(fnd_loc);
1212
1213     hres = IHlink_SetStringReference(link, -(HLINKSETF_TARGET | HLINKSETF_LOCATION), three, one);
1214     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1215
1216     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1217     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1218     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1219     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1220     CoTaskMemFree(fnd_tgt);
1221     CoTaskMemFree(fnd_loc);
1222
1223     /* test invalid flags/params */
1224     hres = IHlink_GetStringReference(link, 4, &fnd_tgt, &fnd_loc);
1225     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1226            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1227     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1228     ok(fnd_loc == NULL, "Found location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1229     CoTaskMemFree(fnd_tgt);
1230     CoTaskMemFree(fnd_loc);
1231
1232     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, NULL);
1233     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1234            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1235     CoTaskMemFree(fnd_tgt);
1236
1237     hres = IHlink_GetStringReference(link, -1, NULL, NULL);
1238     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1239
1240     hres = IHlink_GetStringReference(link, -1, NULL, &fnd_loc);
1241     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1242     CoTaskMemFree(fnd_loc);
1243
1244     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, &fnd_loc);
1245     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1246            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1247     CoTaskMemFree(fnd_tgt);
1248     CoTaskMemFree(fnd_loc);
1249
1250     hres = IHlink_GetStringReference(link, -2, &fnd_tgt, &fnd_loc);
1251     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1252            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1253     CoTaskMemFree(fnd_tgt);
1254     CoTaskMemFree(fnd_loc);
1255
1256     hres = IHlink_SetStringReference(link, 4, NULL, NULL);
1257     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1258     if (0) ok(hres == 4, "IHlink_SetStringReference should have failed with 0x4, instead: 0x%08x\n", hres);
1259
1260     hres = IHlink_SetStringReference(link, -4, NULL, NULL);
1261     if (0) ok(hres == -4, "IHlink_SetStringReference should have failed with 0xFFFFFFFC, instead: 0x%08x\n", hres);
1262
1263     IHlink_Release(link);
1264 }
1265
1266 #define setStringRef(h,f,t,l) r_setStringRef(__LINE__,h,f,t,l)
1267 static void r_setStringRef(unsigned line, IHlink *hlink, DWORD flags, const WCHAR *tgt, const WCHAR *loc)
1268 {
1269     HRESULT hres;
1270     hres = IHlink_SetStringReference(hlink, flags, tgt, loc);
1271     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1272 }
1273
1274 #define getStringRef(h,t,l) r_getStringRef(__LINE__,h,t,l)
1275 static void r_getStringRef(unsigned line, IHlink *hlink, const WCHAR *exp_tgt, const WCHAR *exp_loc)
1276 {
1277     HRESULT hres;
1278     WCHAR *fnd_tgt, *fnd_loc;
1279
1280     hres = IHlink_GetStringReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1281     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1282
1283     if(exp_tgt)
1284         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));
1285     else
1286         ok_(__FILE__,line) (fnd_tgt == NULL, "Found string target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1287
1288     if(exp_loc)
1289         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));
1290     else
1291         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1292
1293     CoTaskMemFree(fnd_tgt);
1294     CoTaskMemFree(fnd_loc);
1295 }
1296
1297 #define setMonikerRef(h,f,t,l) r_setMonikerRef(__LINE__,h,f,t,l)
1298 static void r_setMonikerRef(unsigned line, IHlink *hlink, DWORD flags, IMoniker *tgt, const WCHAR *loc)
1299 {
1300     HRESULT hres;
1301     hres = IHlink_SetMonikerReference(hlink, flags, tgt, loc);
1302     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1303 }
1304
1305 /* passing 0xFFFFFFFF as exp_tgt will return the retrieved target & not test it */
1306 #define getMonikerRef(h,t,l) r_getMonikerRef(__LINE__,h,t,l)
1307 static IMoniker *r_getMonikerRef(unsigned line, IHlink *hlink, IMoniker *exp_tgt, const WCHAR *exp_loc)
1308 {
1309     HRESULT hres;
1310     IMoniker *fnd_tgt;
1311     WCHAR *fnd_loc;
1312
1313     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1314     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1315
1316     if(exp_loc)
1317         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));
1318     else
1319         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1320
1321     CoTaskMemFree(fnd_loc);
1322
1323     if(exp_tgt == (IMoniker*)0xFFFFFFFF)
1324         return fnd_tgt;
1325
1326     ok_(__FILE__,line) (fnd_tgt == exp_tgt, "Found moniker target should have been %p, was: %p\n", exp_tgt, fnd_tgt);
1327
1328     if(fnd_tgt)
1329         IMoniker_Release(fnd_tgt);
1330
1331     return NULL;
1332 }
1333
1334 static void test_HlinkMoniker(void)
1335 {
1336     IHlink *hlink;
1337     IMoniker *aMon, *file_mon;
1338     static const WCHAR emptyW[] = {0};
1339     static const WCHAR wordsW[] = {'w','o','r','d','s',0};
1340     static const WCHAR aW[] = {'a',0};
1341     static const WCHAR bW[] = {'b',0};
1342     HRESULT hres;
1343
1344     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1345     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1346     getStringRef(hlink, NULL, NULL);
1347     getMonikerRef(hlink, NULL, NULL);
1348
1349     /* setting a string target creates a moniker reference */
1350     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, aW, wordsW);
1351     getStringRef(hlink, aW, wordsW);
1352     aMon = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, wordsW);
1353     ok(aMon != NULL, "Moniker from %s target should not be NULL\n", wine_dbgstr_w(aW));
1354     if(aMon)
1355         IMoniker_Release(aMon);
1356
1357     /* setting target & location to the empty string deletes the moniker
1358      * reference */
1359     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, emptyW, emptyW);
1360     getStringRef(hlink, NULL, NULL);
1361     getMonikerRef(hlink, NULL, NULL);
1362
1363     /* setting a moniker target also sets the target string to that moniker's
1364      * display name */
1365     hres = CreateFileMoniker(bW, &file_mon);
1366     ok(hres == S_OK, "CreateFileMoniker failed: 0x%08x\n", hres);
1367
1368     setMonikerRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, file_mon, wordsW);
1369     getStringRef(hlink, bW, wordsW);
1370     getMonikerRef(hlink, file_mon, wordsW);
1371
1372     IMoniker_Release(file_mon);
1373
1374     IHlink_Release(hlink);
1375 }
1376
1377 static void test_HashLink(void)
1378 {
1379     IHlink *hlink;
1380     IMoniker *pmk;
1381     const WCHAR hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r',0};
1382     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};
1383     const WCHAR hash_no_tgtW[] = {'#','a','n','a','n','c','h','o','r',0};
1384     const WCHAR tgt_partW[] = {'a','f','i','l','e',0};
1385     const WCHAR loc_partW[] = {'a','n','a','n','c','h','o','r',0};
1386     const WCHAR two_hash_loc_partW[] = {'a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1387     const WCHAR test_locW[] = {'t','e','s','t','l','o','c',0};
1388     HRESULT hres;
1389
1390     /* simple single hash test */
1391     hres = HlinkCreateFromString(hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1392     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1393     ok(hlink != NULL, "Didn't get an hlink\n");
1394
1395     if(hlink){
1396         getStringRef(hlink, tgt_partW, loc_partW);
1397         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1398         ok(pmk != NULL, "Found moniker should not be NULL\n");
1399         if(pmk)
1400             IMoniker_Release(pmk);
1401
1402         setStringRef(hlink, HLINKSETF_TARGET, hash_targetW, NULL);
1403         getStringRef(hlink, hash_targetW, loc_partW);
1404
1405         IHlink_Release(hlink);
1406     }
1407
1408     /* two hashes in the target */
1409     hres = HlinkCreateFromString(two_hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1410     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1411     ok(hlink != NULL, "Didn't get an hlink\n");
1412
1413     if(hlink){
1414         getStringRef(hlink, tgt_partW, two_hash_loc_partW);
1415         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, two_hash_loc_partW);
1416         ok(pmk != NULL, "Found moniker should not be NULL\n");
1417         if(pmk)
1418             IMoniker_Release(pmk);
1419
1420         IHlink_Release(hlink);
1421     }
1422
1423     /* target with hash plus a location string */
1424     hres = HlinkCreateFromString(hash_targetW, test_locW, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1425     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1426     ok(hlink != NULL, "Didn't get an hlink\n");
1427
1428     if(hlink){
1429         getStringRef(hlink, tgt_partW, test_locW);
1430         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, test_locW);
1431         ok(pmk != NULL, "Found moniker should not be NULL\n");
1432         if(pmk)
1433             IMoniker_Release(pmk);
1434
1435         IHlink_Release(hlink);
1436     }
1437
1438     /* target with hash containing no "target part" */
1439     hres = HlinkCreateFromString(hash_no_tgtW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1440     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1441     ok(hlink != NULL, "Didn't get an hlink\n");
1442
1443     if(hlink){
1444         getStringRef(hlink, NULL, loc_partW);
1445         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1446         ok(pmk == NULL, "Found moniker should be NULL\n");
1447         if(pmk)
1448             IMoniker_Release(pmk);
1449
1450         IHlink_Release(hlink);
1451     }
1452 }
1453
1454 static WCHAR site_monikerW[] = {'S','I','T','E','_','M','O','N','I','K','E','R',0};
1455 static WCHAR ref_monikerW[] = {'R','E','F','_','M','O','N','I','K','E','R',0};
1456
1457 static HRESULT WINAPI hls_test_Moniker_BindToStorage(IMoniker *iface,
1458         IBindCtx *pbc, IMoniker *toLeft, REFIID riid, void **obj)
1459 {
1460     ok(0, "BTS: %p %p %p %p %p\n", iface, pbc, toLeft, riid, obj);
1461     return E_NOTIMPL;
1462 }
1463
1464 static HRESULT WINAPI hls_site_Moniker_ComposeWith(IMoniker *iface,
1465         IMoniker *right, BOOL onlyIfNotGeneric, IMoniker **composite)
1466 {
1467     LPOLESTR rightName;
1468     HRESULT hres;
1469
1470     ok(onlyIfNotGeneric == 0, "Expected onlyIfNotGeneric to be FALSE\n");
1471
1472     CHECK_EXPECT(ComposeWith);
1473
1474     hres = IMoniker_GetDisplayName(right, NULL, NULL, &rightName);
1475     ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres);
1476     ok(!lstrcmpW(rightName, ref_monikerW),
1477             "Expected to get moniker set via SetMonikerReference, instead got: %s\n",
1478             wine_dbgstr_w(rightName));
1479     CoTaskMemFree(rightName);
1480
1481     *composite = NULL;
1482
1483     /* unlikely error code to verify this return result is used */
1484     return E_OUTOFMEMORY;
1485 }
1486
1487 static HRESULT WINAPI hls_site_Moniker_GetDisplayName(IMoniker *iface,
1488         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1489 {
1490     *displayName = CoTaskMemAlloc(sizeof(site_monikerW));
1491     memcpy(*displayName, site_monikerW, sizeof(site_monikerW));
1492     return S_OK;
1493 }
1494
1495 static HRESULT WINAPI hls_ref_Moniker_GetDisplayName(IMoniker *iface,
1496         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1497 {
1498     *displayName = CoTaskMemAlloc(sizeof(ref_monikerW));
1499     memcpy(*displayName, ref_monikerW, sizeof(ref_monikerW));
1500     return S_OK;
1501 }
1502
1503 static HRESULT WINAPI hls_test_Moniker_IsSystemMoniker(IMoniker *iface,
1504         DWORD *mksys)
1505 {
1506     return S_FALSE;
1507 }
1508
1509 static IMonikerVtbl hls_site_MonikerVtbl = {
1510     Moniker_QueryInterface,
1511     Moniker_AddRef,
1512     Moniker_Release,
1513     Moniker_GetClassID,
1514     Moniker_IsDirty,
1515     Moniker_Load,
1516     Moniker_Save,
1517     Moniker_GetSizeMax,
1518     Moniker_BindToObject,
1519     hls_test_Moniker_BindToStorage,
1520     Moniker_Reduce,
1521     hls_site_Moniker_ComposeWith,
1522     Moniker_Enum,
1523     Moniker_IsEqual,
1524     Moniker_Hash,
1525     Moniker_IsRunning,
1526     Moniker_GetTimeOfLastChange,
1527     Moniker_Inverse,
1528     Moniker_CommonPrefixWith,
1529     Moniker_RelativePathTo,
1530     hls_site_Moniker_GetDisplayName,
1531     Moniker_ParseDisplayName,
1532     hls_test_Moniker_IsSystemMoniker
1533 };
1534
1535 static IMonikerVtbl hls_ref_MonikerVtbl = {
1536     Moniker_QueryInterface,
1537     Moniker_AddRef,
1538     Moniker_Release,
1539     Moniker_GetClassID,
1540     Moniker_IsDirty,
1541     Moniker_Load,
1542     Moniker_Save,
1543     Moniker_GetSizeMax,
1544     Moniker_BindToObject,
1545     hls_test_Moniker_BindToStorage,
1546     Moniker_Reduce,
1547     Moniker_ComposeWith,
1548     Moniker_Enum,
1549     Moniker_IsEqual,
1550     Moniker_Hash,
1551     Moniker_IsRunning,
1552     Moniker_GetTimeOfLastChange,
1553     Moniker_Inverse,
1554     Moniker_CommonPrefixWith,
1555     Moniker_RelativePathTo,
1556     hls_ref_Moniker_GetDisplayName,
1557     Moniker_ParseDisplayName,
1558     hls_test_Moniker_IsSystemMoniker
1559 };
1560
1561 static IMoniker hls_site_Moniker = { &hls_site_MonikerVtbl };
1562 static IMoniker hls_ref_Moniker = { &hls_ref_MonikerVtbl };
1563
1564 static HRESULT WINAPI hls_QueryInterface(IHlinkSite *iface, REFGUID iid,
1565         void **obj)
1566 {
1567     ok(0, "QI: %p %s %p\n", iface, debugstr_guid(iid), obj);
1568     return E_NOTIMPL;
1569 }
1570
1571 static ULONG WINAPI hls_AddRef(IHlinkSite *iface)
1572 {
1573     return 2;
1574 }
1575
1576 static ULONG WINAPI hls_Release(IHlinkSite *iface)
1577 {
1578     return 1;
1579 }
1580
1581 static HRESULT WINAPI hls_QueryService(IHlinkSite *iface, DWORD siteData,
1582         REFGUID service, REFIID riid, IUnknown **punk)
1583 {
1584     ok(0, "QS: %p %x %s %s %p\n", iface, siteData, debugstr_guid(service),
1585             debugstr_guid(riid), punk);
1586     return E_NOTIMPL;
1587 }
1588
1589 static HRESULT WINAPI hls_GetMoniker(IHlinkSite *iface, DWORD siteData,
1590         DWORD assign, DWORD which, IMoniker **pmk)
1591 {
1592     ok(siteData == 17, "Expected siteData == 17, got: %d\n", siteData);
1593     *pmk = &hls_site_Moniker;
1594     return S_OK;
1595 }
1596
1597 static HRESULT WINAPI hls_ReadyToNavigate(IHlinkSite *iface, DWORD siteData,
1598         DWORD reserved)
1599 {
1600     ok(0, "RTN: %p %x %x\n", iface, siteData, reserved);
1601     return E_NOTIMPL;
1602 }
1603
1604 static HRESULT WINAPI hls_OnNavigationComplete(IHlinkSite *iface,
1605         DWORD siteData, DWORD reserved, HRESULT error, LPCWSTR errorStr)
1606 {
1607     CHECK_EXPECT(OnNavigationComplete);
1608     ok(siteData == 17, "Expected siteData == 17, got: %d\n", siteData);
1609     ok(error == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", error);
1610     return E_NOTIMPL;
1611 }
1612
1613 static IHlinkSiteVtbl HlinkSiteVtbl = {
1614     hls_QueryInterface,
1615     hls_AddRef,
1616     hls_Release,
1617     hls_QueryService,
1618     hls_GetMoniker,
1619     hls_ReadyToNavigate,
1620     hls_OnNavigationComplete
1621 };
1622
1623 static IHlinkSite HlinkSite = { &HlinkSiteVtbl };
1624
1625 static void test_HlinkSite(void)
1626 {
1627     IHlink *hl;
1628     IMoniker *mon_ref;
1629     IBindCtx *pbc;
1630     HRESULT hres;
1631
1632     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
1633             &IID_IHlink, (LPVOID*)&hl);
1634     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
1635     getMonikerRef(hl, NULL, NULL);
1636
1637     hres = IHlink_SetHlinkSite(hl, &HlinkSite, 17);
1638     ok(hres == S_OK, "SetHlinkSite failed: %08x\n", hres);
1639     getMonikerRef(hl, NULL, NULL);
1640     getStringRef(hl, NULL, NULL);
1641
1642     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1643     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1644     ok(mon_ref == NULL, "Didn't get expected moniker, instead: %p\n", mon_ref);
1645
1646     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1647     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1648     ok(mon_ref == &hls_site_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1649
1650     SET_EXPECT(Reduce);
1651     SET_EXPECT(Enum);
1652     hres = IHlink_SetMonikerReference(hl, HLINKSETF_TARGET, &hls_ref_Moniker, NULL);
1653     ok(hres == S_OK, "SetMonikerReference failed: %08x\n", hres);
1654     todo_wine CHECK_CALLED(Reduce);
1655     todo_wine CHECK_CALLED(Enum);
1656
1657     getMonikerRef(hl, &hls_ref_Moniker, NULL);
1658
1659     SET_EXPECT(Enum);
1660     getStringRef(hl, ref_monikerW, NULL);
1661     todo_wine CHECK_CALLED(Enum);
1662
1663     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1664     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1665     ok(mon_ref == &hls_ref_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1666     IMoniker_Release(mon_ref);
1667
1668     SET_EXPECT(ComposeWith);
1669     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1670     ok(hres == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", hres);
1671     ok(mon_ref == NULL, "Shouldn't have got a Moniker, got: %p\n", mon_ref);
1672     CHECK_CALLED(ComposeWith);
1673
1674     hres = CreateBindCtx(0, &pbc);
1675     ok(hres == S_OK, "CreateBindCtx failed: %08x\n", hres);
1676
1677     SET_EXPECT(ComposeWith);
1678     SET_EXPECT(OnNavigationComplete);
1679     hres = IHlink_Navigate(hl, 0, pbc, NULL, NULL);
1680     ok(hres == E_OUTOFMEMORY, "Navigate should've failed: %08x\n", hres);
1681     CHECK_CALLED(ComposeWith);
1682     CHECK_CALLED(OnNavigationComplete);
1683
1684     IBindCtx_Release(pbc);
1685     IHlink_Release(hl);
1686
1687     SET_EXPECT(Reduce);
1688     SET_EXPECT(Enum);
1689     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, NULL, NULL, &HlinkSite, 17,
1690             NULL, &IID_IHlink, (LPVOID*)&hl);
1691     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1692     todo_wine CHECK_CALLED(Reduce);
1693     todo_wine CHECK_CALLED(Enum);
1694     getMonikerRef(hl, &hls_ref_Moniker, NULL);
1695     IHlink_Release(hl);
1696
1697     hres = HlinkCreateFromMoniker(NULL, NULL, NULL, &HlinkSite, 17,
1698             NULL, &IID_IHlink, (LPVOID*)&hl);
1699     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1700     getMonikerRef(hl, NULL, NULL);
1701     IHlink_Release(hl);
1702 }
1703
1704 static void test_HlinkClone(void)
1705 {
1706     HRESULT hres;
1707     IHlink *hl, *cloned = NULL;
1708     IMoniker *dummy, *fnd_mk;
1709     IHlinkSite *fnd_site;
1710     WCHAR *fnd_name;
1711     DWORD fnd_data;
1712     const WCHAR one[] = {'1',0};
1713     const WCHAR two[] = {'2',0};
1714     const WCHAR name[] = {'a',0};
1715
1716     hres = HlinkClone(NULL, NULL, NULL, 0, NULL);
1717     ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1718
1719     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
1720             &IID_IHlink, (void**)&hl);
1721     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
1722
1723     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, NULL);
1724     ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1725
1726     if(0){ /* crash on Windows XP */
1727         hres = HlinkClone(hl, NULL, NULL, 0, NULL);
1728         ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1729
1730         hres = HlinkClone(hl, NULL, NULL, 0, (void**)&cloned);
1731         ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1732     }
1733
1734     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1735     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1736     ok(cloned != NULL, "Didn't get a clone\n");
1737     getMonikerRef(cloned, NULL, NULL);
1738     IHlink_Release(cloned);
1739
1740     IHlink_Release(hl);
1741
1742     SET_EXPECT(Reduce);
1743     SET_EXPECT(Enum);
1744     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, two, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hl);
1745     todo_wine CHECK_CALLED(Reduce);
1746     todo_wine CHECK_CALLED(Enum);
1747     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1748     getMonikerRef(hl, &hls_ref_Moniker, two);
1749
1750     SET_EXPECT(Save);
1751     SET_EXPECT(GetClassID);
1752     cloned = (IHlink*)0xdeadbeef;
1753     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1754     /* fails because of invalid CLSID given by Moniker_GetClassID */
1755     ok(hres == REGDB_E_CLASSNOTREG, "Wrong error code: %08x\n", hres);
1756     ok(cloned == NULL, "Shouldn't have gotten a clone\n");
1757     CHECK_CALLED(Save);
1758     CHECK_CALLED(GetClassID);
1759
1760     IHlink_Release(hl);
1761
1762     hres = CreateItemMoniker(one, one, &dummy);
1763     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1764
1765     hres = HlinkCreateFromMoniker(dummy, two, name, &HlinkSite, 17, NULL, &IID_IHlink, (void**)&hl);
1766     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1767     getMonikerRef(hl, dummy, two);
1768
1769     cloned = NULL;
1770     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1771     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1772     ok(cloned != NULL, "Should have gotten a clone\n");
1773
1774     fnd_mk = getMonikerRef(cloned, (IMoniker*)0xFFFFFFFF, two);
1775     ok(fnd_mk != NULL, "Expected non-null Moniker\n");
1776     ok(fnd_mk != dummy, "Expected a new Moniker to be created\n");
1777
1778     fnd_name = NULL;
1779     hres = IHlink_GetFriendlyName(cloned, HLFNAMEF_DEFAULT, &fnd_name);
1780     ok(hres == S_OK, "GetFriendlyName failed: %08x\n", hres);
1781     ok(fnd_name != NULL, "Expected friendly name to be non-NULL\n");
1782     ok(lstrcmpW(fnd_name, name) == 0, "Expected friendly name to be %s, was %s\n",
1783             wine_dbgstr_w(name), wine_dbgstr_w(fnd_name));
1784     CoTaskMemFree(fnd_name);
1785
1786     fnd_site = (IHlinkSite*)0xdeadbeef;
1787     fnd_data = 4;
1788     hres = IHlink_GetHlinkSite(cloned, &fnd_site, &fnd_data);
1789     ok(hres == S_OK, "GetHlinkSite failed: %08x\n", hres);
1790     ok(fnd_site == NULL, "Expected NULL site\n");
1791     ok(fnd_data == 4, "Expected site data to be 4, was: %d\n", fnd_data);
1792
1793     IHlink_Release(cloned);
1794     IHlink_Release(hl);
1795
1796     hres = HlinkCreateFromMoniker(dummy, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hl);
1797     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1798     getMonikerRef(hl, dummy, NULL);
1799
1800     cloned = NULL;
1801     hres = HlinkClone(hl, &IID_IHlink, &HlinkSite, 17, (void**)&cloned);
1802     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1803     ok(cloned != NULL, "Should have gotten a clone\n");
1804
1805     fnd_mk = getMonikerRef(cloned, (IMoniker*)0xFFFFFFFF, NULL);
1806     ok(fnd_mk != NULL, "Expected non-null Moniker\n");
1807     ok(fnd_mk != dummy, "Expected a new Moniker to be created\n");
1808
1809     fnd_site = (IHlinkSite*)0xdeadbeef;
1810     fnd_data = 4;
1811     hres = IHlink_GetHlinkSite(cloned, &fnd_site, &fnd_data);
1812     ok(hres == S_OK, "GetHlinkSite failed: %08x\n", hres);
1813     ok(fnd_site == &HlinkSite, "Expected found site to be HlinkSite, was: %p\n", fnd_site);
1814     ok(fnd_data == 17, "Expected site data to be 17, was: %d\n", fnd_data);
1815
1816     IHlink_Release(cloned);
1817     IHlink_Release(hl);
1818
1819     IMoniker_Release(dummy);
1820 }
1821
1822 START_TEST(hlink)
1823 {
1824     CoInitialize(NULL);
1825
1826     test_HlinkIsShortcut();
1827     test_reference();
1828     test_persist();
1829     test_special_reference();
1830     test_HlinkCreateExtensionServices();
1831     test_HlinkParseDisplayName();
1832     test_HlinkResolveMonikerForData();
1833     test_HlinkGetSetMonikerReference();
1834     test_HlinkGetSetStringReference();
1835     test_HlinkMoniker();
1836     test_HashLink();
1837     test_HlinkSite();
1838     test_HlinkClone();
1839
1840     CoUninitialize();
1841 }