msi/tests: Skip some source tests if a required product key cannot be created.
[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     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1097     if (0) ok(hres == 12, "IHlink_SetMonikerReference should've failed with 0x%08x, failed with 0x%08x\n", 12, hres);
1098
1099     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1100     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1101     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1102     IMoniker_Release(found_trgt);
1103     CoTaskMemFree(found_loc);
1104
1105     /* valid & invalid HLINKSETF flags */
1106     hres = IHlink_SetMonikerReference(hlink, 12 | HLINKSETF_TARGET, dummy2, two);
1107     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1108
1109     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1110     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1111     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1112     IMoniker_Release(found_trgt);
1113     CoTaskMemFree(found_loc);
1114
1115     /* NULL args */
1116     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, NULL, NULL);
1117     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1118
1119     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1120     ok(found_trgt == NULL, "Found target should've been %p, was: %p\n", NULL, found_trgt);
1121     ok(found_loc == NULL, "Found location should've been %s, was: %s\n", wine_dbgstr_w(NULL), wine_dbgstr_w(found_loc));
1122     if(found_trgt)
1123         IMoniker_Release(found_trgt);
1124
1125     IHlink_Release(hlink);
1126     IMoniker_Release(dummy2);
1127     IMoniker_Release(dummy);
1128 }
1129
1130 static void test_HlinkGetSetStringReference(void)
1131 {
1132     IHlink *link;
1133     static const WCHAR one[] = {'1',0};
1134     static const WCHAR two[] = {'2',0};
1135     static const WCHAR three[] = {'3',0};
1136     static const WCHAR empty[] = {0};
1137     WCHAR *fnd_tgt, *fnd_loc;
1138     HRESULT hres;
1139
1140     /* create a new hlink: target => NULL, location => one */
1141     hres = HlinkCreateFromMoniker(NULL, one, empty, NULL, 0, NULL, &IID_IHlink, (void**)&link);
1142     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1143
1144     /* test setting/getting location */
1145     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1146     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1147     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1148     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1149     CoTaskMemFree(fnd_tgt);
1150     CoTaskMemFree(fnd_loc);
1151
1152     hres = IHlink_SetStringReference(link, HLINKSETF_LOCATION, one, two);
1153     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1154
1155     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1156     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1157     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1158     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1159     CoTaskMemFree(fnd_tgt);
1160     CoTaskMemFree(fnd_loc);
1161
1162     hres = IHlink_SetStringReference(link, -HLINKSETF_LOCATION, two, one);
1163     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1164
1165     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1166     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1167     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1168     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1169     CoTaskMemFree(fnd_tgt);
1170     CoTaskMemFree(fnd_loc);
1171
1172     /* test setting/getting target */
1173     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET, two, three);
1174     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1175
1176     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1177     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1178     ok(!lstrcmpW(fnd_tgt, two), "Found target should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_tgt));
1179     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1180     CoTaskMemFree(fnd_tgt);
1181     CoTaskMemFree(fnd_loc);
1182
1183     hres = IHlink_SetStringReference(link, -HLINKSETF_TARGET, three, two);
1184     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1185
1186     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1187     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1188     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1189     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1190     CoTaskMemFree(fnd_tgt);
1191     CoTaskMemFree(fnd_loc);
1192
1193     /* test setting/getting both */
1194     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET | HLINKSETF_LOCATION, one, two);
1195     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1196
1197     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1198     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1199     ok(!lstrcmpW(fnd_tgt, one), "Found target should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_tgt));
1200     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1201     CoTaskMemFree(fnd_tgt);
1202     CoTaskMemFree(fnd_loc);
1203
1204     hres = IHlink_SetStringReference(link, -(HLINKSETF_TARGET | HLINKSETF_LOCATION), three, one);
1205     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1206
1207     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1208     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1209     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1210     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1211     CoTaskMemFree(fnd_tgt);
1212     CoTaskMemFree(fnd_loc);
1213
1214     /* test invalid flags/params */
1215     hres = IHlink_GetStringReference(link, 4, &fnd_tgt, &fnd_loc);
1216     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1217            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1218     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1219     ok(fnd_loc == NULL, "Found location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1220     CoTaskMemFree(fnd_tgt);
1221     CoTaskMemFree(fnd_loc);
1222
1223     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, NULL);
1224     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1225            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1226     CoTaskMemFree(fnd_tgt);
1227
1228     hres = IHlink_GetStringReference(link, -1, NULL, NULL);
1229     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1230
1231     hres = IHlink_GetStringReference(link, -1, NULL, &fnd_loc);
1232     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1233     CoTaskMemFree(fnd_loc);
1234
1235     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, &fnd_loc);
1236     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1237            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1238     CoTaskMemFree(fnd_tgt);
1239     CoTaskMemFree(fnd_loc);
1240
1241     hres = IHlink_GetStringReference(link, -2, &fnd_tgt, &fnd_loc);
1242     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1243            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1244     CoTaskMemFree(fnd_tgt);
1245     CoTaskMemFree(fnd_loc);
1246
1247     hres = IHlink_SetStringReference(link, 4, NULL, NULL);
1248     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1249     if (0) ok(hres == 4, "IHlink_SetStringReference should have failed with 0x4, instead: 0x%08x\n", hres);
1250
1251     hres = IHlink_SetStringReference(link, -4, NULL, NULL);
1252     if (0) ok(hres == -4, "IHlink_SetStringReference should have failed with 0xFFFFFFFC, instead: 0x%08x\n", hres);
1253
1254     IHlink_Release(link);
1255 }
1256
1257 #define setStringRef(h,f,t,l) r_setStringRef(__LINE__,h,f,t,l)
1258 static void r_setStringRef(unsigned line, IHlink *hlink, DWORD flags, const WCHAR *tgt, const WCHAR *loc)
1259 {
1260     HRESULT hres;
1261     hres = IHlink_SetStringReference(hlink, flags, tgt, loc);
1262     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1263 }
1264
1265 #define getStringRef(h,t,l) r_getStringRef(__LINE__,h,t,l)
1266 static void r_getStringRef(unsigned line, IHlink *hlink, const WCHAR *exp_tgt, const WCHAR *exp_loc)
1267 {
1268     HRESULT hres;
1269     WCHAR *fnd_tgt, *fnd_loc;
1270
1271     hres = IHlink_GetStringReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1272     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1273
1274     if(exp_tgt)
1275         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));
1276     else
1277         ok_(__FILE__,line) (fnd_tgt == NULL, "Found string target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1278
1279     if(exp_loc)
1280         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));
1281     else
1282         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1283
1284     CoTaskMemFree(fnd_tgt);
1285     CoTaskMemFree(fnd_loc);
1286 }
1287
1288 #define setMonikerRef(h,f,t,l) r_setMonikerRef(__LINE__,h,f,t,l)
1289 static void r_setMonikerRef(unsigned line, IHlink *hlink, DWORD flags, IMoniker *tgt, const WCHAR *loc)
1290 {
1291     HRESULT hres;
1292     hres = IHlink_SetMonikerReference(hlink, flags, tgt, loc);
1293     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1294 }
1295
1296 /* passing 0xFFFFFFFF as exp_tgt will return the retrieved target & not test it */
1297 #define getMonikerRef(h,t,l) r_getMonikerRef(__LINE__,h,t,l)
1298 static IMoniker *r_getMonikerRef(unsigned line, IHlink *hlink, IMoniker *exp_tgt, const WCHAR *exp_loc)
1299 {
1300     HRESULT hres;
1301     IMoniker *fnd_tgt;
1302     WCHAR *fnd_loc;
1303
1304     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1305     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1306
1307     if(exp_loc)
1308         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));
1309     else
1310         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1311
1312     CoTaskMemFree(fnd_loc);
1313
1314     if(exp_tgt == (IMoniker*)0xFFFFFFFF)
1315         return fnd_tgt;
1316
1317     ok_(__FILE__,line) (fnd_tgt == exp_tgt, "Found moniker target should have been %p, was: %p\n", exp_tgt, fnd_tgt);
1318
1319     if(fnd_tgt)
1320         IMoniker_Release(fnd_tgt);
1321
1322     return NULL;
1323 }
1324
1325 static void test_HlinkMoniker(void)
1326 {
1327     IHlink *hlink;
1328     IMoniker *aMon, *file_mon;
1329     static const WCHAR emptyW[] = {0};
1330     static const WCHAR wordsW[] = {'w','o','r','d','s',0};
1331     static const WCHAR aW[] = {'a',0};
1332     static const WCHAR bW[] = {'b',0};
1333     HRESULT hres;
1334
1335     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1336     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1337     getStringRef(hlink, NULL, NULL);
1338     getMonikerRef(hlink, NULL, NULL);
1339
1340     /* setting a string target creates a moniker reference */
1341     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, aW, wordsW);
1342     getStringRef(hlink, aW, wordsW);
1343     aMon = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, wordsW);
1344     ok(aMon != NULL, "Moniker from %s target should not be NULL\n", wine_dbgstr_w(aW));
1345     if(aMon)
1346         IMoniker_Release(aMon);
1347
1348     /* setting target & location to the empty string deletes the moniker
1349      * reference */
1350     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, emptyW, emptyW);
1351     getStringRef(hlink, NULL, NULL);
1352     getMonikerRef(hlink, NULL, NULL);
1353
1354     /* setting a moniker target also sets the target string to that moniker's
1355      * display name */
1356     hres = CreateFileMoniker(bW, &file_mon);
1357     ok(hres == S_OK, "CreateFileMoniker failed: 0x%08x\n", hres);
1358
1359     setMonikerRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, file_mon, wordsW);
1360     getStringRef(hlink, bW, wordsW);
1361     getMonikerRef(hlink, file_mon, wordsW);
1362
1363     IMoniker_Release(file_mon);
1364
1365     IHlink_Release(hlink);
1366 }
1367
1368 static void test_HashLink(void)
1369 {
1370     IHlink *hlink;
1371     IMoniker *pmk;
1372     const WCHAR hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r',0};
1373     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};
1374     const WCHAR hash_no_tgtW[] = {'#','a','n','a','n','c','h','o','r',0};
1375     const WCHAR tgt_partW[] = {'a','f','i','l','e',0};
1376     const WCHAR loc_partW[] = {'a','n','a','n','c','h','o','r',0};
1377     const WCHAR two_hash_loc_partW[] = {'a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1378     const WCHAR test_locW[] = {'t','e','s','t','l','o','c',0};
1379     HRESULT hres;
1380
1381     /* simple single hash test */
1382     hres = HlinkCreateFromString(hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1383     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1384     ok(hlink != NULL, "Didn't get an hlink\n");
1385
1386     if(hlink){
1387         getStringRef(hlink, tgt_partW, loc_partW);
1388         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1389         ok(pmk != NULL, "Found moniker should not be NULL\n");
1390         if(pmk)
1391             IMoniker_Release(pmk);
1392
1393         setStringRef(hlink, HLINKSETF_TARGET, hash_targetW, NULL);
1394         getStringRef(hlink, hash_targetW, loc_partW);
1395
1396         IHlink_Release(hlink);
1397     }
1398
1399     /* two hashes in the target */
1400     hres = HlinkCreateFromString(two_hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1401     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1402     ok(hlink != NULL, "Didn't get an hlink\n");
1403
1404     if(hlink){
1405         getStringRef(hlink, tgt_partW, two_hash_loc_partW);
1406         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, two_hash_loc_partW);
1407         ok(pmk != NULL, "Found moniker should not be NULL\n");
1408         if(pmk)
1409             IMoniker_Release(pmk);
1410
1411         IHlink_Release(hlink);
1412     }
1413
1414     /* target with hash plus a location string */
1415     hres = HlinkCreateFromString(hash_targetW, test_locW, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1416     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1417     ok(hlink != NULL, "Didn't get an hlink\n");
1418
1419     if(hlink){
1420         getStringRef(hlink, tgt_partW, test_locW);
1421         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, test_locW);
1422         ok(pmk != NULL, "Found moniker should not be NULL\n");
1423         if(pmk)
1424             IMoniker_Release(pmk);
1425
1426         IHlink_Release(hlink);
1427     }
1428
1429     /* target with hash containing no "target part" */
1430     hres = HlinkCreateFromString(hash_no_tgtW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1431     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1432     ok(hlink != NULL, "Didn't get an hlink\n");
1433
1434     if(hlink){
1435         getStringRef(hlink, NULL, loc_partW);
1436         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1437         ok(pmk == NULL, "Found moniker should be NULL\n");
1438         if(pmk)
1439             IMoniker_Release(pmk);
1440
1441         IHlink_Release(hlink);
1442     }
1443 }
1444
1445 START_TEST(hlink)
1446 {
1447     CoInitialize(NULL);
1448
1449     test_HlinkIsShortcut();
1450     test_reference();
1451     test_persist();
1452     test_special_reference();
1453     test_HlinkCreateExtensionServices();
1454     test_HlinkParseDisplayName();
1455     test_HlinkResolveMonikerForData();
1456     test_HlinkGetSetMonikerReference();
1457     test_HlinkGetSetStringReference();
1458     test_HlinkMoniker();
1459     test_HashLink();
1460
1461     CoUninitialize();
1462 }