crypt32: Add additional path for Solaris 11 Express.
[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
359     hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
360     ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
361
362     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
363     ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
364
365     hr = IPersistStream_Save(ps, stream, TRUE);
366     ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
367
368     hr = GetHGlobalFromStream(stream, &hglobal);
369     ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
370
371     data_size = GlobalSize(hglobal);
372
373     data = GlobalLock(hglobal);
374
375     /* first check we have the right amount of data */
376     ok((data_size == expected_data_size) ||
377        (data_size == expected_data_alt_size),
378        "%s: Size of saved data differs (expected %d or %d, actual %d)\n",
379        testname, expected_data_size, expected_data_alt_size, data_size);
380
381     same = TRUE;
382     /* then do a byte-by-byte comparison */
383     for (i = 0; i < min(data_size, expected_data_size); i++)
384     {
385         if ((expected_data[i] != data[i]) &&
386             (((expected_data != expected_hlink_data2) &&
387               (expected_data != expected_hlink_data3)) ||
388              ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
389         {
390             same = FALSE;
391             break;
392         }
393     }
394
395     if (!same && (expected_data_alt != expected_data))
396     {
397         /* then try the alternate data */
398         same = TRUE;
399         for (i = 0; i < min(data_size, expected_data_alt_size); i++)
400         {
401             if ((expected_data_alt[i] != data[i]) &&
402                 (((expected_data_alt != expected_hlink_data2) &&
403                   (expected_data_alt != expected_hlink_data3)) ||
404                  ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
405             {
406                 same = FALSE;
407                 break;
408             }
409         }
410     }
411
412     ok(same, "%s: Saved data differs\n", testname);
413     if (!same)
414     {
415         for (i = 0; i < data_size; i++)
416         {
417             if (i % 8 == 0) printf("    ");
418             printf("0x%02x,", data[i]);
419             if (i % 8 == 7) printf("\n");
420         }
421         printf("\n");
422     }
423
424     GlobalUnlock(hglobal);
425
426     IStream_Release(stream);
427     IPersistStream_Release(ps);
428 }
429
430 static void test_persist(void)
431 {
432     static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
433     static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
434     static const WCHAR filename[] = { 'c',':','\\',0 };
435     static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
436     static const WCHAR location[] = { '_','b','l','a','n','k',0 };
437     static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
438     HRESULT hr;
439     IHlink *lnk;
440
441     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
442                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
443     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
444     if (!lnk) {
445         skip("Can't create lnk, skipping test_persist.\n");
446         return;
447     }
448     test_persist_save_data("url only", lnk,
449         expected_hlink_data, sizeof(expected_hlink_data),
450         expected_hlink_data_ie7, sizeof(expected_hlink_data_ie7));
451     IHlink_Release(lnk);
452
453     hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
454                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
455     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
456     test_persist_save_data("url + friendly name", lnk,
457         expected_hlink_data2, sizeof(expected_hlink_data2),
458         expected_hlink_data2_ie7, sizeof(expected_hlink_data2_ie7));
459     IHlink_Release(lnk);
460
461     hr = HlinkCreateFromString(url, location, friendly_name, NULL,
462                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
463     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
464     test_persist_save_data("url + friendly_name + location", lnk,
465         expected_hlink_data3, sizeof(expected_hlink_data3),
466         expected_hlink_data3_ie7, sizeof(expected_hlink_data3_ie7));
467     IHlink_Release(lnk);
468
469     hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
470                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
471     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
472     test_persist_save_data("relative url", lnk,
473         expected_hlink_data4, sizeof(expected_hlink_data4),
474         expected_hlink_data4, sizeof(expected_hlink_data4));
475     IHlink_Release(lnk);
476
477     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
478                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
479     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
480     hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
481     ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
482     test_persist_save_data("url + target frame name", lnk,
483         expected_hlink_data5, sizeof(expected_hlink_data5),
484         expected_hlink_data5_ie7, sizeof(expected_hlink_data5_ie7));
485     IHlink_Release(lnk);
486
487     hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
488                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
489     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
490     test_persist_save_data("filename", lnk,
491         expected_hlink_data6, sizeof(expected_hlink_data6),
492         expected_hlink_data6, sizeof(expected_hlink_data6));
493     IHlink_Release(lnk);
494 }
495
496 static void test_special_reference(void)
497 {
498     LPWSTR ref;
499     HRESULT hres;
500
501     hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
502     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
503     ok(ref != NULL, "ref == NULL\n");
504     CoTaskMemFree(ref);
505
506     hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
507     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
508     ok(ref != NULL, "ref == NULL\n");
509     CoTaskMemFree(ref);
510
511     ref = (void*)0xdeadbeef;
512     hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
513     ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
514     ok(ref == NULL, "ref=%p\n", ref);
515
516     ref = (void*)0xdeadbeef;
517     hres = HlinkGetSpecialReference(4, &ref);
518     ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
519     ok(ref == NULL, "ref=%p\n", ref);
520 }
521
522 static void test_HlinkCreateExtensionServices(void)
523 {
524     IAuthenticate *authenticate;
525     IHttpNegotiate *http_negotiate;
526     LPWSTR password, username, headers;
527     HWND hwnd;
528     HRESULT hres;
529
530     static const WCHAR usernameW[] = {'u','s','e','r',0};
531     static const WCHAR passwordW[] = {'p','a','s','s',0};
532     static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
533     static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
534
535     hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
536                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
537     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
538     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
539
540     password = username = (void*)0xdeadbeef;
541     hwnd = (void*)0xdeadbeef;
542     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
543     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
544     ok(!hwnd, "hwnd != NULL\n");
545     ok(!username, "username != NULL\n");
546     ok(!password, "password != NULL\n");
547
548     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
549     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
550
551     headers = (void*)0xdeadbeef;
552     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
553                                                0, &headers);
554     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
555     ok(headers == NULL, "headers != NULL\n");
556
557     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
558                                                0, NULL);
559     ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
560
561     headers = (void*)0xdeadbeef;
562     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
563     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
564     ok(headers == NULL, "headers != NULL\n");
565
566     IHttpNegotiate_Release(http_negotiate);
567     IAuthenticate_Release(authenticate);
568
569
570     hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
571                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
572     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
573     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
574
575     password = username = NULL;
576     hwnd = NULL;
577     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
578     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
579     ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
580     ok(!lstrcmpW(username, usernameW), "unexpected username\n");
581     ok(!lstrcmpW(password, passwordW), "unexpected password\n");
582     CoTaskMemFree(username);
583     CoTaskMemFree(password);
584
585     password = username = (void*)0xdeadbeef;
586     hwnd = (void*)0xdeadbeef;
587     hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
588     ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
589     ok(password == (void*)0xdeadbeef, "password = %p\n", password);
590     ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
591
592     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
593     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
594
595     headers = (void*)0xdeadbeef;
596     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
597                                                0, &headers);
598     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
599     ok(!lstrcmpW(headers, headersexW), "unexpected headers %s\n", wine_dbgstr_w(headers));
600     CoTaskMemFree(headers);
601
602     headers = (void*)0xdeadbeef;
603     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
604     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
605     ok(headers == NULL, "unexpected headers %s\n", wine_dbgstr_w(headers));
606
607     IHttpNegotiate_Release(http_negotiate);
608     IAuthenticate_Release(authenticate);
609 }
610
611 static void test_HlinkParseDisplayName(void)
612 {
613     IMoniker *mon = NULL;
614     LPWSTR name;
615     DWORD issys;
616     ULONG eaten = 0;
617     IBindCtx *bctx;
618     HRESULT hres;
619
620     static const WCHAR winehq_urlW[] =
621             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
622              '/','s','i','t','e','/','a','b','o','u','t',0};
623     static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
624     static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':',
625             '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8',
626             '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0};
627
628     CreateBindCtx(0, &bctx);
629
630     hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon);
631     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
632     ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
633     ok(mon != NULL, "mon == NULL\n");
634
635     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
636     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
637     ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
638     CoTaskMemFree(name);
639
640     hres = IMoniker_IsSystemMoniker(mon, &issys);
641     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
642     ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys);
643
644     IMoniker_Release(mon);
645
646     hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon);
647     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
648     ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
649     ok(mon != NULL, "mon == NULL\n");
650
651     hres = IMoniker_IsSystemMoniker(mon, &issys);
652     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
653     ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys);
654
655     IMoniker_Release(mon);
656
657     hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon);
658      ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
659     ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
660     ok(mon != NULL, "mon == NULL\n");
661
662     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
663     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
664     ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
665     CoTaskMemFree(name);
666
667     hres = IMoniker_IsSystemMoniker(mon, &issys);
668     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
669     ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys);
670
671     IMoniker_Release(mon);
672     IBindCtx_Release(bctx);
673 }
674
675 static IBindCtx *_bctx;
676
677 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
678 {
679     ok(0, "unexpected call\n");
680     return E_NOINTERFACE;
681 }
682
683 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
684 {
685     return 2;
686 }
687
688 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
689 {
690     return 1;
691 }
692
693 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
694         REFGUID guidService, REFIID riid, void **ppv)
695 {
696     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
697     return E_NOINTERFACE;
698 }
699
700 static IServiceProviderVtbl ServiceProviderVtbl = {
701     ServiceProvider_QueryInterface,
702     ServiceProvider_AddRef,
703     ServiceProvider_Release,
704     ServiceProvider_QueryService
705 };
706
707 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
708
709 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
710 {
711     *ppv = NULL;
712
713     if(IsEqualGUID(riid, &IID_IServiceProvider)) {
714         *ppv = &ServiceProvider;
715         return S_OK;
716     }
717
718     ok(0, "unexpected interface %s\n", debugstr_guid(riid));
719     return E_NOINTERFACE;
720 }
721
722 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
723 {
724     return 2;
725 }
726
727 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
728 {
729     return 1;
730 }
731
732 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
733         IBinding *pib)
734 {
735     ok(0, "unexpected call\n");
736     return E_NOTIMPL;
737 }
738
739 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
740 {
741     ok(0, "unexpected call\n");
742     return E_NOTIMPL;
743 }
744
745 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
746 {
747     ok(0, "unexpected call\n");
748     return E_NOTIMPL;
749 }
750
751 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
752         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
753 {
754     ok(0, "unexpected call\n");
755     return E_NOTIMPL;
756 }
757
758 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
759 {
760     ok(0, "unexpected call\n");
761     return E_NOTIMPL;
762 }
763
764 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
765 {
766     ok(0, "unexpected call\n");
767     return E_NOTIMPL;
768 }
769
770 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
771         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
772 {
773     ok(0, "unexpected call\n");
774     return E_NOTIMPL;
775 }
776
777 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
778 {
779     ok(0, "unexpected call\n");
780     return E_NOTIMPL;
781 }
782
783 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
784     BindStatusCallback_QueryInterface,
785     BindStatusCallback_AddRef,
786     BindStatusCallback_Release,
787     BindStatusCallback_OnStartBinding,
788     BindStatusCallback_GetPriority,
789     BindStatusCallback_OnLowResource,
790     BindStatusCallback_OnProgress,
791     BindStatusCallback_OnStopBinding,
792     BindStatusCallback_GetBindInfo,
793     BindStatusCallback_OnDataAvailable,
794     BindStatusCallback_OnObjectAvailable
795 };
796
797 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
798
799 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
800 {
801     *ppv = NULL;
802
803     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
804     return E_NOINTERFACE;
805 }
806
807 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
808 {
809     return 2;
810 }
811
812 static ULONG WINAPI Moniker_Release(IMoniker *iface)
813 {
814     return 1;
815 }
816
817 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
818 {
819     CHECK_EXPECT(GetClassID);
820     *pClassID = IID_IUnknown; /* not a valid CLSID */
821     return S_OK;
822 }
823
824 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
825 {
826     ok(0, "unexpected call\n");
827     return E_NOTIMPL;
828 }
829
830 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
831 {
832     ok(0, "unexpected call\n");
833     return E_NOTIMPL;
834 }
835
836 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
837 {
838     CHECK_EXPECT(Save);
839     return S_OK;
840 }
841
842 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
843 {
844     ok(0, "unexpected call\n");
845     return E_NOTIMPL;
846 }
847
848 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft,
849         REFIID riidResult, void **ppvResult)
850 {
851     ok(0, "unexpected call\n");
852     return E_NOTIMPL;
853 }
854
855 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
856         REFIID riid, void **ppv)
857 {
858     IUnknown *unk;
859     HRESULT hres;
860
861     static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
862
863     CHECK_EXPECT(BindToStorage);
864
865     ok(pbc == _bctx, "pbc != _bctx\n");
866     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
867     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
868     ok(ppv != NULL, "ppv == NULL\n");
869     ok(*ppv == NULL, "*ppv=%p\n", *ppv);
870
871     hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
872     ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
873     ok(unk != NULL, "unk == NULL\n");
874
875     IUnknown_Release(unk);
876
877     return S_OK;
878 }
879
880 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
881         IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
882 {
883     CHECK_EXPECT(Reduce);
884     return E_NOTIMPL;
885 }
886
887 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
888         BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
889 {
890     ok(0, "unexpected call\n");
891     return E_NOTIMPL;
892 }
893
894 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
895 {
896     CHECK_EXPECT(Enum);
897     return E_NOTIMPL;
898 }
899
900 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
901 {
902     ok(0, "unexpected call\n");
903     return E_NOTIMPL;
904 }
905
906 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
907 {
908     ok(0, "unexpected call\n");
909     return E_NOTIMPL;
910 }
911
912 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
913         IMoniker *pmkNewlyRunning)
914 {
915     ok(0, "unexpected call\n");
916     return E_NOTIMPL;
917 }
918
919 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
920         IMoniker *pmkToLeft, FILETIME *pFileTime)
921 {
922     ok(0, "unexpected call\n");
923     return E_NOTIMPL;
924 }
925
926 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
927 {
928     ok(0, "unexpected call\n");
929     return E_NOTIMPL;
930 }
931
932 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
933         IMoniker **ppmkPrefix)
934 {
935     ok(0, "unexpected call\n");
936     return E_NOTIMPL;
937 }
938
939 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
940         IMoniker **pmkRelPath)
941 {
942     ok(0, "unexpected call\n");
943     return E_NOTIMPL;
944 }
945
946 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
947         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
948 {
949     static const WCHAR winehq_urlW[] =
950             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
951              '/','s','i','t','e','/','a','b','o','u','t',0};
952
953     CHECK_EXPECT(GetDisplayName);
954
955     ok(pbc != NULL, "pbc == NULL\n");
956     ok(pbc != _bctx, "pbc == _bctx\n");
957     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
958
959     *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
960     memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
961     return S_OK;
962 }
963
964 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
965         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
966 {
967     ok(0, "unexpected call\n");
968     return E_NOTIMPL;
969 }
970
971 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
972 {
973     CHECK_EXPECT2(IsSystemMoniker);
974
975     *pdwMksys = MKSYS_URLMONIKER;
976     return S_OK;
977 }
978
979 static IMonikerVtbl MonikerVtbl = {
980     Moniker_QueryInterface,
981     Moniker_AddRef,
982     Moniker_Release,
983     Moniker_GetClassID,
984     Moniker_IsDirty,
985     Moniker_Load,
986     Moniker_Save,
987     Moniker_GetSizeMax,
988     Moniker_BindToObject,
989     Moniker_BindToStorage,
990     Moniker_Reduce,
991     Moniker_ComposeWith,
992     Moniker_Enum,
993     Moniker_IsEqual,
994     Moniker_Hash,
995     Moniker_IsRunning,
996     Moniker_GetTimeOfLastChange,
997     Moniker_Inverse,
998     Moniker_CommonPrefixWith,
999     Moniker_RelativePathTo,
1000     Moniker_GetDisplayName,
1001     Moniker_ParseDisplayName,
1002     Moniker_IsSystemMoniker
1003 };
1004
1005 static IMoniker Moniker = { &MonikerVtbl };
1006
1007 static void test_HlinkResolveMonikerForData(void)
1008 {
1009     IBindCtx *bctx;
1010     HRESULT hres;
1011
1012     CreateBindCtx(0, &bctx);
1013     _bctx = bctx;
1014
1015     SET_EXPECT(IsSystemMoniker);
1016     SET_EXPECT(GetDisplayName);
1017     SET_EXPECT(BindToStorage);
1018
1019     hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
1020     ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
1021
1022     CHECK_CALLED(IsSystemMoniker);
1023     CHECK_CALLED(GetDisplayName);
1024     CHECK_CALLED(BindToStorage);
1025
1026     IBindCtx_Release(bctx);
1027 }
1028
1029 static void test_HlinkGetSetMonikerReference(void)
1030 {
1031     IMoniker *found_trgt, *dummy, *dummy2;
1032     IHlink *hlink;
1033     HRESULT hres;
1034     const WCHAR one[] = {'1',0};
1035     const WCHAR two[] = {'2',0};
1036     const WCHAR name[] = {'a',0};
1037     WCHAR *found_loc;
1038
1039     /* create two dummy monikers to use as targets */
1040     hres = CreateItemMoniker(one, one, &dummy);
1041     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1042
1043     hres = CreateItemMoniker(two, two, &dummy2);
1044     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1045
1046     /* create a new hlink: target => dummy, location => one */
1047     hres = HlinkCreateFromMoniker(dummy, one, name, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1048     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1049
1050     /* validate the target and location */
1051     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1052     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1053     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1054     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1055     IMoniker_Release(found_trgt);
1056     CoTaskMemFree(found_loc);
1057
1058     /* set location => two */
1059     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_LOCATION, dummy2, two);
1060     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1061
1062     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1063     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1064     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1065     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1066     IMoniker_Release(found_trgt);
1067     CoTaskMemFree(found_loc);
1068
1069     /* set target => dummy2 */
1070     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, dummy2, one);
1071     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1072
1073     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1074     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1075     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1076     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1077     IMoniker_Release(found_trgt);
1078     CoTaskMemFree(found_loc);
1079
1080     /* set target => dummy, location => one */
1081     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, dummy, one);
1082     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1083
1084     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1085     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1086     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1087     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1088     IMoniker_Release(found_trgt);
1089     CoTaskMemFree(found_loc);
1090
1091     /* no HLINKSETF flags */
1092     hres = IHlink_SetMonikerReference(hlink, 0, dummy2, two);
1093     ok(hres == E_INVALIDARG, "IHlink_SetMonikerReference should've failed with E_INVALIDARG (0x%08x), failed with 0x%08x\n", E_INVALIDARG, hres);
1094
1095     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1096     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1097     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1098     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1099     IMoniker_Release(found_trgt);
1100     CoTaskMemFree(found_loc);
1101
1102     /* invalid HLINKSETF flags */
1103     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1104     if (0) 
1105         IHlink_SetMonikerReference(hlink, 12, dummy2, two);
1106
1107     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1108     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
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(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1120     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1121     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1122     IMoniker_Release(found_trgt);
1123     CoTaskMemFree(found_loc);
1124
1125     /* NULL args */
1126     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, NULL, NULL);
1127     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1128
1129     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1130     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1131     ok(found_trgt == NULL, "Found target should've been %p, was: %p\n", NULL, found_trgt);
1132     ok(found_loc == NULL, "Found location should've been %s, was: %s\n", wine_dbgstr_w(NULL), wine_dbgstr_w(found_loc));
1133     if(found_trgt)
1134         IMoniker_Release(found_trgt);
1135
1136     IHlink_Release(hlink);
1137     IMoniker_Release(dummy2);
1138     IMoniker_Release(dummy);
1139 }
1140
1141 static void test_HlinkGetSetStringReference(void)
1142 {
1143     IHlink *link;
1144     static const WCHAR one[] = {'1',0};
1145     static const WCHAR two[] = {'2',0};
1146     static const WCHAR three[] = {'3',0};
1147     static const WCHAR empty[] = {0};
1148     WCHAR *fnd_tgt, *fnd_loc;
1149     HRESULT hres;
1150
1151     /* create a new hlink: target => NULL, location => one */
1152     hres = HlinkCreateFromMoniker(NULL, one, empty, NULL, 0, NULL, &IID_IHlink, (void**)&link);
1153     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1154
1155     /* test setting/getting location */
1156     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1157     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1158     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1159     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1160     CoTaskMemFree(fnd_tgt);
1161     CoTaskMemFree(fnd_loc);
1162
1163     hres = IHlink_SetStringReference(link, HLINKSETF_LOCATION, one, two);
1164     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1165
1166     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1167     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1168     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1169     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1170     CoTaskMemFree(fnd_tgt);
1171     CoTaskMemFree(fnd_loc);
1172
1173     hres = IHlink_SetStringReference(link, -HLINKSETF_LOCATION, two, one);
1174     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1175
1176     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1177     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1178     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1179     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1180     CoTaskMemFree(fnd_tgt);
1181     CoTaskMemFree(fnd_loc);
1182
1183     /* test setting/getting target */
1184     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET, two, three);
1185     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1186
1187     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1188     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1189     ok(!lstrcmpW(fnd_tgt, two), "Found target should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_tgt));
1190     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1191     CoTaskMemFree(fnd_tgt);
1192     CoTaskMemFree(fnd_loc);
1193
1194     hres = IHlink_SetStringReference(link, -HLINKSETF_TARGET, three, two);
1195     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1196
1197     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1198     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1199     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1200     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1201     CoTaskMemFree(fnd_tgt);
1202     CoTaskMemFree(fnd_loc);
1203
1204     /* test setting/getting both */
1205     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET | HLINKSETF_LOCATION, one, two);
1206     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1207
1208     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1209     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1210     ok(!lstrcmpW(fnd_tgt, one), "Found target should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_tgt));
1211     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1212     CoTaskMemFree(fnd_tgt);
1213     CoTaskMemFree(fnd_loc);
1214
1215     hres = IHlink_SetStringReference(link, -(HLINKSETF_TARGET | HLINKSETF_LOCATION), three, one);
1216     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1217
1218     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1219     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1220     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1221     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1222     CoTaskMemFree(fnd_tgt);
1223     CoTaskMemFree(fnd_loc);
1224
1225     /* test invalid flags/params */
1226     hres = IHlink_GetStringReference(link, 4, &fnd_tgt, &fnd_loc);
1227     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1228            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1229     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1230     ok(fnd_loc == NULL, "Found location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1231     CoTaskMemFree(fnd_tgt);
1232     CoTaskMemFree(fnd_loc);
1233
1234     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, NULL);
1235     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1236            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1237     CoTaskMemFree(fnd_tgt);
1238
1239     hres = IHlink_GetStringReference(link, -1, NULL, NULL);
1240     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1241
1242     hres = IHlink_GetStringReference(link, -1, NULL, &fnd_loc);
1243     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1244     CoTaskMemFree(fnd_loc);
1245
1246     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, &fnd_loc);
1247     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1248            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1249     CoTaskMemFree(fnd_tgt);
1250     CoTaskMemFree(fnd_loc);
1251
1252     hres = IHlink_GetStringReference(link, -2, &fnd_tgt, &fnd_loc);
1253     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1254            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1255     CoTaskMemFree(fnd_tgt);
1256     CoTaskMemFree(fnd_loc);
1257
1258     if (0)
1259     {
1260         /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1261         IHlink_SetStringReference(link, 4, NULL, NULL);
1262         IHlink_SetStringReference(link, -4, NULL, NULL);
1263     }
1264
1265     IHlink_Release(link);
1266 }
1267
1268 #define setStringRef(h,f,t,l) r_setStringRef(__LINE__,h,f,t,l)
1269 static void r_setStringRef(unsigned line, IHlink *hlink, DWORD flags, const WCHAR *tgt, const WCHAR *loc)
1270 {
1271     HRESULT hres;
1272     hres = IHlink_SetStringReference(hlink, flags, tgt, loc);
1273     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1274 }
1275
1276 #define getStringRef(h,t,l) r_getStringRef(__LINE__,h,t,l)
1277 static void r_getStringRef(unsigned line, IHlink *hlink, const WCHAR *exp_tgt, const WCHAR *exp_loc)
1278 {
1279     HRESULT hres;
1280     WCHAR *fnd_tgt, *fnd_loc;
1281
1282     hres = IHlink_GetStringReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1283     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1284
1285     if(exp_tgt)
1286         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));
1287     else
1288         ok_(__FILE__,line) (fnd_tgt == NULL, "Found string target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1289
1290     if(exp_loc)
1291         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));
1292     else
1293         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1294
1295     CoTaskMemFree(fnd_tgt);
1296     CoTaskMemFree(fnd_loc);
1297 }
1298
1299 #define setMonikerRef(h,f,t,l) r_setMonikerRef(__LINE__,h,f,t,l)
1300 static void r_setMonikerRef(unsigned line, IHlink *hlink, DWORD flags, IMoniker *tgt, const WCHAR *loc)
1301 {
1302     HRESULT hres;
1303     hres = IHlink_SetMonikerReference(hlink, flags, tgt, loc);
1304     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1305 }
1306
1307 /* passing 0xFFFFFFFF as exp_tgt will return the retrieved target & not test it */
1308 #define getMonikerRef(h,t,l) r_getMonikerRef(__LINE__,h,t,l)
1309 static IMoniker *r_getMonikerRef(unsigned line, IHlink *hlink, IMoniker *exp_tgt, const WCHAR *exp_loc)
1310 {
1311     HRESULT hres;
1312     IMoniker *fnd_tgt;
1313     WCHAR *fnd_loc;
1314
1315     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1316     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1317
1318     if(exp_loc)
1319         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));
1320     else
1321         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1322
1323     CoTaskMemFree(fnd_loc);
1324
1325     if(exp_tgt == (IMoniker*)0xFFFFFFFF)
1326         return fnd_tgt;
1327
1328     ok_(__FILE__,line) (fnd_tgt == exp_tgt, "Found moniker target should have been %p, was: %p\n", exp_tgt, fnd_tgt);
1329
1330     if(fnd_tgt)
1331         IMoniker_Release(fnd_tgt);
1332
1333     return NULL;
1334 }
1335
1336 static void test_HlinkMoniker(void)
1337 {
1338     IHlink *hlink;
1339     IMoniker *aMon, *file_mon;
1340     static const WCHAR emptyW[] = {0};
1341     static const WCHAR wordsW[] = {'w','o','r','d','s',0};
1342     static const WCHAR aW[] = {'a',0};
1343     static const WCHAR bW[] = {'b',0};
1344     HRESULT hres;
1345
1346     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1347     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1348     getStringRef(hlink, NULL, NULL);
1349     getMonikerRef(hlink, NULL, NULL);
1350
1351     /* setting a string target creates a moniker reference */
1352     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, aW, wordsW);
1353     getStringRef(hlink, aW, wordsW);
1354     aMon = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, wordsW);
1355     ok(aMon != NULL, "Moniker from %s target should not be NULL\n", wine_dbgstr_w(aW));
1356     if(aMon)
1357         IMoniker_Release(aMon);
1358
1359     /* setting target & location to the empty string deletes the moniker
1360      * reference */
1361     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, emptyW, emptyW);
1362     getStringRef(hlink, NULL, NULL);
1363     getMonikerRef(hlink, NULL, NULL);
1364
1365     /* setting a moniker target also sets the target string to that moniker's
1366      * display name */
1367     hres = CreateFileMoniker(bW, &file_mon);
1368     ok(hres == S_OK, "CreateFileMoniker failed: 0x%08x\n", hres);
1369
1370     setMonikerRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, file_mon, wordsW);
1371     getStringRef(hlink, bW, wordsW);
1372     getMonikerRef(hlink, file_mon, wordsW);
1373
1374     IMoniker_Release(file_mon);
1375
1376     IHlink_Release(hlink);
1377 }
1378
1379 static void test_HashLink(void)
1380 {
1381     IHlink *hlink;
1382     IMoniker *pmk;
1383     const WCHAR hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r',0};
1384     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};
1385     const WCHAR hash_no_tgtW[] = {'#','a','n','a','n','c','h','o','r',0};
1386     const WCHAR tgt_partW[] = {'a','f','i','l','e',0};
1387     const WCHAR loc_partW[] = {'a','n','a','n','c','h','o','r',0};
1388     const WCHAR two_hash_loc_partW[] = {'a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1389     const WCHAR test_locW[] = {'t','e','s','t','l','o','c',0};
1390     HRESULT hres;
1391
1392     /* simple single hash test */
1393     hres = HlinkCreateFromString(hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1394     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1395     ok(hlink != NULL, "Didn't get an hlink\n");
1396
1397     if(hlink){
1398         getStringRef(hlink, tgt_partW, loc_partW);
1399         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1400         ok(pmk != NULL, "Found moniker should not be NULL\n");
1401         if(pmk)
1402             IMoniker_Release(pmk);
1403
1404         setStringRef(hlink, HLINKSETF_TARGET, hash_targetW, NULL);
1405         getStringRef(hlink, hash_targetW, loc_partW);
1406
1407         IHlink_Release(hlink);
1408     }
1409
1410     /* two hashes in the target */
1411     hres = HlinkCreateFromString(two_hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1412     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1413     ok(hlink != NULL, "Didn't get an hlink\n");
1414
1415     if(hlink){
1416         getStringRef(hlink, tgt_partW, two_hash_loc_partW);
1417         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, two_hash_loc_partW);
1418         ok(pmk != NULL, "Found moniker should not be NULL\n");
1419         if(pmk)
1420             IMoniker_Release(pmk);
1421
1422         IHlink_Release(hlink);
1423     }
1424
1425     /* target with hash plus a location string */
1426     hres = HlinkCreateFromString(hash_targetW, test_locW, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1427     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1428     ok(hlink != NULL, "Didn't get an hlink\n");
1429
1430     if(hlink){
1431         getStringRef(hlink, tgt_partW, test_locW);
1432         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, test_locW);
1433         ok(pmk != NULL, "Found moniker should not be NULL\n");
1434         if(pmk)
1435             IMoniker_Release(pmk);
1436
1437         IHlink_Release(hlink);
1438     }
1439
1440     /* target with hash containing no "target part" */
1441     hres = HlinkCreateFromString(hash_no_tgtW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1442     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1443     ok(hlink != NULL, "Didn't get an hlink\n");
1444
1445     if(hlink){
1446         getStringRef(hlink, NULL, loc_partW);
1447         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1448         ok(pmk == NULL, "Found moniker should be NULL\n");
1449         if(pmk)
1450             IMoniker_Release(pmk);
1451
1452         IHlink_Release(hlink);
1453     }
1454 }
1455
1456 static WCHAR site_monikerW[] = {'S','I','T','E','_','M','O','N','I','K','E','R',0};
1457 static WCHAR ref_monikerW[] = {'R','E','F','_','M','O','N','I','K','E','R',0};
1458
1459 static HRESULT WINAPI hls_test_Moniker_BindToStorage(IMoniker *iface,
1460         IBindCtx *pbc, IMoniker *toLeft, REFIID riid, void **obj)
1461 {
1462     ok(0, "BTS: %p %p %p %p %p\n", iface, pbc, toLeft, riid, obj);
1463     return E_NOTIMPL;
1464 }
1465
1466 static HRESULT WINAPI hls_site_Moniker_ComposeWith(IMoniker *iface,
1467         IMoniker *right, BOOL onlyIfNotGeneric, IMoniker **composite)
1468 {
1469     LPOLESTR rightName;
1470     HRESULT hres;
1471
1472     ok(onlyIfNotGeneric == 0, "Expected onlyIfNotGeneric to be FALSE\n");
1473
1474     CHECK_EXPECT(ComposeWith);
1475
1476     hres = IMoniker_GetDisplayName(right, NULL, NULL, &rightName);
1477     ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres);
1478     ok(!lstrcmpW(rightName, ref_monikerW),
1479             "Expected to get moniker set via SetMonikerReference, instead got: %s\n",
1480             wine_dbgstr_w(rightName));
1481     CoTaskMemFree(rightName);
1482
1483     *composite = NULL;
1484
1485     /* unlikely error code to verify this return result is used */
1486     return E_OUTOFMEMORY;
1487 }
1488
1489 static HRESULT WINAPI hls_site_Moniker_GetDisplayName(IMoniker *iface,
1490         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1491 {
1492     *displayName = CoTaskMemAlloc(sizeof(site_monikerW));
1493     memcpy(*displayName, site_monikerW, sizeof(site_monikerW));
1494     return S_OK;
1495 }
1496
1497 static HRESULT WINAPI hls_ref_Moniker_GetDisplayName(IMoniker *iface,
1498         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1499 {
1500     *displayName = CoTaskMemAlloc(sizeof(ref_monikerW));
1501     memcpy(*displayName, ref_monikerW, sizeof(ref_monikerW));
1502     return S_OK;
1503 }
1504
1505 static HRESULT WINAPI hls_test_Moniker_IsSystemMoniker(IMoniker *iface,
1506         DWORD *mksys)
1507 {
1508     return S_FALSE;
1509 }
1510
1511 static IMonikerVtbl hls_site_MonikerVtbl = {
1512     Moniker_QueryInterface,
1513     Moniker_AddRef,
1514     Moniker_Release,
1515     Moniker_GetClassID,
1516     Moniker_IsDirty,
1517     Moniker_Load,
1518     Moniker_Save,
1519     Moniker_GetSizeMax,
1520     Moniker_BindToObject,
1521     hls_test_Moniker_BindToStorage,
1522     Moniker_Reduce,
1523     hls_site_Moniker_ComposeWith,
1524     Moniker_Enum,
1525     Moniker_IsEqual,
1526     Moniker_Hash,
1527     Moniker_IsRunning,
1528     Moniker_GetTimeOfLastChange,
1529     Moniker_Inverse,
1530     Moniker_CommonPrefixWith,
1531     Moniker_RelativePathTo,
1532     hls_site_Moniker_GetDisplayName,
1533     Moniker_ParseDisplayName,
1534     hls_test_Moniker_IsSystemMoniker
1535 };
1536
1537 static IMonikerVtbl hls_ref_MonikerVtbl = {
1538     Moniker_QueryInterface,
1539     Moniker_AddRef,
1540     Moniker_Release,
1541     Moniker_GetClassID,
1542     Moniker_IsDirty,
1543     Moniker_Load,
1544     Moniker_Save,
1545     Moniker_GetSizeMax,
1546     Moniker_BindToObject,
1547     hls_test_Moniker_BindToStorage,
1548     Moniker_Reduce,
1549     Moniker_ComposeWith,
1550     Moniker_Enum,
1551     Moniker_IsEqual,
1552     Moniker_Hash,
1553     Moniker_IsRunning,
1554     Moniker_GetTimeOfLastChange,
1555     Moniker_Inverse,
1556     Moniker_CommonPrefixWith,
1557     Moniker_RelativePathTo,
1558     hls_ref_Moniker_GetDisplayName,
1559     Moniker_ParseDisplayName,
1560     hls_test_Moniker_IsSystemMoniker
1561 };
1562
1563 static IMoniker hls_site_Moniker = { &hls_site_MonikerVtbl };
1564 static IMoniker hls_ref_Moniker = { &hls_ref_MonikerVtbl };
1565
1566 static HRESULT WINAPI hls_QueryInterface(IHlinkSite *iface, REFGUID iid,
1567         void **obj)
1568 {
1569     ok(0, "QI: %p %s %p\n", iface, debugstr_guid(iid), obj);
1570     return E_NOTIMPL;
1571 }
1572
1573 static ULONG WINAPI hls_AddRef(IHlinkSite *iface)
1574 {
1575     return 2;
1576 }
1577
1578 static ULONG WINAPI hls_Release(IHlinkSite *iface)
1579 {
1580     return 1;
1581 }
1582
1583 static HRESULT WINAPI hls_QueryService(IHlinkSite *iface, DWORD siteData,
1584         REFGUID service, REFIID riid, IUnknown **punk)
1585 {
1586     ok(0, "QS: %p %x %s %s %p\n", iface, siteData, debugstr_guid(service),
1587             debugstr_guid(riid), punk);
1588     return E_NOTIMPL;
1589 }
1590
1591 static HRESULT WINAPI hls_GetMoniker(IHlinkSite *iface, DWORD siteData,
1592         DWORD assign, DWORD which, IMoniker **pmk)
1593 {
1594     ok(siteData == 17, "Expected siteData == 17, got: %d\n", siteData);
1595     *pmk = &hls_site_Moniker;
1596     return S_OK;
1597 }
1598
1599 static HRESULT WINAPI hls_ReadyToNavigate(IHlinkSite *iface, DWORD siteData,
1600         DWORD reserved)
1601 {
1602     ok(0, "RTN: %p %x %x\n", iface, siteData, reserved);
1603     return E_NOTIMPL;
1604 }
1605
1606 static HRESULT WINAPI hls_OnNavigationComplete(IHlinkSite *iface,
1607         DWORD siteData, DWORD reserved, HRESULT error, LPCWSTR errorStr)
1608 {
1609     CHECK_EXPECT(OnNavigationComplete);
1610     ok(siteData == 17, "Expected siteData == 17, got: %d\n", siteData);
1611     ok(error == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", error);
1612     return E_NOTIMPL;
1613 }
1614
1615 static IHlinkSiteVtbl HlinkSiteVtbl = {
1616     hls_QueryInterface,
1617     hls_AddRef,
1618     hls_Release,
1619     hls_QueryService,
1620     hls_GetMoniker,
1621     hls_ReadyToNavigate,
1622     hls_OnNavigationComplete
1623 };
1624
1625 static IHlinkSite HlinkSite = { &HlinkSiteVtbl };
1626
1627 static void test_HlinkSite(void)
1628 {
1629     IHlink *hl;
1630     IMoniker *mon_ref;
1631     IBindCtx *pbc;
1632     HRESULT hres;
1633
1634     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
1635             &IID_IHlink, (LPVOID*)&hl);
1636     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
1637     getMonikerRef(hl, NULL, NULL);
1638
1639     hres = IHlink_SetHlinkSite(hl, &HlinkSite, 17);
1640     ok(hres == S_OK, "SetHlinkSite failed: %08x\n", hres);
1641     getMonikerRef(hl, NULL, NULL);
1642     getStringRef(hl, NULL, NULL);
1643
1644     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1645     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1646     ok(mon_ref == NULL, "Didn't get expected moniker, instead: %p\n", mon_ref);
1647
1648     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1649     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1650     ok(mon_ref == &hls_site_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1651
1652     SET_EXPECT(Reduce);
1653     SET_EXPECT(Enum);
1654     hres = IHlink_SetMonikerReference(hl, HLINKSETF_TARGET, &hls_ref_Moniker, NULL);
1655     ok(hres == S_OK, "SetMonikerReference failed: %08x\n", hres);
1656     todo_wine CHECK_CALLED(Reduce);
1657     todo_wine CHECK_CALLED(Enum);
1658
1659     getMonikerRef(hl, &hls_ref_Moniker, NULL);
1660
1661     SET_EXPECT(Enum);
1662     getStringRef(hl, ref_monikerW, NULL);
1663     todo_wine CHECK_CALLED(Enum);
1664
1665     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1666     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1667     ok(mon_ref == &hls_ref_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1668     IMoniker_Release(mon_ref);
1669
1670     SET_EXPECT(ComposeWith);
1671     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1672     ok(hres == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", hres);
1673     ok(mon_ref == NULL, "Shouldn't have got a Moniker, got: %p\n", mon_ref);
1674     CHECK_CALLED(ComposeWith);
1675
1676     hres = CreateBindCtx(0, &pbc);
1677     ok(hres == S_OK, "CreateBindCtx failed: %08x\n", hres);
1678
1679     SET_EXPECT(ComposeWith);
1680     SET_EXPECT(OnNavigationComplete);
1681     hres = IHlink_Navigate(hl, 0, pbc, NULL, NULL);
1682     ok(hres == E_OUTOFMEMORY, "Navigate should've failed: %08x\n", hres);
1683     CHECK_CALLED(ComposeWith);
1684     CHECK_CALLED(OnNavigationComplete);
1685
1686     IBindCtx_Release(pbc);
1687     IHlink_Release(hl);
1688
1689     SET_EXPECT(Reduce);
1690     SET_EXPECT(Enum);
1691     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, NULL, NULL, &HlinkSite, 17,
1692             NULL, &IID_IHlink, (LPVOID*)&hl);
1693     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1694     todo_wine CHECK_CALLED(Reduce);
1695     todo_wine CHECK_CALLED(Enum);
1696     getMonikerRef(hl, &hls_ref_Moniker, NULL);
1697     IHlink_Release(hl);
1698
1699     hres = HlinkCreateFromMoniker(NULL, NULL, NULL, &HlinkSite, 17,
1700             NULL, &IID_IHlink, (LPVOID*)&hl);
1701     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1702     getMonikerRef(hl, NULL, NULL);
1703     IHlink_Release(hl);
1704 }
1705
1706 static void test_HlinkClone(void)
1707 {
1708     HRESULT hres;
1709     IHlink *hl, *cloned = NULL;
1710     IMoniker *dummy, *fnd_mk;
1711     IHlinkSite *fnd_site;
1712     WCHAR *fnd_name;
1713     DWORD fnd_data;
1714     const WCHAR one[] = {'1',0};
1715     const WCHAR two[] = {'2',0};
1716     const WCHAR name[] = {'a',0};
1717
1718     hres = HlinkClone(NULL, NULL, NULL, 0, NULL);
1719     ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1720
1721     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
1722             &IID_IHlink, (void**)&hl);
1723     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
1724
1725     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, NULL);
1726     ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
1727
1728     if (0)
1729     { 
1730         /* crash on Windows XP */
1731         HlinkClone(hl, NULL, NULL, 0, NULL);
1732
1733         HlinkClone(hl, NULL, NULL, 0, (void**)&cloned);
1734     }
1735
1736     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1737     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1738     ok(cloned != NULL, "Didn't get a clone\n");
1739     getMonikerRef(cloned, NULL, NULL);
1740     IHlink_Release(cloned);
1741
1742     IHlink_Release(hl);
1743
1744     SET_EXPECT(Reduce);
1745     SET_EXPECT(Enum);
1746     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, two, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hl);
1747     todo_wine CHECK_CALLED(Reduce);
1748     todo_wine CHECK_CALLED(Enum);
1749     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1750     getMonikerRef(hl, &hls_ref_Moniker, two);
1751
1752     SET_EXPECT(Save);
1753     SET_EXPECT(GetClassID);
1754     cloned = (IHlink*)0xdeadbeef;
1755     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1756     /* fails because of invalid CLSID given by Moniker_GetClassID */
1757     ok(hres == REGDB_E_CLASSNOTREG, "Wrong error code: %08x\n", hres);
1758     ok(cloned == NULL, "Shouldn't have gotten a clone\n");
1759     CHECK_CALLED(Save);
1760     CHECK_CALLED(GetClassID);
1761
1762     IHlink_Release(hl);
1763
1764     hres = CreateItemMoniker(one, one, &dummy);
1765     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1766
1767     hres = HlinkCreateFromMoniker(dummy, two, name, &HlinkSite, 17, NULL, &IID_IHlink, (void**)&hl);
1768     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1769     getMonikerRef(hl, dummy, two);
1770
1771     cloned = NULL;
1772     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
1773     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1774     ok(cloned != NULL, "Should have gotten a clone\n");
1775
1776     fnd_mk = getMonikerRef(cloned, (IMoniker*)0xFFFFFFFF, two);
1777     ok(fnd_mk != NULL, "Expected non-null Moniker\n");
1778     ok(fnd_mk != dummy, "Expected a new Moniker to be created\n");
1779
1780     fnd_name = NULL;
1781     hres = IHlink_GetFriendlyName(cloned, HLFNAMEF_DEFAULT, &fnd_name);
1782     ok(hres == S_OK, "GetFriendlyName failed: %08x\n", hres);
1783     ok(fnd_name != NULL, "Expected friendly name to be non-NULL\n");
1784     ok(lstrcmpW(fnd_name, name) == 0, "Expected friendly name to be %s, was %s\n",
1785             wine_dbgstr_w(name), wine_dbgstr_w(fnd_name));
1786     CoTaskMemFree(fnd_name);
1787
1788     fnd_site = (IHlinkSite*)0xdeadbeef;
1789     fnd_data = 4;
1790     hres = IHlink_GetHlinkSite(cloned, &fnd_site, &fnd_data);
1791     ok(hres == S_OK, "GetHlinkSite failed: %08x\n", hres);
1792     ok(fnd_site == NULL, "Expected NULL site\n");
1793     ok(fnd_data == 4, "Expected site data to be 4, was: %d\n", fnd_data);
1794
1795     IHlink_Release(cloned);
1796     IHlink_Release(hl);
1797
1798     hres = HlinkCreateFromMoniker(dummy, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hl);
1799     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1800     getMonikerRef(hl, dummy, NULL);
1801
1802     cloned = NULL;
1803     hres = HlinkClone(hl, &IID_IHlink, &HlinkSite, 17, (void**)&cloned);
1804     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
1805     ok(cloned != NULL, "Should have gotten a clone\n");
1806
1807     fnd_mk = getMonikerRef(cloned, (IMoniker*)0xFFFFFFFF, NULL);
1808     ok(fnd_mk != NULL, "Expected non-null Moniker\n");
1809     ok(fnd_mk != dummy, "Expected a new Moniker to be created\n");
1810
1811     fnd_site = (IHlinkSite*)0xdeadbeef;
1812     fnd_data = 4;
1813     hres = IHlink_GetHlinkSite(cloned, &fnd_site, &fnd_data);
1814     ok(hres == S_OK, "GetHlinkSite failed: %08x\n", hres);
1815     ok(fnd_site == &HlinkSite, "Expected found site to be HlinkSite, was: %p\n", fnd_site);
1816     ok(fnd_data == 17, "Expected site data to be 17, was: %d\n", fnd_data);
1817
1818     IHlink_Release(cloned);
1819     IHlink_Release(hl);
1820
1821     IMoniker_Release(dummy);
1822 }
1823
1824 START_TEST(hlink)
1825 {
1826     CoInitialize(NULL);
1827
1828     test_HlinkIsShortcut();
1829     test_reference();
1830     test_persist();
1831     test_special_reference();
1832     test_HlinkCreateExtensionServices();
1833     test_HlinkParseDisplayName();
1834     test_HlinkResolveMonikerForData();
1835     test_HlinkGetSetMonikerReference();
1836     test_HlinkGetSetStringReference();
1837     test_HlinkMoniker();
1838     test_HashLink();
1839     test_HlinkSite();
1840     test_HlinkClone();
1841
1842     CoUninitialize();
1843 }