comctl32/listview: Free ID array when removing all items.
[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     IBindCtx_Release(bctx);
664 }
665
666 static IBindCtx *_bctx;
667
668 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
669 {
670     ok(0, "unexpected call\n");
671     return E_NOINTERFACE;
672 }
673
674 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
675 {
676     return 2;
677 }
678
679 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
680 {
681     return 1;
682 }
683
684 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
685         REFGUID guidService, REFIID riid, void **ppv)
686 {
687     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
688     return E_NOINTERFACE;
689 }
690
691 static IServiceProviderVtbl ServiceProviderVtbl = {
692     ServiceProvider_QueryInterface,
693     ServiceProvider_AddRef,
694     ServiceProvider_Release,
695     ServiceProvider_QueryService
696 };
697
698 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
699
700 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
701 {
702     *ppv = NULL;
703
704     if(IsEqualGUID(riid, &IID_IServiceProvider)) {
705         *ppv = &ServiceProvider;
706         return S_OK;
707     }
708
709     ok(0, "unexpected interface %s\n", debugstr_guid(riid));
710     return E_NOINTERFACE;
711 }
712
713 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
714 {
715     return 2;
716 }
717
718 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
719 {
720     return 1;
721 }
722
723 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
724         IBinding *pib)
725 {
726     ok(0, "unexpected call\n");
727     return E_NOTIMPL;
728 }
729
730 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
731 {
732     ok(0, "unexpected call\n");
733     return E_NOTIMPL;
734 }
735
736 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
737 {
738     ok(0, "unexpected call\n");
739     return E_NOTIMPL;
740 }
741
742 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
743         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
744 {
745     ok(0, "unexpected call\n");
746     return E_NOTIMPL;
747 }
748
749 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
750 {
751     ok(0, "unexpected call\n");
752     return E_NOTIMPL;
753 }
754
755 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
756 {
757     ok(0, "unexpected call\n");
758     return E_NOTIMPL;
759 }
760
761 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
762         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
763 {
764     ok(0, "unexpected call\n");
765     return E_NOTIMPL;
766 }
767
768 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
769 {
770     ok(0, "unexpected call\n");
771     return E_NOTIMPL;
772 }
773
774 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
775     BindStatusCallback_QueryInterface,
776     BindStatusCallback_AddRef,
777     BindStatusCallback_Release,
778     BindStatusCallback_OnStartBinding,
779     BindStatusCallback_GetPriority,
780     BindStatusCallback_OnLowResource,
781     BindStatusCallback_OnProgress,
782     BindStatusCallback_OnStopBinding,
783     BindStatusCallback_GetBindInfo,
784     BindStatusCallback_OnDataAvailable,
785     BindStatusCallback_OnObjectAvailable
786 };
787
788 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
789
790 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
791 {
792     *ppv = NULL;
793
794     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
795     return E_NOINTERFACE;
796 }
797
798 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
799 {
800     return 2;
801 }
802
803 static ULONG WINAPI Moniker_Release(IMoniker *iface)
804 {
805     return 1;
806 }
807
808 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
809 {
810     ok(0, "unexpected call\n");
811     return E_NOTIMPL;
812 }
813
814 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
815 {
816     ok(0, "unexpected call\n");
817     return E_NOTIMPL;
818 }
819
820 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
821 {
822     ok(0, "unexpected call\n");
823     return E_NOTIMPL;
824 }
825
826 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
827 {
828     ok(0, "unexpected call\n");
829     return E_NOTIMPL;
830 }
831
832 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
833 {
834     ok(0, "unexpected call\n");
835     return E_NOTIMPL;
836 }
837
838 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft,
839         REFIID riidResult, void **ppvResult)
840 {
841     ok(0, "unexpected call\n");
842     return E_NOTIMPL;
843 }
844
845 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
846         REFIID riid, void **ppv)
847 {
848     IUnknown *unk;
849     HRESULT hres;
850
851     static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
852
853     CHECK_EXPECT(BindToStorage);
854
855     ok(pbc == _bctx, "pbc != _bctx\n");
856     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
857     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
858     ok(ppv != NULL, "ppv == NULL\n");
859     ok(*ppv == NULL, "*ppv=%p\n", *ppv);
860
861     hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
862     ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
863     ok(unk != NULL, "unk == NULL\n");
864
865     IUnknown_Release(unk);
866
867     return S_OK;
868 }
869
870 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
871         IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
872 {
873     ok(0, "unexpected call\n");
874     return E_NOTIMPL;
875 }
876
877 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
878         BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
879 {
880     ok(0, "unexpected call\n");
881     return E_NOTIMPL;
882 }
883
884 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
885 {
886     ok(0, "unexpected call\n");
887     return E_NOTIMPL;
888 }
889
890 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
891 {
892     ok(0, "unexpected call\n");
893     return E_NOTIMPL;
894 }
895
896 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
897 {
898     ok(0, "unexpected call\n");
899     return E_NOTIMPL;
900 }
901
902 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
903         IMoniker *pmkNewlyRunning)
904 {
905     ok(0, "unexpected call\n");
906     return E_NOTIMPL;
907 }
908
909 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
910         IMoniker *pmkToLeft, FILETIME *pFileTime)
911 {
912     ok(0, "unexpected call\n");
913     return E_NOTIMPL;
914 }
915
916 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
917 {
918     ok(0, "unexpected call\n");
919     return E_NOTIMPL;
920 }
921
922 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
923         IMoniker **ppmkPrefix)
924 {
925     ok(0, "unexpected call\n");
926     return E_NOTIMPL;
927 }
928
929 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
930         IMoniker **pmkRelPath)
931 {
932     ok(0, "unexpected call\n");
933     return E_NOTIMPL;
934 }
935
936 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
937         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
938 {
939     static const WCHAR winehq_urlW[] =
940             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
941              '/','s','i','t','e','/','a','b','o','u','t',0};
942
943     CHECK_EXPECT(GetDisplayName);
944
945     ok(pbc != NULL, "pbc == NULL\n");
946     ok(pbc != _bctx, "pbc == _bctx\n");
947     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
948
949     *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
950     memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
951     return S_OK;
952 }
953
954 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
955         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
956 {
957     ok(0, "unexpected call\n");
958     return E_NOTIMPL;
959 }
960
961 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
962 {
963     CHECK_EXPECT2(IsSystemMoniker);
964
965     *pdwMksys = MKSYS_URLMONIKER;
966     return S_OK;
967 }
968
969 static IMonikerVtbl MonikerVtbl = {
970     Moniker_QueryInterface,
971     Moniker_AddRef,
972     Moniker_Release,
973     Moniker_GetClassID,
974     Moniker_IsDirty,
975     Moniker_Load,
976     Moniker_Save,
977     Moniker_GetSizeMax,
978     Moniker_BindToObject,
979     Moniker_BindToStorage,
980     Moniker_Reduce,
981     Moniker_ComposeWith,
982     Moniker_Enum,
983     Moniker_IsEqual,
984     Moniker_Hash,
985     Moniker_IsRunning,
986     Moniker_GetTimeOfLastChange,
987     Moniker_Inverse,
988     Moniker_CommonPrefixWith,
989     Moniker_RelativePathTo,
990     Moniker_GetDisplayName,
991     Moniker_ParseDisplayName,
992     Moniker_IsSystemMoniker
993 };
994
995 static IMoniker Moniker = { &MonikerVtbl };
996
997 static void test_HlinkResolveMonikerForData(void)
998 {
999     IBindCtx *bctx;
1000     HRESULT hres;
1001
1002     CreateBindCtx(0, &bctx);
1003     _bctx = bctx;
1004
1005     SET_EXPECT(IsSystemMoniker);
1006     SET_EXPECT(GetDisplayName);
1007     SET_EXPECT(BindToStorage);
1008
1009     hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
1010     ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
1011
1012     CHECK_CALLED(IsSystemMoniker);
1013     CHECK_CALLED(GetDisplayName);
1014     CHECK_CALLED(BindToStorage);
1015
1016     IBindCtx_Release(bctx);
1017 }
1018
1019 static void test_HlinkGetSetMonikerReference(void)
1020 {
1021     IMoniker *found_trgt, *dummy, *dummy2;
1022     IHlink *hlink;
1023     HRESULT hres;
1024     const WCHAR one[] = {'1',0};
1025     const WCHAR two[] = {'2',0};
1026     const WCHAR name[] = {'a',0};
1027     WCHAR *found_loc;
1028
1029     /* create two dummy monikers to use as targets */
1030     hres = CreateItemMoniker(one, one, &dummy);
1031     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1032
1033     hres = CreateItemMoniker(two, two, &dummy2);
1034     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1035
1036     /* create a new hlink: target => dummy, location => one */
1037     hres = HlinkCreateFromMoniker(dummy, one, name, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1038     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1039
1040     /* validate the target and location */
1041     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1042     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1043     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1044     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1045     IMoniker_Release(found_trgt);
1046
1047     /* set location => two */
1048     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_LOCATION, dummy2, two);
1049     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1050
1051     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1052     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1053     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1054     IMoniker_Release(found_trgt);
1055
1056     /* set target => dummy2 */
1057     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, dummy2, one);
1058     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1059
1060     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1061     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1062     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1063     IMoniker_Release(found_trgt);
1064
1065     /* set target => dummy, location => one */
1066     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, dummy, one);
1067     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1068
1069     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1070     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1071     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1072     IMoniker_Release(found_trgt);
1073
1074     /* no HLINKSETF flags */
1075     hres = IHlink_SetMonikerReference(hlink, 0, dummy2, two);
1076     ok(hres == E_INVALIDARG, "IHlink_SetMonikerReference should've failed with E_INVALIDARG (0x%08x), failed with 0x%08x\n", E_INVALIDARG, hres);
1077
1078     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1079     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1080     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1081     IMoniker_Release(found_trgt);
1082
1083     /* invalid HLINKSETF flags */
1084     hres = IHlink_SetMonikerReference(hlink, 12, dummy2, two);
1085     ok(hres == 12, "IHlink_SetMonikerReference should've failed with 0x%08x, failed with 0x%08x\n", 12, hres);
1086
1087     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1088     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1089     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1090     IMoniker_Release(found_trgt);
1091
1092     /* valid & invalid HLINKSETF flags */
1093     hres = IHlink_SetMonikerReference(hlink, 12 | HLINKSETF_TARGET, dummy2, two);
1094     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1095
1096     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1097     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, 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
1101     /* NULL args */
1102     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, NULL, NULL);
1103     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1104
1105     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1106     ok(found_trgt == NULL, "Found target should've been %p, was: %p\n", NULL, found_trgt);
1107     ok(found_loc == NULL, "Found location should've been %s, was: %s\n", wine_dbgstr_w(NULL), wine_dbgstr_w(found_loc));
1108     if(found_trgt)
1109         IMoniker_Release(found_trgt);
1110
1111     IHlink_Release(hlink);
1112     IMoniker_Release(dummy2);
1113     IMoniker_Release(dummy);
1114 }
1115
1116 START_TEST(hlink)
1117 {
1118     CoInitialize(NULL);
1119
1120     test_HlinkIsShortcut();
1121     test_reference();
1122     test_persist();
1123     test_special_reference();
1124     test_HlinkCreateExtensionServices();
1125     test_HlinkParseDisplayName();
1126     test_HlinkResolveMonikerForData();
1127     test_HlinkGetSetMonikerReference();
1128
1129     CoUninitialize();
1130 }