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