mshtml: Add tests for get_scrollLeft.
[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 static const char *debugstr_w(LPCWSTR str)
61 {
62     static char buf[1024];
63     if(!str)
64         return "(null)";
65     WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
66     return buf;
67 }
68
69 static const char *debugstr_guid(REFIID riid)
70 {
71     static char buf[50];
72
73     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
74             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
75             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
76             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
77
78     return buf;
79 }
80
81 static void test_HlinkIsShortcut(void)
82 {
83     int i;
84     HRESULT hres;
85
86     static const WCHAR file0[] = {'f','i','l','e',0};
87     static const WCHAR file1[] = {'f','i','l','e','.','u','r','l',0};
88     static const WCHAR file2[] = {'f','i','l','e','.','l','n','k',0};
89     static const WCHAR file3[] = {'f','i','l','e','.','u','R','l',0};
90     static const WCHAR file4[] = {'f','i','l','e','u','r','l',0};
91     static const WCHAR file5[] = {'c',':','\\','f','i','l','e','.','u','r','l',0};
92     static const WCHAR file6[] = {'c',':','\\','f','i','l','e','.','l','n','k',0};
93     static const WCHAR file7[] = {'.','u','r','l',0};
94
95     static struct {
96         LPCWSTR file;
97         HRESULT hres;
98     } shortcut_test[] = {
99         {file0, S_FALSE},
100         {file1, S_OK},
101         {file2, S_FALSE},
102         {file3, S_OK},
103         {file4, S_FALSE},
104         {file5, S_OK},
105         {file6, S_FALSE},
106         {file7, S_OK},
107         {NULL,  E_INVALIDARG}
108     };
109
110     for(i=0; i<sizeof(shortcut_test)/sizeof(shortcut_test[0]); i++) {
111         hres = HlinkIsShortcut(shortcut_test[i].file);
112         ok(hres == shortcut_test[i].hres, "[%d] HlinkIsShortcut returned %08x, expected %08x\n",
113            i, hres, shortcut_test[i].hres);
114     }
115 }
116
117 static void test_reference(void)
118 {
119     HRESULT r;
120     IHlink *lnk = NULL;
121     IMoniker *mk = NULL;
122     const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
123     const WCHAR url2[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/',0 };
124     LPWSTR str = NULL;
125
126     r = HlinkCreateFromString(url, NULL, NULL, NULL,
127                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
128     ok(r == S_OK, "failed to create link\n");
129     if (FAILED(r))
130         return;
131
132     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
133     ok(r == S_OK, "failed\n");
134
135     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, &mk, &str);
136     ok(r == S_OK, "failed\n");
137     ok(mk != NULL, "no moniker\n");
138     ok(str == NULL, "string should be null\n");
139
140     r = IMoniker_Release(mk);
141     ok( r == 1, "moniker refcount wrong\n");
142
143     r = IHlink_GetStringReference(lnk, -1, &str, NULL);
144     ok(r == S_OK, "failed\n");
145     CoTaskMemFree(str);
146
147     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, &str, NULL);
148     ok(r == S_OK, "failed\n");
149     todo_wine {
150     ok(!lstrcmpW(str, url2), "url wrong\n");
151     }
152     CoTaskMemFree(str);
153
154     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
155     ok(r == S_OK, "failed\n");
156
157     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, &str);
158     ok(r == S_OK, "failed\n");
159     ok(str == NULL, "string should be null\n");
160
161     IHlink_Release(lnk);
162 }
163
164 /* url only */
165 static const unsigned char expected_hlink_data[] =
166 {
167     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
168     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
169     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
170     0x26,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
171     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
172     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
173     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
174     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
175     0x00,0x00,
176 };
177
178 /* url only (IE7) */
179 static const unsigned char expected_hlink_data_ie7[] =
180 {
181     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
182     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
183     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
184     0x3e,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
185     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
186     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
187     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
188     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
189     0x00,0x00,0x79,0x58,0x81,0xf4,0x3b,0x1d,
190     0x7f,0x48,0xaf,0x2c,0x82,0x5d,0xc4,0x85,
191     0x27,0x63,0x00,0x00,0x00,0x00,0xa5,0xab,
192     0x00,0x00,
193 };
194
195 /* url + friendly name */
196 static const unsigned char expected_hlink_data2[] =
197 {
198     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
199     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
200     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
201     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
202     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
203     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
204     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
205     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
206     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
207     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
208     0x67,0x00,0x2f,0x00,0x00,0x00,
209 };
210
211 /* url + friendly name (IE7) */
212 static const unsigned char expected_hlink_data2_ie7[] =
213 {
214     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
215     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
216     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
217     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
218     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
219     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
220     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
221     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
222     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
223     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
224     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
225     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
226     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
227     0x00,0x00,0xa5,0xab,0x00,0x00,
228 };
229
230 /* url + friendly name + location */
231 static const unsigned char expected_hlink_data3[] =
232 {
233     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
234     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
235     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
236     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
237     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
238     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
239     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
240     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
241     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
242     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
243     0x67,0x00,0x2f,0x00,0x00,0x00,0x07,0x00,
244     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
245     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
246 };
247
248 /* url + friendly name + location (IE7) */
249 static const unsigned char expected_hlink_data3_ie7[] =
250 {
251     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
252     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
253     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
254     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
255     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
256     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
257     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
258     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
259     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
260     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
261     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
262     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
263     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
264     0x00,0x00,0xa5,0xab,0x00,0x00,0x07,0x00,
265     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
266     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
267 };
268
269 /* relative url */
270 static const unsigned char expected_hlink_data4[] =
271 {
272     0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
273     0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
274     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
275     0x00,0x00,0x0b,0x00,0x00,0x00,0x69,0x6e,
276     0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,
277     0x00,0xff,0xff,0xad,0xde,0x00,0x00,0x00,
278     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
279     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
280     0x00,0x00,0x00,0x00,0x00,
281 };
282
283 /* url + target frame name */
284 static const unsigned char expected_hlink_data5[] =
285 {
286     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
287     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
288     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
289     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
290     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
291     0xa9,0x0b,0x26,0x00,0x00,0x00,0x68,0x00,
292     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
293     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
294     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
295     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
296     0x2f,0x00,0x00,0x00,
297 };
298
299 /* url + target frame name (IE7) */
300 static const unsigned char expected_hlink_data5_ie7[] =
301 {
302     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
303     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
304     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
305     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
306     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
307     0xa9,0x0b,0x3e,0x00,0x00,0x00,0x68,0x00,
308     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
309     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
310     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
311     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
312     0x2f,0x00,0x00,0x00,0x79,0x58,0x81,0xf4,
313     0x3b,0x1d,0x7f,0x48,0xaf,0x2c,0x82,0x5d,
314     0xc4,0x85,0x27,0x63,0x00,0x00,0x00,0x00,
315     0xa5,0xab,0x00,0x00,
316 };
317
318 /* filename */
319 static const unsigned char expected_hlink_data6[] =
320 {
321      0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
322      0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
323      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
324      0x00,0x00,0x04,0x00,0x00,0x00,0x63,0x3a,
325      0x5c,0x00,0xff,0xff,0xad,0xde,0x00,0x00,
326      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
327      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
328      0x00,0x00,0x0c,0x00,0x00,0x00,0x06,0x00,
329      0x00,0x00,0x03,0x00,0x63,0x00,0x3a,0x00,
330      0x5c,0x00,
331 };
332
333 static void test_persist_save_data(const char *testname, IHlink *lnk,
334                                    const unsigned char *expected_data,
335                                    unsigned int expected_data_size,
336                                    const unsigned char *expected_data_alt,
337                                    unsigned int expected_data_alt_size)
338 {
339     HRESULT hr;
340     IStream *stream;
341     IPersistStream *ps;
342     HGLOBAL hglobal;
343     DWORD data_size;
344     const unsigned char *data;
345     DWORD i;
346     BOOL same;
347
348     hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
349     ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
350
351     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
352     ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
353
354     hr = IPersistStream_Save(ps, stream, TRUE);
355     ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
356
357     hr = GetHGlobalFromStream(stream, &hglobal);
358     ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
359
360     data_size = GlobalSize(hglobal);
361
362     data = GlobalLock(hglobal);
363
364     /* first check we have the right amount of data */
365     ok((data_size == expected_data_size) || (data_size == expected_data_alt_size),
366        "%s: Size of saved data differs (expected %d or %d, actual %d)\n",
367        testname, expected_data_size, expected_data_alt_size, data_size);
368
369     same = TRUE;
370     /* then do a byte-by-byte comparison */
371     for (i = 0; i < min(data_size, expected_data_size); i++)
372     {
373         if ((expected_data[i] != data[i]) &&
374             (((expected_data != expected_hlink_data2) &&
375               (expected_data != expected_hlink_data3)) ||
376              ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
377         {
378             same = FALSE;
379             break;
380         }
381     }
382
383     if (!same && (expected_data_alt != expected_data))
384     {
385         /* then try the alternate data */
386         same = TRUE;
387         for (i = 0; i < min(data_size, expected_data_alt_size); i++)
388         {
389             if ((expected_data_alt[i] != data[i]) &&
390                 (((expected_data_alt != expected_hlink_data2) &&
391                   (expected_data_alt != expected_hlink_data3)) ||
392                  ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
393             {
394                 same = FALSE;
395                 break;
396             }
397         }
398     }
399
400     ok(same, "%s: Saved data differs\n", testname);
401     if (!same)
402     {
403         for (i = 0; i < data_size; i++)
404         {
405             if (i % 8 == 0) printf("    ");
406             printf("0x%02x,", data[i]);
407             if (i % 8 == 7) printf("\n");
408         }
409         printf("\n");
410     }
411
412     GlobalUnlock(hglobal);
413
414     IStream_Release(stream);
415     IPersistStream_Release(ps);
416 }
417
418 static void test_persist(void)
419 {
420     static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
421     static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
422     static const WCHAR filename[] = { 'c',':','\\',0 };
423     static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
424     static const WCHAR location[] = { '_','b','l','a','n','k',0 };
425     static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
426     HRESULT hr;
427     IHlink *lnk;
428
429     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
430                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
431     ok(hr == S_OK, "IHlinkCreateFromString failed with error 0x%08x\n", hr);
432     if (!lnk) {
433         skip("Can't create lnk, skipping test_persist.  Was wineprefixcreate run properly?\n");
434         return;
435     }
436     test_persist_save_data("url only", lnk,
437         expected_hlink_data, sizeof(expected_hlink_data),
438         expected_hlink_data_ie7, sizeof(expected_hlink_data_ie7));
439     IHlink_Release(lnk);
440
441     hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
442                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
443     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
444     test_persist_save_data("url + friendly name", lnk,
445         expected_hlink_data2, sizeof(expected_hlink_data2),
446         expected_hlink_data2_ie7, sizeof(expected_hlink_data2_ie7));
447     IHlink_Release(lnk);
448
449     hr = HlinkCreateFromString(url, location, friendly_name, NULL,
450                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
451     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
452     test_persist_save_data("url + friendly_name + location", lnk,
453         expected_hlink_data3, sizeof(expected_hlink_data3),
454         expected_hlink_data3_ie7, sizeof(expected_hlink_data3_ie7));
455     IHlink_Release(lnk);
456
457     hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
458                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
459     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
460     test_persist_save_data("relative url", lnk,
461         expected_hlink_data4, sizeof(expected_hlink_data4),
462         expected_hlink_data4, sizeof(expected_hlink_data4));
463     IHlink_Release(lnk);
464
465     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
466                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
467     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
468     hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
469     ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
470     test_persist_save_data("url + target frame name", lnk,
471         expected_hlink_data5, sizeof(expected_hlink_data5),
472         expected_hlink_data5_ie7, sizeof(expected_hlink_data5_ie7));
473     IHlink_Release(lnk);
474
475     hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
476                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
477     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
478     test_persist_save_data("filename", lnk,
479         expected_hlink_data6, sizeof(expected_hlink_data6),
480         expected_hlink_data6, sizeof(expected_hlink_data6));
481     IHlink_Release(lnk);
482 }
483
484 static void test_special_reference(void)
485 {
486     LPWSTR ref;
487     HRESULT hres;
488
489     hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
490     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
491     ok(ref != NULL, "ref == NULL\n");
492     CoTaskMemFree(ref);
493
494     hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
495     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
496     ok(ref != NULL, "ref == NULL\n");
497     CoTaskMemFree(ref);
498
499     ref = (void*)0xdeadbeef;
500     hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
501     ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
502     ok(ref == NULL, "ref=%p\n", ref);
503
504     ref = (void*)0xdeadbeef;
505     hres = HlinkGetSpecialReference(4, &ref);
506     ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
507     ok(ref == NULL, "ref=%p\n", ref);
508 }
509
510 static void test_HlinkCreateExtensionServices(void)
511 {
512     IAuthenticate *authenticate;
513     IHttpNegotiate *http_negotiate;
514     LPWSTR password, username, headers;
515     HWND hwnd;
516     HRESULT hres;
517
518     static const WCHAR usernameW[] = {'u','s','e','r',0};
519     static const WCHAR passwordW[] = {'p','a','s','s',0};
520     static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
521     static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
522
523     hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
524                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
525     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
526     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
527
528     password = username = (void*)0xdeadbeef;
529     hwnd = (void*)0xdeadbeef;
530     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
531     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
532     ok(!hwnd, "hwnd != NULL\n");
533     ok(!username, "username != NULL\n");
534     ok(!password, "password != NULL\n");
535
536     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
537     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
538
539     headers = (void*)0xdeadbeef;
540     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
541                                                0, &headers);
542     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
543     ok(headers == NULL, "headers != NULL\n");
544
545     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
546                                                0, NULL);
547     ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
548
549     headers = (void*)0xdeadbeef;
550     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
551     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
552     ok(headers == NULL, "headers != NULL\n");
553
554     IHttpNegotiate_Release(http_negotiate);
555     IAuthenticate_Release(authenticate);
556
557
558     hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
559                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
560     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
561     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
562
563     password = username = NULL;
564     hwnd = NULL;
565     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
566     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
567     ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
568     ok(!lstrcmpW(username, usernameW), "unexpected username\n");
569     ok(!lstrcmpW(password, passwordW), "unexpected password\n");
570     CoTaskMemFree(username);
571     CoTaskMemFree(password);
572
573     password = username = (void*)0xdeadbeef;
574     hwnd = (void*)0xdeadbeef;
575     hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
576     ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
577     ok(password == (void*)0xdeadbeef, "password = %p\n", password);
578     ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
579
580     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
581     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
582
583     headers = (void*)0xdeadbeef;
584     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
585                                                0, &headers);
586     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
587     ok(!lstrcmpW(headers, headersexW), "unexpected headers \"%s\"\n", debugstr_w(headers));
588     CoTaskMemFree(headers);
589
590     headers = (void*)0xdeadbeef;
591     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
592     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
593     ok(headers == NULL, "unexpected headers \"%s\"\n", debugstr_w(headers));
594
595     IHttpNegotiate_Release(http_negotiate);
596     IAuthenticate_Release(authenticate);
597 }
598
599 static void test_HlinkParseDisplayName(void)
600 {
601     IMoniker *mon = NULL;
602     LPWSTR name;
603     DWORD issys;
604     ULONG eaten = 0;
605     IBindCtx *bctx;
606     HRESULT hres;
607
608     static const WCHAR winehq_urlW[] =
609             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
610              '/','s','i','t','e','/','a','b','o','u','t',0};
611     static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
612     static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':',
613             '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8',
614             '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0};
615
616     CreateBindCtx(0, &bctx);
617
618     hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon);
619     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
620     ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
621     ok(mon != NULL, "mon == NULL\n");
622
623     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
624     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
625     ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", debugstr_w(name));
626     CoTaskMemFree(name);
627
628     hres = IMoniker_IsSystemMoniker(mon, &issys);
629     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
630     ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys);
631
632     IMoniker_Release(mon);
633
634     hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon);
635     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
636     ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
637     ok(mon != NULL, "mon == NULL\n");
638
639     hres = IMoniker_IsSystemMoniker(mon, &issys);
640     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
641     ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys);
642
643     IMoniker_Release(mon);
644
645     hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon);
646      ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
647     ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
648     ok(mon != NULL, "mon == NULL\n");
649
650     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
651     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
652     ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", debugstr_w(name));
653     CoTaskMemFree(name);
654
655     hres = IMoniker_IsSystemMoniker(mon, &issys);
656     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
657     ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys);
658
659     IBindCtx_Release(bctx);
660 }
661
662 static IBindCtx *_bctx;
663
664 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
665 {
666     ok(0, "unexpected call\n");
667     return E_NOINTERFACE;
668 }
669
670 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
671 {
672     return 2;
673 }
674
675 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
676 {
677     return 1;
678 }
679
680 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
681         REFGUID guidService, REFIID riid, void **ppv)
682 {
683     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
684     return E_NOINTERFACE;
685 }
686
687 static IServiceProviderVtbl ServiceProviderVtbl = {
688     ServiceProvider_QueryInterface,
689     ServiceProvider_AddRef,
690     ServiceProvider_Release,
691     ServiceProvider_QueryService
692 };
693
694 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
695
696 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
697 {
698     *ppv = NULL;
699
700     if(IsEqualGUID(riid, &IID_IServiceProvider)) {
701         *ppv = &ServiceProvider;
702         return S_OK;
703     }
704
705     ok(0, "unexpected interface %s\n", debugstr_guid(riid));
706     return E_NOINTERFACE;
707 }
708
709 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
710 {
711     return 2;
712 }
713
714 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
715 {
716     return 1;
717 }
718
719 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
720         IBinding *pib)
721 {
722     ok(0, "unexpected call\n");
723     return E_NOTIMPL;
724 }
725
726 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
727 {
728     ok(0, "unexpected call\n");
729     return E_NOTIMPL;
730 }
731
732 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
733 {
734     ok(0, "unexpected call\n");
735     return E_NOTIMPL;
736 }
737
738 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
739         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
740 {
741     ok(0, "unexpected call\n");
742     return E_NOTIMPL;
743 }
744
745 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
746 {
747     ok(0, "unexpected call\n");
748     return E_NOTIMPL;
749 }
750
751 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
752 {
753     ok(0, "unexpected call\n");
754     return E_NOTIMPL;
755 }
756
757 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
758         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
759 {
760     ok(0, "unexpected call\n");
761     return E_NOTIMPL;
762 }
763
764 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
765 {
766     ok(0, "unexpected call\n");
767     return E_NOTIMPL;
768 }
769
770 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
771     BindStatusCallback_QueryInterface,
772     BindStatusCallback_AddRef,
773     BindStatusCallback_Release,
774     BindStatusCallback_OnStartBinding,
775     BindStatusCallback_GetPriority,
776     BindStatusCallback_OnLowResource,
777     BindStatusCallback_OnProgress,
778     BindStatusCallback_OnStopBinding,
779     BindStatusCallback_GetBindInfo,
780     BindStatusCallback_OnDataAvailable,
781     BindStatusCallback_OnObjectAvailable
782 };
783
784 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
785
786 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
787 {
788     *ppv = NULL;
789
790     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
791     return E_NOINTERFACE;
792 }
793
794 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
795 {
796     return 2;
797 }
798
799 static ULONG WINAPI Moniker_Release(IMoniker *iface)
800 {
801     return 1;
802 }
803
804 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
805 {
806     ok(0, "unexpected call\n");
807     return E_NOTIMPL;
808 }
809
810 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
811 {
812     ok(0, "unexpected call\n");
813     return E_NOTIMPL;
814 }
815
816 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
817 {
818     ok(0, "unexpected call\n");
819     return E_NOTIMPL;
820 }
821
822 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
823 {
824     ok(0, "unexpected call\n");
825     return E_NOTIMPL;
826 }
827
828 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
829 {
830     ok(0, "unexpected call\n");
831     return E_NOTIMPL;
832 }
833
834 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft,
835         REFIID riidResult, void **ppvResult)
836 {
837     ok(0, "unexpected call\n");
838     return E_NOTIMPL;
839 }
840
841 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
842         REFIID riid, void **ppv)
843 {
844     IUnknown *unk;
845     HRESULT hres;
846
847     static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
848
849     CHECK_EXPECT(BindToStorage);
850
851     ok(pbc == _bctx, "pbc != _bctx\n");
852     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
853     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
854     ok(ppv != NULL, "ppv == NULL\n");
855     ok(*ppv == NULL, "*ppv=%p\n", *ppv);
856
857     hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
858     ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
859     ok(unk != NULL, "unk == NULL\n");
860
861     IUnknown_Release(unk);
862
863     return S_OK;
864 }
865
866 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
867         IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
868 {
869     ok(0, "unexpected call\n");
870     return E_NOTIMPL;
871 }
872
873 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
874         BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
875 {
876     ok(0, "unexpected call\n");
877     return E_NOTIMPL;
878 }
879
880 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
881 {
882     ok(0, "unexpected call\n");
883     return E_NOTIMPL;
884 }
885
886 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
887 {
888     ok(0, "unexpected call\n");
889     return E_NOTIMPL;
890 }
891
892 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
893 {
894     ok(0, "unexpected call\n");
895     return E_NOTIMPL;
896 }
897
898 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
899         IMoniker *pmkNewlyRunning)
900 {
901     ok(0, "unexpected call\n");
902     return E_NOTIMPL;
903 }
904
905 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
906         IMoniker *pmkToLeft, FILETIME *pFileTime)
907 {
908     ok(0, "unexpected call\n");
909     return E_NOTIMPL;
910 }
911
912 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
913 {
914     ok(0, "unexpected call\n");
915     return E_NOTIMPL;
916 }
917
918 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
919         IMoniker **ppmkPrefix)
920 {
921     ok(0, "unexpected call\n");
922     return E_NOTIMPL;
923 }
924
925 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
926         IMoniker **pmkRelPath)
927 {
928     ok(0, "unexpected call\n");
929     return E_NOTIMPL;
930 }
931
932 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
933         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
934 {
935     static const WCHAR winehq_urlW[] =
936             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
937              '/','s','i','t','e','/','a','b','o','u','t',0};
938
939     CHECK_EXPECT(GetDisplayName);
940
941     ok(pbc != NULL, "pbc == NULL\n");
942     ok(pbc != _bctx, "pbc == _bctx\n");
943     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
944
945     *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
946     memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
947     return S_OK;
948 }
949
950 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
951         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
952 {
953     ok(0, "unexpected call\n");
954     return E_NOTIMPL;
955 }
956
957 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
958 {
959     CHECK_EXPECT2(IsSystemMoniker);
960
961     *pdwMksys = MKSYS_URLMONIKER;
962     return S_OK;
963 }
964
965 static IMonikerVtbl MonikerVtbl = {
966     Moniker_QueryInterface,
967     Moniker_AddRef,
968     Moniker_Release,
969     Moniker_GetClassID,
970     Moniker_IsDirty,
971     Moniker_Load,
972     Moniker_Save,
973     Moniker_GetSizeMax,
974     Moniker_BindToObject,
975     Moniker_BindToStorage,
976     Moniker_Reduce,
977     Moniker_ComposeWith,
978     Moniker_Enum,
979     Moniker_IsEqual,
980     Moniker_Hash,
981     Moniker_IsRunning,
982     Moniker_GetTimeOfLastChange,
983     Moniker_Inverse,
984     Moniker_CommonPrefixWith,
985     Moniker_RelativePathTo,
986     Moniker_GetDisplayName,
987     Moniker_ParseDisplayName,
988     Moniker_IsSystemMoniker
989 };
990
991 static IMoniker Moniker = { &MonikerVtbl };
992
993 static void test_HlinkResolveMonikerForData(void)
994 {
995     IBindCtx *bctx;
996     HRESULT hres;
997
998     CreateBindCtx(0, &bctx);
999     _bctx = bctx;
1000
1001     SET_EXPECT(IsSystemMoniker);
1002     SET_EXPECT(GetDisplayName);
1003     SET_EXPECT(BindToStorage);
1004
1005     hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
1006     ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
1007
1008     CHECK_CALLED(IsSystemMoniker);
1009     CHECK_CALLED(GetDisplayName);
1010     CHECK_CALLED(BindToStorage);
1011
1012     IBindCtx_Release(bctx);
1013 }
1014
1015 START_TEST(hlink)
1016 {
1017     CoInitialize(NULL);
1018
1019     test_HlinkIsShortcut();
1020     test_reference();
1021     test_persist();
1022     test_special_reference();
1023     test_HlinkCreateExtensionServices();
1024     test_HlinkParseDisplayName();
1025     test_HlinkResolveMonikerForData();
1026
1027     CoUninitialize();
1028 }