comctl32: Only support an alpha channel for 32-bpp DIB-based imagelists.
[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, -1, NULL, NULL);
139     ok(r == S_OK, "failed, r=%08x\n", r);
140
141     r = IHlink_GetStringReference(lnk, -1, NULL, &str);
142     ok(r == S_OK, "failed, r=%08x\n", r);
143     ok(str == NULL, "string should be null\n");
144
145     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, &str, NULL);
146     ok(r == S_OK, "failed\n");
147     ok(!lstrcmpW(str, url2), "url wrong\n");
148     CoTaskMemFree(str);
149
150     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
151     ok(r == S_OK, "failed\n");
152
153     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, &str);
154     ok(r == S_OK, "failed\n");
155     ok(str == NULL, "string should be null\n");
156
157     /* Unimplented functions checks */
158     r = IHlink_GetAdditionalParams(lnk, NULL);
159     ok(r == E_NOTIMPL, "failed\n");
160
161     r = IHlink_SetAdditionalParams(lnk, NULL);
162     ok(r == E_NOTIMPL, "failed\n");
163
164     IHlink_Release(lnk);
165 }
166
167 /* url only */
168 static const unsigned char expected_hlink_data[] =
169 {
170     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
171     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
172     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
173     0x26,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
174     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
175     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
176     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
177     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
178     0x00,0x00,
179 };
180
181 /* url only (IE7) */
182 static const unsigned char expected_hlink_data_ie7[] =
183 {
184     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
185     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
186     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
187     0x3e,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
188     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
189     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
190     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
191     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
192     0x00,0x00,0x79,0x58,0x81,0xf4,0x3b,0x1d,
193     0x7f,0x48,0xaf,0x2c,0x82,0x5d,0xc4,0x85,
194     0x27,0x63,0x00,0x00,0x00,0x00,0xa5,0xab,
195     0x00,0x00,
196 };
197
198 /* url + friendly name */
199 static const unsigned char expected_hlink_data2[] =
200 {
201     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
202     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
203     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
204     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
205     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
206     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
207     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
208     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
209     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
210     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
211     0x67,0x00,0x2f,0x00,0x00,0x00,
212 };
213
214 /* url + friendly name (IE7) */
215 static const unsigned char expected_hlink_data2_ie7[] =
216 {
217     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
218     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
219     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
220     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
221     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
222     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
223     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
224     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
225     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
226     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
227     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
228     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
229     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
230     0x00,0x00,0xa5,0xab,0x00,0x00,
231 };
232
233 /* url + friendly name + location */
234 static const unsigned char expected_hlink_data3[] =
235 {
236     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
237     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
238     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
239     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
240     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
241     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
242     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
243     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
244     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
245     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
246     0x67,0x00,0x2f,0x00,0x00,0x00,0x07,0x00,
247     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
248     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
249 };
250
251 /* url + friendly name + location (IE7) */
252 static const unsigned char expected_hlink_data3_ie7[] =
253 {
254     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
255     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
256     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
257     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
258     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
259     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
260     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
261     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
262     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
263     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
264     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
265     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
266     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
267     0x00,0x00,0xa5,0xab,0x00,0x00,0x07,0x00,
268     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
269     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
270 };
271
272 /* relative url */
273 static const unsigned char expected_hlink_data4[] =
274 {
275     0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
276     0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
277     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
278     0x00,0x00,0x0b,0x00,0x00,0x00,0x69,0x6e,
279     0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,
280     0x00,0xff,0xff,0xad,0xde,0x00,0x00,0x00,
281     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
282     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
283     0x00,0x00,0x00,0x00,0x00,
284 };
285
286 /* url + target frame name */
287 static const unsigned char expected_hlink_data5[] =
288 {
289     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
290     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
291     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
292     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
293     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
294     0xa9,0x0b,0x26,0x00,0x00,0x00,0x68,0x00,
295     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
296     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
297     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
298     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
299     0x2f,0x00,0x00,0x00,
300 };
301
302 /* url + target frame name (IE7) */
303 static const unsigned char expected_hlink_data5_ie7[] =
304 {
305     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
306     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
307     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
308     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
309     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
310     0xa9,0x0b,0x3e,0x00,0x00,0x00,0x68,0x00,
311     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
312     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
313     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
314     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
315     0x2f,0x00,0x00,0x00,0x79,0x58,0x81,0xf4,
316     0x3b,0x1d,0x7f,0x48,0xaf,0x2c,0x82,0x5d,
317     0xc4,0x85,0x27,0x63,0x00,0x00,0x00,0x00,
318     0xa5,0xab,0x00,0x00,
319 };
320
321 /* filename */
322 static const unsigned char expected_hlink_data6[] =
323 {
324      0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
325      0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
326      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
327      0x00,0x00,0x04,0x00,0x00,0x00,0x63,0x3a,
328      0x5c,0x00,0xff,0xff,0xad,0xde,0x00,0x00,
329      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
330      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
331      0x00,0x00,0x0c,0x00,0x00,0x00,0x06,0x00,
332      0x00,0x00,0x03,0x00,0x63,0x00,0x3a,0x00,
333      0x5c,0x00,
334 };
335
336 static void test_persist_save_data(const char *testname, IHlink *lnk,
337                                    const unsigned char *expected_data,
338                                    unsigned int expected_data_size,
339                                    const unsigned char *expected_data_alt,
340                                    unsigned int expected_data_alt_size)
341 {
342     HRESULT hr;
343     IStream *stream;
344     IPersistStream *ps;
345     HGLOBAL hglobal;
346     DWORD data_size;
347     const unsigned char *data;
348     DWORD i;
349     BOOL same;
350     unsigned int expected_data_win9x_size = 0;
351
352     hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
353     ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
354
355     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
356     ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
357
358     hr = IPersistStream_Save(ps, stream, TRUE);
359     ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
360
361     hr = GetHGlobalFromStream(stream, &hglobal);
362     ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
363
364     data_size = GlobalSize(hglobal);
365
366     data = GlobalLock(hglobal);
367
368     if (expected_data_size % 4)
369         expected_data_win9x_size =  4 * ((expected_data_size / 4) + 1);
370
371     /* first check we have the right amount of data */
372     ok((data_size == expected_data_size) ||
373        (data_size == expected_data_alt_size) ||
374        broken(data_size == expected_data_win9x_size), /* Win9x and WinMe */
375        "%s: Size of saved data differs (expected %d or %d, actual %d)\n",
376        testname, expected_data_size, expected_data_alt_size, data_size);
377
378     same = TRUE;
379     /* then do a byte-by-byte comparison */
380     for (i = 0; i < min(data_size, expected_data_size); i++)
381     {
382         if ((expected_data[i] != data[i]) &&
383             (((expected_data != expected_hlink_data2) &&
384               (expected_data != expected_hlink_data3)) ||
385              ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
386         {
387             same = FALSE;
388             break;
389         }
390     }
391
392     if (!same && (expected_data_alt != expected_data))
393     {
394         /* then try the alternate data */
395         same = TRUE;
396         for (i = 0; i < min(data_size, expected_data_alt_size); i++)
397         {
398             if ((expected_data_alt[i] != data[i]) &&
399                 (((expected_data_alt != expected_hlink_data2) &&
400                   (expected_data_alt != expected_hlink_data3)) ||
401                  ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
402             {
403                 same = FALSE;
404                 break;
405             }
406         }
407     }
408
409     ok(same, "%s: Saved data differs\n", testname);
410     if (!same)
411     {
412         for (i = 0; i < data_size; i++)
413         {
414             if (i % 8 == 0) printf("    ");
415             printf("0x%02x,", data[i]);
416             if (i % 8 == 7) printf("\n");
417         }
418         printf("\n");
419     }
420
421     GlobalUnlock(hglobal);
422
423     IStream_Release(stream);
424     IPersistStream_Release(ps);
425 }
426
427 static void test_persist(void)
428 {
429     static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
430     static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
431     static const WCHAR filename[] = { 'c',':','\\',0 };
432     static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
433     static const WCHAR location[] = { '_','b','l','a','n','k',0 };
434     static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
435     HRESULT hr;
436     IHlink *lnk;
437
438     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
439                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
440     ok(hr == S_OK, "IHlinkCreateFromString failed with error 0x%08x\n", hr);
441     if (!lnk) {
442         skip("Can't create lnk, skipping test_persist.  Was wineprefixcreate run properly?\n");
443         return;
444     }
445     test_persist_save_data("url only", lnk,
446         expected_hlink_data, sizeof(expected_hlink_data),
447         expected_hlink_data_ie7, sizeof(expected_hlink_data_ie7));
448     IHlink_Release(lnk);
449
450     hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
451                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
452     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
453     test_persist_save_data("url + friendly name", lnk,
454         expected_hlink_data2, sizeof(expected_hlink_data2),
455         expected_hlink_data2_ie7, sizeof(expected_hlink_data2_ie7));
456     IHlink_Release(lnk);
457
458     hr = HlinkCreateFromString(url, location, friendly_name, NULL,
459                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
460     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
461     test_persist_save_data("url + friendly_name + location", lnk,
462         expected_hlink_data3, sizeof(expected_hlink_data3),
463         expected_hlink_data3_ie7, sizeof(expected_hlink_data3_ie7));
464     IHlink_Release(lnk);
465
466     hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
467                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
468     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
469     test_persist_save_data("relative url", lnk,
470         expected_hlink_data4, sizeof(expected_hlink_data4),
471         expected_hlink_data4, sizeof(expected_hlink_data4));
472     IHlink_Release(lnk);
473
474     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
475                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
476     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
477     hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
478     ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
479     test_persist_save_data("url + target frame name", lnk,
480         expected_hlink_data5, sizeof(expected_hlink_data5),
481         expected_hlink_data5_ie7, sizeof(expected_hlink_data5_ie7));
482     IHlink_Release(lnk);
483
484     hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
485                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
486     ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
487     test_persist_save_data("filename", lnk,
488         expected_hlink_data6, sizeof(expected_hlink_data6),
489         expected_hlink_data6, sizeof(expected_hlink_data6));
490     IHlink_Release(lnk);
491 }
492
493 static void test_special_reference(void)
494 {
495     LPWSTR ref;
496     HRESULT hres;
497
498     hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
499     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
500     ok(ref != NULL, "ref == NULL\n");
501     CoTaskMemFree(ref);
502
503     hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
504     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
505     ok(ref != NULL, "ref == NULL\n");
506     CoTaskMemFree(ref);
507
508     ref = (void*)0xdeadbeef;
509     hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
510     ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
511     ok(ref == NULL, "ref=%p\n", ref);
512
513     ref = (void*)0xdeadbeef;
514     hres = HlinkGetSpecialReference(4, &ref);
515     ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
516     ok(ref == NULL, "ref=%p\n", ref);
517 }
518
519 static void test_HlinkCreateExtensionServices(void)
520 {
521     IAuthenticate *authenticate;
522     IHttpNegotiate *http_negotiate;
523     LPWSTR password, username, headers;
524     HWND hwnd;
525     HRESULT hres;
526
527     static const WCHAR usernameW[] = {'u','s','e','r',0};
528     static const WCHAR passwordW[] = {'p','a','s','s',0};
529     static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
530     static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
531
532     hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
533                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
534     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
535     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
536
537     password = username = (void*)0xdeadbeef;
538     hwnd = (void*)0xdeadbeef;
539     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
540     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
541     ok(!hwnd, "hwnd != NULL\n");
542     ok(!username, "username != NULL\n");
543     ok(!password, "password != NULL\n");
544
545     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
546     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
547
548     headers = (void*)0xdeadbeef;
549     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
550                                                0, &headers);
551     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
552     ok(headers == NULL, "headers != NULL\n");
553
554     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
555                                                0, NULL);
556     ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
557
558     headers = (void*)0xdeadbeef;
559     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
560     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
561     ok(headers == NULL, "headers != NULL\n");
562
563     IHttpNegotiate_Release(http_negotiate);
564     IAuthenticate_Release(authenticate);
565
566
567     hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
568                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
569     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
570     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
571
572     password = username = NULL;
573     hwnd = NULL;
574     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
575     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
576     ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
577     ok(!lstrcmpW(username, usernameW), "unexpected username\n");
578     ok(!lstrcmpW(password, passwordW), "unexpected password\n");
579     CoTaskMemFree(username);
580     CoTaskMemFree(password);
581
582     password = username = (void*)0xdeadbeef;
583     hwnd = (void*)0xdeadbeef;
584     hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
585     ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
586     ok(password == (void*)0xdeadbeef, "password = %p\n", password);
587     ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
588
589     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
590     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
591
592     headers = (void*)0xdeadbeef;
593     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
594                                                0, &headers);
595     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
596     ok(!lstrcmpW(headers, headersexW), "unexpected headers %s\n", wine_dbgstr_w(headers));
597     CoTaskMemFree(headers);
598
599     headers = (void*)0xdeadbeef;
600     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
601     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
602     ok(headers == NULL, "unexpected headers %s\n", wine_dbgstr_w(headers));
603
604     IHttpNegotiate_Release(http_negotiate);
605     IAuthenticate_Release(authenticate);
606 }
607
608 static void test_HlinkParseDisplayName(void)
609 {
610     IMoniker *mon = NULL;
611     LPWSTR name;
612     DWORD issys;
613     ULONG eaten = 0;
614     IBindCtx *bctx;
615     HRESULT hres;
616
617     static const WCHAR winehq_urlW[] =
618             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
619              '/','s','i','t','e','/','a','b','o','u','t',0};
620     static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
621     static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':',
622             '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8',
623             '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0};
624
625     CreateBindCtx(0, &bctx);
626
627     hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon);
628     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
629     ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
630     ok(mon != NULL, "mon == NULL\n");
631
632     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
633     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
634     ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
635     CoTaskMemFree(name);
636
637     hres = IMoniker_IsSystemMoniker(mon, &issys);
638     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
639     ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys);
640
641     IMoniker_Release(mon);
642
643     hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon);
644     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
645     ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
646     ok(mon != NULL, "mon == NULL\n");
647
648     hres = IMoniker_IsSystemMoniker(mon, &issys);
649     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
650     ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys);
651
652     IMoniker_Release(mon);
653
654     hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon);
655      ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
656     ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
657     ok(mon != NULL, "mon == NULL\n");
658
659     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
660     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
661     ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
662     CoTaskMemFree(name);
663
664     hres = IMoniker_IsSystemMoniker(mon, &issys);
665     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
666     ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys);
667
668     IMoniker_Release(mon);
669     IBindCtx_Release(bctx);
670 }
671
672 static IBindCtx *_bctx;
673
674 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
675 {
676     ok(0, "unexpected call\n");
677     return E_NOINTERFACE;
678 }
679
680 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
681 {
682     return 2;
683 }
684
685 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
686 {
687     return 1;
688 }
689
690 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
691         REFGUID guidService, REFIID riid, void **ppv)
692 {
693     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
694     return E_NOINTERFACE;
695 }
696
697 static IServiceProviderVtbl ServiceProviderVtbl = {
698     ServiceProvider_QueryInterface,
699     ServiceProvider_AddRef,
700     ServiceProvider_Release,
701     ServiceProvider_QueryService
702 };
703
704 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
705
706 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
707 {
708     *ppv = NULL;
709
710     if(IsEqualGUID(riid, &IID_IServiceProvider)) {
711         *ppv = &ServiceProvider;
712         return S_OK;
713     }
714
715     ok(0, "unexpected interface %s\n", debugstr_guid(riid));
716     return E_NOINTERFACE;
717 }
718
719 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
720 {
721     return 2;
722 }
723
724 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
725 {
726     return 1;
727 }
728
729 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
730         IBinding *pib)
731 {
732     ok(0, "unexpected call\n");
733     return E_NOTIMPL;
734 }
735
736 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
737 {
738     ok(0, "unexpected call\n");
739     return E_NOTIMPL;
740 }
741
742 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
743 {
744     ok(0, "unexpected call\n");
745     return E_NOTIMPL;
746 }
747
748 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
749         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
750 {
751     ok(0, "unexpected call\n");
752     return E_NOTIMPL;
753 }
754
755 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
756 {
757     ok(0, "unexpected call\n");
758     return E_NOTIMPL;
759 }
760
761 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
762 {
763     ok(0, "unexpected call\n");
764     return E_NOTIMPL;
765 }
766
767 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
768         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
769 {
770     ok(0, "unexpected call\n");
771     return E_NOTIMPL;
772 }
773
774 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
775 {
776     ok(0, "unexpected call\n");
777     return E_NOTIMPL;
778 }
779
780 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
781     BindStatusCallback_QueryInterface,
782     BindStatusCallback_AddRef,
783     BindStatusCallback_Release,
784     BindStatusCallback_OnStartBinding,
785     BindStatusCallback_GetPriority,
786     BindStatusCallback_OnLowResource,
787     BindStatusCallback_OnProgress,
788     BindStatusCallback_OnStopBinding,
789     BindStatusCallback_GetBindInfo,
790     BindStatusCallback_OnDataAvailable,
791     BindStatusCallback_OnObjectAvailable
792 };
793
794 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
795
796 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
797 {
798     *ppv = NULL;
799
800     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
801     return E_NOINTERFACE;
802 }
803
804 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
805 {
806     return 2;
807 }
808
809 static ULONG WINAPI Moniker_Release(IMoniker *iface)
810 {
811     return 1;
812 }
813
814 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
815 {
816     ok(0, "unexpected call\n");
817     return E_NOTIMPL;
818 }
819
820 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
821 {
822     ok(0, "unexpected call\n");
823     return E_NOTIMPL;
824 }
825
826 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
827 {
828     ok(0, "unexpected call\n");
829     return E_NOTIMPL;
830 }
831
832 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
833 {
834     ok(0, "unexpected call\n");
835     return E_NOTIMPL;
836 }
837
838 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
839 {
840     ok(0, "unexpected call\n");
841     return E_NOTIMPL;
842 }
843
844 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft,
845         REFIID riidResult, void **ppvResult)
846 {
847     ok(0, "unexpected call\n");
848     return E_NOTIMPL;
849 }
850
851 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
852         REFIID riid, void **ppv)
853 {
854     IUnknown *unk;
855     HRESULT hres;
856
857     static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
858
859     CHECK_EXPECT(BindToStorage);
860
861     ok(pbc == _bctx, "pbc != _bctx\n");
862     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
863     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
864     ok(ppv != NULL, "ppv == NULL\n");
865     ok(*ppv == NULL, "*ppv=%p\n", *ppv);
866
867     hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
868     ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
869     ok(unk != NULL, "unk == NULL\n");
870
871     IUnknown_Release(unk);
872
873     return S_OK;
874 }
875
876 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
877         IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
878 {
879     ok(0, "unexpected call\n");
880     return E_NOTIMPL;
881 }
882
883 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
884         BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
885 {
886     ok(0, "unexpected call\n");
887     return E_NOTIMPL;
888 }
889
890 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
891 {
892     ok(0, "unexpected call\n");
893     return E_NOTIMPL;
894 }
895
896 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
897 {
898     ok(0, "unexpected call\n");
899     return E_NOTIMPL;
900 }
901
902 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
903 {
904     ok(0, "unexpected call\n");
905     return E_NOTIMPL;
906 }
907
908 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
909         IMoniker *pmkNewlyRunning)
910 {
911     ok(0, "unexpected call\n");
912     return E_NOTIMPL;
913 }
914
915 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
916         IMoniker *pmkToLeft, FILETIME *pFileTime)
917 {
918     ok(0, "unexpected call\n");
919     return E_NOTIMPL;
920 }
921
922 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
923 {
924     ok(0, "unexpected call\n");
925     return E_NOTIMPL;
926 }
927
928 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
929         IMoniker **ppmkPrefix)
930 {
931     ok(0, "unexpected call\n");
932     return E_NOTIMPL;
933 }
934
935 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
936         IMoniker **pmkRelPath)
937 {
938     ok(0, "unexpected call\n");
939     return E_NOTIMPL;
940 }
941
942 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
943         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
944 {
945     static const WCHAR winehq_urlW[] =
946             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
947              '/','s','i','t','e','/','a','b','o','u','t',0};
948
949     CHECK_EXPECT(GetDisplayName);
950
951     ok(pbc != NULL, "pbc == NULL\n");
952     ok(pbc != _bctx, "pbc == _bctx\n");
953     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
954
955     *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
956     memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
957     return S_OK;
958 }
959
960 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
961         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
962 {
963     ok(0, "unexpected call\n");
964     return E_NOTIMPL;
965 }
966
967 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
968 {
969     CHECK_EXPECT2(IsSystemMoniker);
970
971     *pdwMksys = MKSYS_URLMONIKER;
972     return S_OK;
973 }
974
975 static IMonikerVtbl MonikerVtbl = {
976     Moniker_QueryInterface,
977     Moniker_AddRef,
978     Moniker_Release,
979     Moniker_GetClassID,
980     Moniker_IsDirty,
981     Moniker_Load,
982     Moniker_Save,
983     Moniker_GetSizeMax,
984     Moniker_BindToObject,
985     Moniker_BindToStorage,
986     Moniker_Reduce,
987     Moniker_ComposeWith,
988     Moniker_Enum,
989     Moniker_IsEqual,
990     Moniker_Hash,
991     Moniker_IsRunning,
992     Moniker_GetTimeOfLastChange,
993     Moniker_Inverse,
994     Moniker_CommonPrefixWith,
995     Moniker_RelativePathTo,
996     Moniker_GetDisplayName,
997     Moniker_ParseDisplayName,
998     Moniker_IsSystemMoniker
999 };
1000
1001 static IMoniker Moniker = { &MonikerVtbl };
1002
1003 static void test_HlinkResolveMonikerForData(void)
1004 {
1005     IBindCtx *bctx;
1006     HRESULT hres;
1007
1008     CreateBindCtx(0, &bctx);
1009     _bctx = bctx;
1010
1011     SET_EXPECT(IsSystemMoniker);
1012     SET_EXPECT(GetDisplayName);
1013     SET_EXPECT(BindToStorage);
1014
1015     hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
1016     ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
1017
1018     CHECK_CALLED(IsSystemMoniker);
1019     CHECK_CALLED(GetDisplayName);
1020     CHECK_CALLED(BindToStorage);
1021
1022     IBindCtx_Release(bctx);
1023 }
1024
1025 static void test_HlinkGetSetMonikerReference(void)
1026 {
1027     IMoniker *found_trgt, *dummy, *dummy2;
1028     IHlink *hlink;
1029     HRESULT hres;
1030     const WCHAR one[] = {'1',0};
1031     const WCHAR two[] = {'2',0};
1032     const WCHAR name[] = {'a',0};
1033     WCHAR *found_loc;
1034
1035     /* create two dummy monikers to use as targets */
1036     hres = CreateItemMoniker(one, one, &dummy);
1037     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1038
1039     hres = CreateItemMoniker(two, two, &dummy2);
1040     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1041
1042     /* create a new hlink: target => dummy, location => one */
1043     hres = HlinkCreateFromMoniker(dummy, one, name, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1044     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1045
1046     /* validate the target and location */
1047     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1048     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1049     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1050     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1051     IMoniker_Release(found_trgt);
1052     CoTaskMemFree(found_loc);
1053
1054     /* set location => two */
1055     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_LOCATION, dummy2, two);
1056     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1057
1058     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1059     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1060     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1061     IMoniker_Release(found_trgt);
1062     CoTaskMemFree(found_loc);
1063
1064     /* set target => dummy2 */
1065     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, dummy2, one);
1066     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1067
1068     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1069     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1070     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1071     IMoniker_Release(found_trgt);
1072     CoTaskMemFree(found_loc);
1073
1074     /* set target => dummy, location => one */
1075     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, dummy, one);
1076     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", 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     CoTaskMemFree(found_loc);
1083
1084     /* no HLINKSETF flags */
1085     hres = IHlink_SetMonikerReference(hlink, 0, dummy2, two);
1086     ok(hres == E_INVALIDARG, "IHlink_SetMonikerReference should've failed with E_INVALIDARG (0x%08x), failed with 0x%08x\n", E_INVALIDARG, hres);
1087
1088     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1089     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1090     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1091     IMoniker_Release(found_trgt);
1092     CoTaskMemFree(found_loc);
1093
1094     /* invalid HLINKSETF flags */
1095     hres = IHlink_SetMonikerReference(hlink, 12, dummy2, two);
1096     ok(hres == 12, "IHlink_SetMonikerReference should've failed with 0x%08x, failed with 0x%08x\n", 12, hres);
1097
1098     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1099     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1100     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1101     IMoniker_Release(found_trgt);
1102     CoTaskMemFree(found_loc);
1103
1104     /* valid & invalid HLINKSETF flags */
1105     hres = IHlink_SetMonikerReference(hlink, 12 | HLINKSETF_TARGET, dummy2, two);
1106     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1107
1108     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1109     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1110     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1111     IMoniker_Release(found_trgt);
1112     CoTaskMemFree(found_loc);
1113
1114     /* NULL args */
1115     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, NULL, NULL);
1116     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1117
1118     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1119     ok(found_trgt == NULL, "Found target should've been %p, was: %p\n", NULL, found_trgt);
1120     ok(found_loc == NULL, "Found location should've been %s, was: %s\n", wine_dbgstr_w(NULL), wine_dbgstr_w(found_loc));
1121     if(found_trgt)
1122         IMoniker_Release(found_trgt);
1123
1124     IHlink_Release(hlink);
1125     IMoniker_Release(dummy2);
1126     IMoniker_Release(dummy);
1127 }
1128
1129 static void test_HlinkGetSetStringReference(void)
1130 {
1131     IHlink *link;
1132     static const WCHAR one[] = {'1',0};
1133     static const WCHAR two[] = {'2',0};
1134     static const WCHAR three[] = {'3',0};
1135     static const WCHAR empty[] = {0};
1136     WCHAR *fnd_tgt, *fnd_loc;
1137     HRESULT hres;
1138
1139     /* create a new hlink: target => NULL, location => one */
1140     hres = HlinkCreateFromMoniker(NULL, one, empty, NULL, 0, NULL, &IID_IHlink, (void**)&link);
1141     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1142
1143     /* test setting/getting location */
1144     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1145     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1146     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1147     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1148     CoTaskMemFree(fnd_tgt);
1149     CoTaskMemFree(fnd_loc);
1150
1151     hres = IHlink_SetStringReference(link, HLINKSETF_LOCATION, one, two);
1152     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1153
1154     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1155     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1156     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1157     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1158     CoTaskMemFree(fnd_tgt);
1159     CoTaskMemFree(fnd_loc);
1160
1161     hres = IHlink_SetStringReference(link, -HLINKSETF_LOCATION, two, one);
1162     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1163
1164     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1165     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1166     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1167     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1168     CoTaskMemFree(fnd_tgt);
1169     CoTaskMemFree(fnd_loc);
1170
1171     /* test setting/getting target */
1172     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET, two, three);
1173     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1174
1175     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1176     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1177     ok(!lstrcmpW(fnd_tgt, two), "Found target should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_tgt));
1178     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1179     CoTaskMemFree(fnd_tgt);
1180     CoTaskMemFree(fnd_loc);
1181
1182     hres = IHlink_SetStringReference(link, -HLINKSETF_TARGET, three, two);
1183     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1184
1185     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1186     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1187     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1188     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1189     CoTaskMemFree(fnd_tgt);
1190     CoTaskMemFree(fnd_loc);
1191
1192     /* test setting/getting both */
1193     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET | HLINKSETF_LOCATION, one, two);
1194     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1195
1196     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1197     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1198     ok(!lstrcmpW(fnd_tgt, one), "Found target should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_tgt));
1199     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1200     CoTaskMemFree(fnd_tgt);
1201     CoTaskMemFree(fnd_loc);
1202
1203     hres = IHlink_SetStringReference(link, -(HLINKSETF_TARGET | HLINKSETF_LOCATION), three, one);
1204     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1205
1206     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1207     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1208     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1209     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1210     CoTaskMemFree(fnd_tgt);
1211     CoTaskMemFree(fnd_loc);
1212
1213     /* test invalid flags/params */
1214     hres = IHlink_GetStringReference(link, 4, &fnd_tgt, &fnd_loc);
1215     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1216            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1217     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1218     ok(fnd_loc == NULL, "Found location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1219     CoTaskMemFree(fnd_tgt);
1220     CoTaskMemFree(fnd_loc);
1221
1222     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, NULL);
1223     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1224            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1225     CoTaskMemFree(fnd_tgt);
1226
1227     hres = IHlink_GetStringReference(link, -1, NULL, NULL);
1228     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1229
1230     hres = IHlink_GetStringReference(link, -1, NULL, &fnd_loc);
1231     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1232     CoTaskMemFree(fnd_loc);
1233
1234     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, &fnd_loc);
1235     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1236            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1237     CoTaskMemFree(fnd_tgt);
1238     CoTaskMemFree(fnd_loc);
1239
1240     hres = IHlink_GetStringReference(link, -2, &fnd_tgt, &fnd_loc);
1241     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1242            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1243     CoTaskMemFree(fnd_tgt);
1244     CoTaskMemFree(fnd_loc);
1245
1246     hres = IHlink_SetStringReference(link, 4, NULL, NULL);
1247     ok(hres == 4, "IHlink_SetStringReference should have failed with 0x4, instead: 0x%08x\n", hres);
1248
1249     hres = IHlink_SetStringReference(link, -4, NULL, NULL);
1250     ok(hres == -4, "IHlink_SetStringReference should have failed with 0xFFFFFFFC, instead: 0x%08x\n", hres);
1251
1252     IHlink_Release(link);
1253 }
1254
1255 #define setStringRef(h,f,t,l) r_setStringRef(__LINE__,h,f,t,l)
1256 static void r_setStringRef(unsigned line, IHlink *hlink, DWORD flags, const WCHAR *tgt, const WCHAR *loc)
1257 {
1258     HRESULT hres;
1259     hres = IHlink_SetStringReference(hlink, flags, tgt, loc);
1260     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1261 }
1262
1263 #define getStringRef(h,t,l) r_getStringRef(__LINE__,h,t,l)
1264 static void r_getStringRef(unsigned line, IHlink *hlink, const WCHAR *exp_tgt, const WCHAR *exp_loc)
1265 {
1266     HRESULT hres;
1267     WCHAR *fnd_tgt, *fnd_loc;
1268
1269     hres = IHlink_GetStringReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1270     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1271
1272     if(exp_tgt)
1273         ok_(__FILE__,line) (!lstrcmpW(fnd_tgt, exp_tgt), "Found string target should have been %s, was: %s\n", wine_dbgstr_w(exp_tgt), wine_dbgstr_w(fnd_tgt));
1274     else
1275         ok_(__FILE__,line) (fnd_tgt == NULL, "Found string target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1276
1277     if(exp_loc)
1278         ok_(__FILE__,line) (!lstrcmpW(fnd_loc, exp_loc), "Found string location should have been %s, was: %s\n", wine_dbgstr_w(exp_loc), wine_dbgstr_w(fnd_loc));
1279     else
1280         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1281
1282     CoTaskMemFree(fnd_tgt);
1283     CoTaskMemFree(fnd_loc);
1284 }
1285
1286 #define setMonikerRef(h,f,t,l) r_setMonikerRef(__LINE__,h,f,t,l)
1287 static void r_setMonikerRef(unsigned line, IHlink *hlink, DWORD flags, IMoniker *tgt, const WCHAR *loc)
1288 {
1289     HRESULT hres;
1290     hres = IHlink_SetMonikerReference(hlink, flags, tgt, loc);
1291     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1292 }
1293
1294 /* passing 0xFFFFFFFF as exp_tgt will return the retrieved target & not test it */
1295 #define getMonikerRef(h,t,l) r_getMonikerRef(__LINE__,h,t,l)
1296 static IMoniker *r_getMonikerRef(unsigned line, IHlink *hlink, IMoniker *exp_tgt, const WCHAR *exp_loc)
1297 {
1298     HRESULT hres;
1299     IMoniker *fnd_tgt;
1300     WCHAR *fnd_loc;
1301
1302     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1303     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1304
1305     if(exp_loc)
1306         ok_(__FILE__,line) (!lstrcmpW(fnd_loc, exp_loc), "Found string location should have been %s, was: %s\n", wine_dbgstr_w(exp_loc), wine_dbgstr_w(fnd_loc));
1307     else
1308         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1309
1310     CoTaskMemFree(fnd_loc);
1311
1312     if(exp_tgt == (IMoniker*)0xFFFFFFFF)
1313         return fnd_tgt;
1314
1315     ok_(__FILE__,line) (fnd_tgt == exp_tgt, "Found moniker target should have been %p, was: %p\n", exp_tgt, fnd_tgt);
1316
1317     if(fnd_tgt)
1318         IMoniker_Release(fnd_tgt);
1319
1320     return NULL;
1321 }
1322
1323 static void test_HlinkMoniker(void)
1324 {
1325     IHlink *hlink;
1326     IMoniker *aMon, *file_mon;
1327     static const WCHAR emptyW[] = {0};
1328     static const WCHAR wordsW[] = {'w','o','r','d','s',0};
1329     static const WCHAR aW[] = {'a',0};
1330     static const WCHAR bW[] = {'b',0};
1331     HRESULT hres;
1332
1333     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1334     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1335     getStringRef(hlink, NULL, NULL);
1336     getMonikerRef(hlink, NULL, NULL);
1337
1338     /* setting a string target creates a moniker reference */
1339     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, aW, wordsW);
1340     getStringRef(hlink, aW, wordsW);
1341     aMon = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, wordsW);
1342     ok(aMon != NULL, "Moniker from %s target should not be NULL\n", wine_dbgstr_w(aW));
1343     if(aMon)
1344         IMoniker_Release(aMon);
1345
1346     /* setting target & location to the empty string deletes the moniker
1347      * reference */
1348     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, emptyW, emptyW);
1349     getStringRef(hlink, NULL, NULL);
1350     getMonikerRef(hlink, NULL, NULL);
1351
1352     /* setting a moniker target also sets the target string to that moniker's
1353      * display name */
1354     hres = CreateFileMoniker(bW, &file_mon);
1355     ok(hres == S_OK, "CreateFileMoniker failed: 0x%08x\n", hres);
1356
1357     setMonikerRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, file_mon, wordsW);
1358     getStringRef(hlink, bW, wordsW);
1359     getMonikerRef(hlink, file_mon, wordsW);
1360
1361     IMoniker_Release(file_mon);
1362
1363     IHlink_Release(hlink);
1364 }
1365
1366 static void test_HashLink(void)
1367 {
1368     IHlink *hlink;
1369     IMoniker *pmk;
1370     const WCHAR hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r',0};
1371     const WCHAR two_hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1372     const WCHAR hash_no_tgtW[] = {'#','a','n','a','n','c','h','o','r',0};
1373     const WCHAR tgt_partW[] = {'a','f','i','l','e',0};
1374     const WCHAR loc_partW[] = {'a','n','a','n','c','h','o','r',0};
1375     const WCHAR two_hash_loc_partW[] = {'a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1376     const WCHAR test_locW[] = {'t','e','s','t','l','o','c',0};
1377     HRESULT hres;
1378
1379     /* simple single hash test */
1380     hres = HlinkCreateFromString(hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1381     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1382     ok(hlink != NULL, "Didn't get an hlink\n");
1383
1384     if(hlink){
1385         getStringRef(hlink, tgt_partW, loc_partW);
1386         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1387         ok(pmk != NULL, "Found moniker should not be NULL\n");
1388         if(pmk)
1389             IMoniker_Release(pmk);
1390
1391         setStringRef(hlink, HLINKSETF_TARGET, hash_targetW, NULL);
1392         getStringRef(hlink, hash_targetW, loc_partW);
1393
1394         IHlink_Release(hlink);
1395     }
1396
1397     /* two hashes in the target */
1398     hres = HlinkCreateFromString(two_hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1399     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1400     ok(hlink != NULL, "Didn't get an hlink\n");
1401
1402     if(hlink){
1403         getStringRef(hlink, tgt_partW, two_hash_loc_partW);
1404         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, two_hash_loc_partW);
1405         ok(pmk != NULL, "Found moniker should not be NULL\n");
1406         if(pmk)
1407             IMoniker_Release(pmk);
1408
1409         IHlink_Release(hlink);
1410     }
1411
1412     /* target with hash plus a location string */
1413     hres = HlinkCreateFromString(hash_targetW, test_locW, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1414     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1415     ok(hlink != NULL, "Didn't get an hlink\n");
1416
1417     if(hlink){
1418         getStringRef(hlink, tgt_partW, test_locW);
1419         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, test_locW);
1420         ok(pmk != NULL, "Found moniker should not be NULL\n");
1421         if(pmk)
1422             IMoniker_Release(pmk);
1423
1424         IHlink_Release(hlink);
1425     }
1426
1427     /* target with hash containing no "target part" */
1428     hres = HlinkCreateFromString(hash_no_tgtW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1429     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1430     ok(hlink != NULL, "Didn't get an hlink\n");
1431
1432     if(hlink){
1433         getStringRef(hlink, NULL, loc_partW);
1434         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1435         ok(pmk == NULL, "Found moniker should be NULL\n");
1436         if(pmk)
1437             IMoniker_Release(pmk);
1438
1439         IHlink_Release(hlink);
1440     }
1441 }
1442
1443 START_TEST(hlink)
1444 {
1445     CoInitialize(NULL);
1446
1447     test_HlinkIsShortcut();
1448     test_reference();
1449     test_persist();
1450     test_special_reference();
1451     test_HlinkCreateExtensionServices();
1452     test_HlinkParseDisplayName();
1453     test_HlinkResolveMonikerForData();
1454     test_HlinkGetSetMonikerReference();
1455     test_HlinkGetSetStringReference();
1456     test_HlinkMoniker();
1457     test_HashLink();
1458
1459     CoUninitialize();
1460 }