Release 1.5.29.
[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(BindToObject);
59 DEFINE_EXPECT(GetDisplayName);
60
61 DEFINE_EXPECT(ComposeWith);
62 DEFINE_EXPECT(OnNavigationComplete);
63 DEFINE_EXPECT(Enum);
64 DEFINE_EXPECT(Reduce);
65
66 DEFINE_EXPECT(GetClassID);
67 DEFINE_EXPECT(Save);
68
69 DEFINE_EXPECT(HBC_QueryInterface_IHlinkHistory);
70 DEFINE_EXPECT(HBC_GetObject);
71 DEFINE_EXPECT(HBC_UpdateHlink);
72
73 DEFINE_EXPECT(HT_SetBrowseContext);
74 DEFINE_EXPECT(HT_GetBrowseContext);
75 DEFINE_EXPECT(HT_Navigate);
76 DEFINE_EXPECT(HT_GetFriendlyName);
77
78 DEFINE_EXPECT(HLF_UpdateHlink);
79
80 DEFINE_GUID(IID_IHlinkHistory,0x79eac9c8,0xbaf9,0x11ce,0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b);
81
82 static const char *debugstr_guid(REFIID riid)
83 {
84     static char buf[50];
85
86     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
87             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
88             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
89             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
90
91     return buf;
92 }
93
94 static void test_HlinkIsShortcut(void)
95 {
96     UINT i;
97     HRESULT hres;
98
99     static const WCHAR file0[] = {'f','i','l','e',0};
100     static const WCHAR file1[] = {'f','i','l','e','.','u','r','l',0};
101     static const WCHAR file2[] = {'f','i','l','e','.','l','n','k',0};
102     static const WCHAR file3[] = {'f','i','l','e','.','u','R','l',0};
103     static const WCHAR file4[] = {'f','i','l','e','u','r','l',0};
104     static const WCHAR file5[] = {'c',':','\\','f','i','l','e','.','u','r','l',0};
105     static const WCHAR file6[] = {'c',':','\\','f','i','l','e','.','l','n','k',0};
106     static const WCHAR file7[] = {'.','u','r','l',0};
107
108     static struct {
109         LPCWSTR file;
110         HRESULT hres;
111     } shortcut_test[] = {
112         {file0, S_FALSE},
113         {file1, S_OK},
114         {file2, S_FALSE},
115         {file3, S_OK},
116         {file4, S_FALSE},
117         {file5, S_OK},
118         {file6, S_FALSE},
119         {file7, S_OK},
120         {NULL,  E_INVALIDARG}
121     };
122
123     for(i=0; i<sizeof(shortcut_test)/sizeof(shortcut_test[0]); i++) {
124         hres = HlinkIsShortcut(shortcut_test[i].file);
125         ok(hres == shortcut_test[i].hres, "[%d] HlinkIsShortcut returned %08x, expected %08x\n",
126            i, hres, shortcut_test[i].hres);
127     }
128 }
129
130 static void test_reference(void)
131 {
132     HRESULT r;
133     IHlink *lnk = NULL;
134     IMoniker *mk = NULL;
135     const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
136     const WCHAR url2[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/',0 };
137     LPWSTR str = NULL;
138
139     r = HlinkCreateFromString(url, NULL, NULL, NULL,
140                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
141     ok(r == S_OK, "failed to create link\n");
142     if (FAILED(r))
143         return;
144
145     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
146     ok(r == S_OK, "failed\n");
147
148     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, &mk, &str);
149     ok(r == S_OK, "failed\n");
150     ok(mk != NULL, "no moniker\n");
151     ok(str == NULL, "string should be null\n");
152
153     r = IMoniker_Release(mk);
154     ok( r == 1, "moniker refcount wrong\n");
155
156     r = IHlink_GetStringReference(lnk, -1, &str, NULL);
157     ok(r == S_OK, "failed\n");
158     CoTaskMemFree(str);
159
160     r = IHlink_GetStringReference(lnk, -1, NULL, NULL);
161     ok(r == S_OK, "failed, r=%08x\n", r);
162
163     r = IHlink_GetStringReference(lnk, -1, NULL, &str);
164     ok(r == S_OK, "failed, r=%08x\n", r);
165     ok(str == NULL, "string should be null\n");
166
167     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, &str, NULL);
168     ok(r == S_OK, "failed\n");
169     ok(!lstrcmpW(str, url2), "url wrong\n");
170     CoTaskMemFree(str);
171
172     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
173     ok(r == S_OK, "failed\n");
174
175     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, &str);
176     ok(r == S_OK, "failed\n");
177     ok(str == NULL, "string should be null\n");
178
179     /* Unimplented functions checks */
180     r = IHlink_GetAdditionalParams(lnk, NULL);
181     ok(r == E_NOTIMPL, "failed\n");
182
183     r = IHlink_SetAdditionalParams(lnk, NULL);
184     ok(r == E_NOTIMPL, "failed\n");
185
186     IHlink_Release(lnk);
187 }
188
189 /* url only */
190 static const unsigned char expected_hlink_data[] =
191 {
192     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
193     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
194     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
195     0x26,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
196     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
197     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
198     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
199     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
200     0x00,0x00,
201 };
202
203 /* url only (IE7) */
204 static const unsigned char expected_hlink_data_ie7[] =
205 {
206     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
207     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
208     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
209     0x3e,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
210     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
211     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
212     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
213     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
214     0x00,0x00,0x79,0x58,0x81,0xf4,0x3b,0x1d,
215     0x7f,0x48,0xaf,0x2c,0x82,0x5d,0xc4,0x85,
216     0x27,0x63,0x00,0x00,0x00,0x00,0xa5,0xab,
217     0x00,0x00,
218 };
219
220 /* url + friendly name */
221 static const unsigned char expected_hlink_data2[] =
222 {
223     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
224     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
225     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
226     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
227     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
228     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
229     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
230     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
231     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
232     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
233     0x67,0x00,0x2f,0x00,0x00,0x00,
234 };
235
236 /* url + friendly name (IE7) */
237 static const unsigned char expected_hlink_data2_ie7[] =
238 {
239     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
240     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
241     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
242     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
243     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
244     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
245     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
246     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
247     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
248     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
249     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
250     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
251     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
252     0x00,0x00,0xa5,0xab,0x00,0x00,
253 };
254
255 /* url + friendly name + location */
256 static const unsigned char expected_hlink_data3[] =
257 {
258     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
259     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
260     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
261     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
262     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
263     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
264     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
265     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
266     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
267     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
268     0x67,0x00,0x2f,0x00,0x00,0x00,0x07,0x00,
269     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
270     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
271 };
272
273 /* url + friendly name + location (IE7) */
274 static const unsigned char expected_hlink_data3_ie7[] =
275 {
276     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
277     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
278     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
279     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
280     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
281     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
282     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
283     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
284     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
285     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
286     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
287     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
288     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
289     0x00,0x00,0xa5,0xab,0x00,0x00,0x07,0x00,
290     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
291     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
292 };
293
294 /* relative url */
295 static const unsigned char expected_hlink_data4[] =
296 {
297     0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
298     0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
299     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
300     0x00,0x00,0x0b,0x00,0x00,0x00,0x69,0x6e,
301     0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,
302     0x00,0xff,0xff,0xad,0xde,0x00,0x00,0x00,
303     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
304     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
305     0x00,0x00,0x00,0x00,0x00,
306 };
307
308 /* url + target frame name */
309 static const unsigned char expected_hlink_data5[] =
310 {
311     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
312     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
313     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
314     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
315     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
316     0xa9,0x0b,0x26,0x00,0x00,0x00,0x68,0x00,
317     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
318     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
319     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
320     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
321     0x2f,0x00,0x00,0x00,
322 };
323
324 /* url + target frame name (IE7) */
325 static const unsigned char expected_hlink_data5_ie7[] =
326 {
327     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
328     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
329     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
330     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
331     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
332     0xa9,0x0b,0x3e,0x00,0x00,0x00,0x68,0x00,
333     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
334     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
335     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
336     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
337     0x2f,0x00,0x00,0x00,0x79,0x58,0x81,0xf4,
338     0x3b,0x1d,0x7f,0x48,0xaf,0x2c,0x82,0x5d,
339     0xc4,0x85,0x27,0x63,0x00,0x00,0x00,0x00,
340     0xa5,0xab,0x00,0x00,
341 };
342
343 /* filename */
344 static const unsigned char expected_hlink_data6[] =
345 {
346      0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
347      0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
348      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
349      0x00,0x00,0x04,0x00,0x00,0x00,0x63,0x3a,
350      0x5c,0x00,0xff,0xff,0xad,0xde,0x00,0x00,
351      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
352      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
353      0x00,0x00,0x0c,0x00,0x00,0x00,0x06,0x00,
354      0x00,0x00,0x03,0x00,0x63,0x00,0x3a,0x00,
355      0x5c,0x00,
356 };
357
358 static void test_persist_save_data(const char *testname, IHlink *lnk,
359                                    const unsigned char *expected_data,
360                                    unsigned int expected_data_size,
361                                    const unsigned char *expected_data_alt,
362                                    unsigned int expected_data_alt_size)
363 {
364     HRESULT hr;
365     IStream *stream;
366     IPersistStream *ps;
367     HGLOBAL hglobal;
368     DWORD data_size;
369     const unsigned char *data;
370     DWORD i;
371     BOOL same;
372
373     hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
374     ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
375
376     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
377     ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
378
379     hr = IPersistStream_Save(ps, stream, TRUE);
380     ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
381
382     hr = GetHGlobalFromStream(stream, &hglobal);
383     ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
384
385     data_size = GlobalSize(hglobal);
386
387     data = GlobalLock(hglobal);
388
389     /* first check we have the right amount of data */
390     ok((data_size == expected_data_size) ||
391        (data_size == expected_data_alt_size),
392        "%s: Size of saved data differs (expected %d or %d, actual %d)\n",
393        testname, expected_data_size, expected_data_alt_size, data_size);
394
395     same = TRUE;
396     /* then do a byte-by-byte comparison */
397     for (i = 0; i < min(data_size, expected_data_size); i++)
398     {
399         if ((expected_data[i] != data[i]) &&
400             (((expected_data != expected_hlink_data2) &&
401               (expected_data != expected_hlink_data3)) ||
402              ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
403         {
404             same = FALSE;
405             break;
406         }
407     }
408
409     if (!same && (expected_data_alt != expected_data))
410     {
411         /* then try the alternate data */
412         same = TRUE;
413         for (i = 0; i < min(data_size, expected_data_alt_size); i++)
414         {
415             if ((expected_data_alt[i] != data[i]) &&
416                 (((expected_data_alt != expected_hlink_data2) &&
417                   (expected_data_alt != expected_hlink_data3)) ||
418                  ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
419             {
420                 same = FALSE;
421                 break;
422             }
423         }
424     }
425
426     ok(same, "%s: Saved data differs\n", testname);
427     if (!same)
428     {
429         for (i = 0; i < data_size; i++)
430         {
431             if (i % 8 == 0) printf("    ");
432             printf("0x%02x,", data[i]);
433             if (i % 8 == 7) printf("\n");
434         }
435         printf("\n");
436     }
437
438     GlobalUnlock(hglobal);
439
440     IStream_Release(stream);
441     IPersistStream_Release(ps);
442 }
443
444 static void test_persist(void)
445 {
446     static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
447     static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
448     static const WCHAR filename[] = { 'c',':','\\',0 };
449     static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
450     static const WCHAR location[] = { '_','b','l','a','n','k',0 };
451     static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
452     HRESULT hr;
453     IHlink *lnk;
454
455     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
456                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
457     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
458     if (!lnk) {
459         skip("Can't create lnk, skipping test_persist.\n");
460         return;
461     }
462     test_persist_save_data("url only", lnk,
463         expected_hlink_data, sizeof(expected_hlink_data),
464         expected_hlink_data_ie7, sizeof(expected_hlink_data_ie7));
465     IHlink_Release(lnk);
466
467     hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
468                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
469     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
470     test_persist_save_data("url + friendly name", lnk,
471         expected_hlink_data2, sizeof(expected_hlink_data2),
472         expected_hlink_data2_ie7, sizeof(expected_hlink_data2_ie7));
473     IHlink_Release(lnk);
474
475     hr = HlinkCreateFromString(url, location, friendly_name, NULL,
476                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
477     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
478     test_persist_save_data("url + friendly_name + location", lnk,
479         expected_hlink_data3, sizeof(expected_hlink_data3),
480         expected_hlink_data3_ie7, sizeof(expected_hlink_data3_ie7));
481     IHlink_Release(lnk);
482
483     hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
484                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
485     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
486     test_persist_save_data("relative url", lnk,
487         expected_hlink_data4, sizeof(expected_hlink_data4),
488         expected_hlink_data4, sizeof(expected_hlink_data4));
489     IHlink_Release(lnk);
490
491     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
492                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
493     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
494     hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
495     ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
496     test_persist_save_data("url + target frame name", lnk,
497         expected_hlink_data5, sizeof(expected_hlink_data5),
498         expected_hlink_data5_ie7, sizeof(expected_hlink_data5_ie7));
499     IHlink_Release(lnk);
500
501     hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
502                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
503     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
504     test_persist_save_data("filename", lnk,
505         expected_hlink_data6, sizeof(expected_hlink_data6),
506         expected_hlink_data6, sizeof(expected_hlink_data6));
507     IHlink_Release(lnk);
508 }
509
510 static void test_special_reference(void)
511 {
512     LPWSTR ref;
513     HRESULT hres;
514
515     hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
516     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
517     ok(ref != NULL, "ref == NULL\n");
518     CoTaskMemFree(ref);
519
520     hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
521     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
522     ok(ref != NULL, "ref == NULL\n");
523     CoTaskMemFree(ref);
524
525     ref = (void*)0xdeadbeef;
526     hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
527     ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
528     ok(ref == NULL, "ref=%p\n", ref);
529
530     ref = (void*)0xdeadbeef;
531     hres = HlinkGetSpecialReference(4, &ref);
532     ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
533     ok(ref == NULL, "ref=%p\n", ref);
534 }
535
536 static void test_HlinkCreateExtensionServices(void)
537 {
538     IAuthenticate *authenticate;
539     IHttpNegotiate *http_negotiate;
540     LPWSTR password, username, headers;
541     HWND hwnd;
542     HRESULT hres;
543
544     static const WCHAR usernameW[] = {'u','s','e','r',0};
545     static const WCHAR passwordW[] = {'p','a','s','s',0};
546     static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
547     static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
548
549     hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
550                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
551     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
552     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
553
554     password = username = (void*)0xdeadbeef;
555     hwnd = (void*)0xdeadbeef;
556     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
557     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
558     ok(!hwnd, "hwnd != NULL\n");
559     ok(!username, "username != NULL\n");
560     ok(!password, "password != NULL\n");
561
562     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
563     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
564
565     headers = (void*)0xdeadbeef;
566     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
567                                                0, &headers);
568     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
569     ok(headers == NULL, "headers != NULL\n");
570
571     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
572                                                0, NULL);
573     ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
574
575     headers = (void*)0xdeadbeef;
576     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
577     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
578     ok(headers == NULL, "headers != NULL\n");
579
580     IHttpNegotiate_Release(http_negotiate);
581     IAuthenticate_Release(authenticate);
582
583
584     hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
585                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
586     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
587     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
588
589     password = username = NULL;
590     hwnd = NULL;
591     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
592     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
593     ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
594     ok(!lstrcmpW(username, usernameW), "unexpected username\n");
595     ok(!lstrcmpW(password, passwordW), "unexpected password\n");
596     CoTaskMemFree(username);
597     CoTaskMemFree(password);
598
599     password = username = (void*)0xdeadbeef;
600     hwnd = (void*)0xdeadbeef;
601     hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
602     ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
603     ok(password == (void*)0xdeadbeef, "password = %p\n", password);
604     ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
605
606     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
607     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
608
609     headers = (void*)0xdeadbeef;
610     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
611                                                0, &headers);
612     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
613     ok(!lstrcmpW(headers, headersexW), "unexpected headers %s\n", wine_dbgstr_w(headers));
614     CoTaskMemFree(headers);
615
616     headers = (void*)0xdeadbeef;
617     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
618     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
619     ok(headers == NULL, "unexpected headers %s\n", wine_dbgstr_w(headers));
620
621     IHttpNegotiate_Release(http_negotiate);
622     IAuthenticate_Release(authenticate);
623 }
624
625 static void test_HlinkParseDisplayName(void)
626 {
627     IMoniker *mon = NULL;
628     LPWSTR name;
629     DWORD issys;
630     ULONG eaten = 0;
631     IBindCtx *bctx;
632     HRESULT hres;
633
634     static const WCHAR winehq_urlW[] =
635             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
636              '/','s','i','t','e','/','a','b','o','u','t',0};
637     static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
638     static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':',
639             '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8',
640             '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0};
641
642     CreateBindCtx(0, &bctx);
643
644     hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon);
645     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
646     ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
647     ok(mon != NULL, "mon == NULL\n");
648
649     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
650     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
651     ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
652     CoTaskMemFree(name);
653
654     hres = IMoniker_IsSystemMoniker(mon, &issys);
655     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
656     ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys);
657
658     IMoniker_Release(mon);
659
660     hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon);
661     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
662     ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
663     ok(mon != NULL, "mon == NULL\n");
664
665     hres = IMoniker_IsSystemMoniker(mon, &issys);
666     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
667     ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys);
668
669     IMoniker_Release(mon);
670
671     hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon);
672      ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
673     ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
674     ok(mon != NULL, "mon == NULL\n");
675
676     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
677     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
678     ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
679     CoTaskMemFree(name);
680
681     hres = IMoniker_IsSystemMoniker(mon, &issys);
682     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
683     ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys);
684
685     IMoniker_Release(mon);
686     IBindCtx_Release(bctx);
687 }
688
689 static IBindCtx *_bctx;
690
691 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
692 {
693     ok(0, "unexpected call\n");
694     return E_NOINTERFACE;
695 }
696
697 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
698 {
699     return 2;
700 }
701
702 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
703 {
704     return 1;
705 }
706
707 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
708         REFGUID guidService, REFIID riid, void **ppv)
709 {
710     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
711     return E_NOINTERFACE;
712 }
713
714 static IServiceProviderVtbl ServiceProviderVtbl = {
715     ServiceProvider_QueryInterface,
716     ServiceProvider_AddRef,
717     ServiceProvider_Release,
718     ServiceProvider_QueryService
719 };
720
721 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
722
723 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
724 {
725     *ppv = NULL;
726
727     if(IsEqualGUID(riid, &IID_IServiceProvider)) {
728         *ppv = &ServiceProvider;
729         return S_OK;
730     }
731
732     ok(0, "unexpected interface %s\n", debugstr_guid(riid));
733     return E_NOINTERFACE;
734 }
735
736 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
737 {
738     return 2;
739 }
740
741 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
742 {
743     return 1;
744 }
745
746 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
747         IBinding *pib)
748 {
749     ok(0, "unexpected call\n");
750     return E_NOTIMPL;
751 }
752
753 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
754 {
755     ok(0, "unexpected call\n");
756     return E_NOTIMPL;
757 }
758
759 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
760 {
761     ok(0, "unexpected call\n");
762     return E_NOTIMPL;
763 }
764
765 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
766         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
767 {
768     ok(0, "unexpected call\n");
769     return E_NOTIMPL;
770 }
771
772 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
773 {
774     ok(0, "unexpected call\n");
775     return E_NOTIMPL;
776 }
777
778 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
779 {
780     ok(0, "unexpected call\n");
781     return E_NOTIMPL;
782 }
783
784 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
785         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
786 {
787     ok(0, "unexpected call\n");
788     return E_NOTIMPL;
789 }
790
791 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
792 {
793     ok(0, "unexpected call\n");
794     return E_NOTIMPL;
795 }
796
797 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
798     BindStatusCallback_QueryInterface,
799     BindStatusCallback_AddRef,
800     BindStatusCallback_Release,
801     BindStatusCallback_OnStartBinding,
802     BindStatusCallback_GetPriority,
803     BindStatusCallback_OnLowResource,
804     BindStatusCallback_OnProgress,
805     BindStatusCallback_OnStopBinding,
806     BindStatusCallback_GetBindInfo,
807     BindStatusCallback_OnDataAvailable,
808     BindStatusCallback_OnObjectAvailable
809 };
810
811 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
812
813 static HRESULT WINAPI HlinkBrowseContext_QueryInterface(
814         IHlinkBrowseContext *iface, REFIID riid, void **ppv)
815 {
816     *ppv = NULL;
817
818     if(IsEqualGUID(&IID_IHlinkHistory, riid)) {
819         CHECK_EXPECT(HBC_QueryInterface_IHlinkHistory);
820         return E_NOINTERFACE;
821     }
822
823     ok(0, "unexpected interface: %s\n", debugstr_guid(riid));
824     return E_NOINTERFACE;
825 }
826
827 static ULONG WINAPI HlinkBrowseContext_AddRef(IHlinkBrowseContext *iface)
828 {
829     return 2;
830 }
831
832 static ULONG WINAPI HlinkBrowseContext_Release(IHlinkBrowseContext *iface)
833 {
834     return 1;
835 }
836
837 static HRESULT WINAPI HlinkBrowseContext_Register(IHlinkBrowseContext *iface,
838         DWORD reserved, IUnknown *piunk, IMoniker *pimk, DWORD *pdwRegister)
839 {
840     ok(0, "unexpected call\n");
841     return E_NOTIMPL;
842 }
843
844 static IMoniker Moniker;
845 static HRESULT WINAPI HlinkBrowseContext_GetObject(IHlinkBrowseContext *iface,
846         IMoniker *pimk, BOOL fBindIfRootRegistered, IUnknown **ppiunk)
847 {
848     CHECK_EXPECT(HBC_GetObject);
849
850     ok(pimk == &Moniker, "pimk != &Moniker\n");
851     ok(fBindIfRootRegistered == 1, "fBindIfRootRegistered = %x\n", fBindIfRootRegistered);
852     *ppiunk = NULL;
853     return S_FALSE;
854 }
855
856 static HRESULT WINAPI HlinkBrowseContext_Revoke(IHlinkBrowseContext *iface, DWORD dwRegister)
857 {
858     ok(0, "unexpected call\n");
859     return E_NOTIMPL;
860 }
861
862 static HRESULT WINAPI HlinkBrowseContext_SetBrowseWindowInfo(
863         IHlinkBrowseContext *iface, HLBWINFO *phlbwi)
864 {
865     ok(0, "unexpected call\n");
866     return E_NOTIMPL;
867 }
868
869 static HRESULT WINAPI HlinkBrowseContext_GetBrowseWindowInfo(
870         IHlinkBrowseContext *iface, HLBWINFO *phlbwi)
871 {
872     ok(0, "unexpected call\n");
873     return E_NOTIMPL;
874 }
875
876 static HRESULT WINAPI HlinkBrowseContext_SetInitialHlink(IHlinkBrowseContext *iface,
877         IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName)
878 {
879     ok(0, "unexpected call\n");
880     return E_NOTIMPL;
881 }
882
883 static HRESULT WINAPI HlinkBrowseContext_OnNavigateHlink(IHlinkBrowseContext *iface, DWORD grfHLNF,
884         IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, ULONG *puHLID)
885 {
886     ok(0, "unexpected call\n");
887     return E_NOTIMPL;
888 }
889
890 static HRESULT WINAPI HlinkBrowseContext_UpdateHlink(IHlinkBrowseContext *iface, ULONG uHLID,
891         IMoniker *pimkTarget, LPCWSTR location, LPCWSTR friendly_name)
892 {
893     CHECK_EXPECT(HBC_UpdateHlink);
894     return S_OK;
895 }
896
897 static HRESULT WINAPI HlinkBrowseContext_EnumNavigationStack(IHlinkBrowseContext *iface,
898         DWORD dwReserved, DWORD grfHLFNAMEF, IEnumHLITEM **ppienumhlitem)
899 {
900     ok(0, "unexpected call\n");
901     return E_NOTIMPL;
902 }
903
904 static HRESULT WINAPI HlinkBrowseContext_QueryHlink(IHlinkBrowseContext *iface,
905         DWORD grfHLQF, ULONG uHLID)
906 {
907     ok(0, "unexpected call\n");
908     return E_NOTIMPL;
909 }
910
911 static HRESULT WINAPI HlinkBrowseContext_GetHlink(IHlinkBrowseContext *iface,
912         ULONG uHLID, IHlink **ppihl)
913 {
914     ok(0, "unexpected call\n");
915     return E_NOTIMPL;
916 }
917
918 static HRESULT WINAPI HlinkBrowseContext_SetCurrentHlink(
919         IHlinkBrowseContext *iface, ULONG uHLID)
920 {
921     ok(0, "unexpected call\n");
922     return E_NOTIMPL;
923 }
924
925 static HRESULT WINAPI HlinkBrowseContext_Clone(IHlinkBrowseContext *iface,
926         IUnknown *piunkOuter, REFIID riid, IUnknown **ppiunkObj)
927 {
928     ok(0, "unexpected call\n");
929     return E_NOTIMPL;
930 }
931
932 static HRESULT WINAPI HlinkBrowseContext_Close(IHlinkBrowseContext *iface, DWORD reserved)
933 {
934     ok(0, "unexpected call\n");
935     return E_NOTIMPL;
936 }
937
938 static IHlinkBrowseContextVtbl HlinkBrowseContextVtbl = {
939     HlinkBrowseContext_QueryInterface,
940     HlinkBrowseContext_AddRef,
941     HlinkBrowseContext_Release,
942     HlinkBrowseContext_Register,
943     HlinkBrowseContext_GetObject,
944     HlinkBrowseContext_Revoke,
945     HlinkBrowseContext_SetBrowseWindowInfo,
946     HlinkBrowseContext_GetBrowseWindowInfo,
947     HlinkBrowseContext_SetInitialHlink,
948     HlinkBrowseContext_OnNavigateHlink,
949     HlinkBrowseContext_UpdateHlink,
950     HlinkBrowseContext_EnumNavigationStack,
951     HlinkBrowseContext_QueryHlink,
952     HlinkBrowseContext_GetHlink,
953     HlinkBrowseContext_SetCurrentHlink,
954     HlinkBrowseContext_Clone,
955     HlinkBrowseContext_Close
956 };
957
958 static IHlinkBrowseContext HlinkBrowseContext = { &HlinkBrowseContextVtbl };
959
960 static HRESULT WINAPI HlinkTarget_QueryInterface(IHlinkTarget *iface, REFIID riid, void **ppv)
961 {
962     if(IsEqualGUID(&IID_IHlinkTarget, riid)) {
963         *ppv = iface;
964         return S_OK;
965     }
966
967     ok(0, "unexpected interface: %s\n", debugstr_guid(riid));
968     return E_NOINTERFACE;
969 }
970
971 static ULONG WINAPI HlinkTarget_AddRef(IHlinkTarget *iface)
972 {
973     return 2;
974 }
975
976 static ULONG WINAPI HlinkTarget_Release(IHlinkTarget *iface)
977 {
978     return 1;
979 }
980
981 static HRESULT WINAPI HlinkTarget_SetBrowseContext(IHlinkTarget *iface,
982         IHlinkBrowseContext *pihlbc)
983 {
984     CHECK_EXPECT(HT_SetBrowseContext);
985
986     ok(pihlbc == &HlinkBrowseContext, "pihlbc != &HlinkBrowseContext (%p)\n", pihlbc);
987     return S_OK;
988 }
989
990 static HRESULT WINAPI HlinkTarget_GetBrowseContext(IHlinkTarget *iface,
991         IHlinkBrowseContext **ppihlbc)
992 {
993     CHECK_EXPECT(HT_GetBrowseContext);
994
995     *ppihlbc = NULL;
996     return S_OK;
997 }
998
999 static HRESULT WINAPI HlinkTarget_Navigate(IHlinkTarget *iface,
1000         DWORD grfHLNF, LPCWSTR pwzJumpLocation)
1001 {
1002     CHECK_EXPECT(HT_Navigate);
1003
1004     ok(grfHLNF == 0, "grfHLNF = %x\n", grfHLNF);
1005     ok(pwzJumpLocation == NULL, "pwzJumpLocation = %s\n", wine_dbgstr_w(pwzJumpLocation));
1006     return S_OK;
1007 }
1008
1009 static HRESULT WINAPI HlinkTarget_GetMoniker(IHlinkTarget *iface,
1010         LPCWSTR pwzLocation, DWORD dwAssign, IMoniker **ppimkLocation)
1011 {
1012     ok(0, "unexpected call\n");
1013     return E_NOTIMPL;
1014 }
1015
1016 static HRESULT WINAPI HlinkTarget_GetFriendlyName(IHlinkTarget *iface,
1017         LPCWSTR pwzLocation, LPWSTR *ppwzFriendlyName)
1018 {
1019     CHECK_EXPECT(HT_GetFriendlyName);
1020     return E_NOTIMPL;
1021 }
1022
1023 static IHlinkTargetVtbl HlinkTargetVtbl = {
1024     HlinkTarget_QueryInterface,
1025     HlinkTarget_AddRef,
1026     HlinkTarget_Release,
1027     HlinkTarget_SetBrowseContext,
1028     HlinkTarget_GetBrowseContext,
1029     HlinkTarget_Navigate,
1030     HlinkTarget_GetMoniker,
1031     HlinkTarget_GetFriendlyName
1032 };
1033
1034 static IHlinkTarget HlinkTarget = { &HlinkTargetVtbl };
1035
1036 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
1037 {
1038     *ppv = NULL;
1039
1040     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
1041     return E_NOINTERFACE;
1042 }
1043
1044 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
1045 {
1046     return 2;
1047 }
1048
1049 static ULONG WINAPI Moniker_Release(IMoniker *iface)
1050 {
1051     return 1;
1052 }
1053
1054 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
1055 {
1056     CHECK_EXPECT(GetClassID);
1057     *pClassID = IID_IUnknown; /* not a valid CLSID */
1058     return S_OK;
1059 }
1060
1061 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
1062 {
1063     ok(0, "unexpected call\n");
1064     return E_NOTIMPL;
1065 }
1066
1067 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
1068 {
1069     ok(0, "unexpected call\n");
1070     return E_NOTIMPL;
1071 }
1072
1073 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
1074 {
1075     CHECK_EXPECT(Save);
1076     return S_OK;
1077 }
1078
1079 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
1080 {
1081     ok(0, "unexpected call\n");
1082     return E_NOTIMPL;
1083 }
1084
1085 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
1086         REFIID riid, void **ppv)
1087 {
1088     CHECK_EXPECT(BindToObject);
1089
1090     ok(pbc != _bctx, "pbc != _bctx\n");
1091     ok(pmkToLeft == NULL, "pmkToLeft = %p\n", pmkToLeft);
1092     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
1093     ok(ppv != NULL, "ppv == NULL\n");
1094     ok(*ppv == NULL, "*ppv = %p\n", *ppv);
1095
1096     *ppv = &HlinkTarget;
1097     return S_OK;
1098 }
1099
1100 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
1101         REFIID riid, void **ppv)
1102 {
1103     IUnknown *unk;
1104     HRESULT hres;
1105
1106     static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
1107
1108     CHECK_EXPECT(BindToStorage);
1109
1110     ok(pbc == _bctx, "pbc != _bctx\n");
1111     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
1112     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
1113     ok(ppv != NULL, "ppv == NULL\n");
1114     ok(*ppv == NULL, "*ppv=%p\n", *ppv);
1115
1116     hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
1117     ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
1118     ok(unk != NULL, "unk == NULL\n");
1119
1120     IUnknown_Release(unk);
1121
1122     return S_OK;
1123 }
1124
1125 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
1126         IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
1127 {
1128     CHECK_EXPECT(Reduce);
1129     return E_NOTIMPL;
1130 }
1131
1132 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
1133         BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
1134 {
1135     ok(0, "unexpected call\n");
1136     return E_NOTIMPL;
1137 }
1138
1139 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
1140 {
1141     CHECK_EXPECT(Enum);
1142     return E_NOTIMPL;
1143 }
1144
1145 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
1146 {
1147     ok(0, "unexpected call\n");
1148     return E_NOTIMPL;
1149 }
1150
1151 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
1152 {
1153     ok(0, "unexpected call\n");
1154     return E_NOTIMPL;
1155 }
1156
1157 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
1158         IMoniker *pmkNewlyRunning)
1159 {
1160     ok(0, "unexpected call\n");
1161     return E_NOTIMPL;
1162 }
1163
1164 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
1165         IMoniker *pmkToLeft, FILETIME *pFileTime)
1166 {
1167     ok(0, "unexpected call\n");
1168     return E_NOTIMPL;
1169 }
1170
1171 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
1172 {
1173     ok(0, "unexpected call\n");
1174     return E_NOTIMPL;
1175 }
1176
1177 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
1178         IMoniker **ppmkPrefix)
1179 {
1180     ok(0, "unexpected call\n");
1181     return E_NOTIMPL;
1182 }
1183
1184 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
1185         IMoniker **pmkRelPath)
1186 {
1187     ok(0, "unexpected call\n");
1188     return E_NOTIMPL;
1189 }
1190
1191 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
1192         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
1193 {
1194     static const WCHAR winehq_urlW[] =
1195             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
1196              '/','s','i','t','e','/','a','b','o','u','t',0};
1197
1198     CHECK_EXPECT2(GetDisplayName);
1199
1200     ok(pbc != NULL, "pbc == NULL\n");
1201     ok(pbc != _bctx, "pbc == _bctx\n");
1202     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
1203
1204     *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
1205     memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
1206     return S_OK;
1207 }
1208
1209 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
1210         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
1211 {
1212     ok(0, "unexpected call\n");
1213     return E_NOTIMPL;
1214 }
1215
1216 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
1217 {
1218     CHECK_EXPECT2(IsSystemMoniker);
1219
1220     *pdwMksys = MKSYS_URLMONIKER;
1221     return S_OK;
1222 }
1223
1224 static IMonikerVtbl MonikerVtbl = {
1225     Moniker_QueryInterface,
1226     Moniker_AddRef,
1227     Moniker_Release,
1228     Moniker_GetClassID,
1229     Moniker_IsDirty,
1230     Moniker_Load,
1231     Moniker_Save,
1232     Moniker_GetSizeMax,
1233     Moniker_BindToObject,
1234     Moniker_BindToStorage,
1235     Moniker_Reduce,
1236     Moniker_ComposeWith,
1237     Moniker_Enum,
1238     Moniker_IsEqual,
1239     Moniker_Hash,
1240     Moniker_IsRunning,
1241     Moniker_GetTimeOfLastChange,
1242     Moniker_Inverse,
1243     Moniker_CommonPrefixWith,
1244     Moniker_RelativePathTo,
1245     Moniker_GetDisplayName,
1246     Moniker_ParseDisplayName,
1247     Moniker_IsSystemMoniker
1248 };
1249
1250 static IMoniker Moniker = { &MonikerVtbl };
1251
1252 static void test_HlinkResolveMonikerForData(void)
1253 {
1254     IBindCtx *bctx;
1255     HRESULT hres;
1256
1257     CreateBindCtx(0, &bctx);
1258     _bctx = bctx;
1259
1260     SET_EXPECT(IsSystemMoniker);
1261     SET_EXPECT(GetDisplayName);
1262     SET_EXPECT(BindToStorage);
1263
1264     hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
1265     ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
1266
1267     CHECK_CALLED(IsSystemMoniker);
1268     CHECK_CALLED(GetDisplayName);
1269     CHECK_CALLED(BindToStorage);
1270
1271     IBindCtx_Release(bctx);
1272     _bctx = NULL;
1273 }
1274
1275 static void test_HlinkGetSetMonikerReference(void)
1276 {
1277     IMoniker *found_trgt, *dummy, *dummy2;
1278     IHlink *hlink;
1279     HRESULT hres;
1280     const WCHAR one[] = {'1',0};
1281     const WCHAR two[] = {'2',0};
1282     const WCHAR name[] = {'a',0};
1283     WCHAR *found_loc;
1284
1285     /* create two dummy monikers to use as targets */
1286     hres = CreateItemMoniker(one, one, &dummy);
1287     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1288
1289     hres = CreateItemMoniker(two, two, &dummy2);
1290     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1291
1292     /* create a new hlink: target => dummy, location => one */
1293     hres = HlinkCreateFromMoniker(dummy, one, name, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1294     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1295
1296     /* validate the target and location */
1297     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1298     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1299     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1300     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1301     IMoniker_Release(found_trgt);
1302     CoTaskMemFree(found_loc);
1303
1304     /* set location => two */
1305     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_LOCATION, dummy2, two);
1306     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1307
1308     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1309     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1310     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1311     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1312     IMoniker_Release(found_trgt);
1313     CoTaskMemFree(found_loc);
1314
1315     /* set target => dummy2 */
1316     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, dummy2, one);
1317     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1318
1319     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1320     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1321     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1322     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1323     IMoniker_Release(found_trgt);
1324     CoTaskMemFree(found_loc);
1325
1326     /* set target => dummy, location => one */
1327     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, dummy, one);
1328     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1329
1330     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1331     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1332     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1333     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1334     IMoniker_Release(found_trgt);
1335     CoTaskMemFree(found_loc);
1336
1337     /* no HLINKSETF flags */
1338     hres = IHlink_SetMonikerReference(hlink, 0, dummy2, two);
1339     ok(hres == E_INVALIDARG, "IHlink_SetMonikerReference should've failed with E_INVALIDARG (0x%08x), failed with 0x%08x\n", E_INVALIDARG, hres);
1340
1341     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1342     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1343     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1344     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1345     IMoniker_Release(found_trgt);
1346     CoTaskMemFree(found_loc);
1347
1348     /* invalid HLINKSETF flags */
1349     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1350     if (0) 
1351         IHlink_SetMonikerReference(hlink, 12, dummy2, two);
1352
1353     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1354     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1355     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1356     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1357     IMoniker_Release(found_trgt);
1358     CoTaskMemFree(found_loc);
1359
1360     /* valid & invalid HLINKSETF flags */
1361     hres = IHlink_SetMonikerReference(hlink, 12 | HLINKSETF_TARGET, dummy2, two);
1362     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1363
1364     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1365     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1366     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1367     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1368     IMoniker_Release(found_trgt);
1369     CoTaskMemFree(found_loc);
1370
1371     /* NULL args */
1372     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, NULL, NULL);
1373     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1374
1375     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1376     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1377     ok(found_trgt == NULL, "Found target should've been %p, was: %p\n", NULL, found_trgt);
1378     ok(found_loc == NULL, "Found location should've been %s, was: %s\n", wine_dbgstr_w(NULL), wine_dbgstr_w(found_loc));
1379     if(found_trgt)
1380         IMoniker_Release(found_trgt);
1381
1382     IHlink_Release(hlink);
1383     IMoniker_Release(dummy2);
1384     IMoniker_Release(dummy);
1385
1386     SET_EXPECT(Reduce);
1387     SET_EXPECT(Enum);
1388     SET_EXPECT(IsSystemMoniker);
1389     SET_EXPECT(GetDisplayName);
1390     hres = HlinkCreateFromMoniker(&Moniker, NULL, NULL, NULL, 0, NULL,
1391             &IID_IHlink, (void **)&hlink);
1392     ok(hres == S_OK, "CreateFromMoniker failed: %08x\n", hres);
1393
1394     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_ABSOLUTE,
1395             &found_trgt, &found_loc);
1396     ok(hres == S_OK, "CreateFromMoniker failed: %08x\n", hres);
1397     ok(found_trgt == &Moniker, "Got unexpected moniker: %p\n", found_trgt);
1398     ok(found_loc == NULL, "Got unexpected location: %p\n", found_loc);
1399     todo_wine CHECK_CALLED(Reduce);
1400     todo_wine CHECK_CALLED(Enum);
1401     CHECK_CALLED(IsSystemMoniker);
1402     CHECK_CALLED(GetDisplayName);
1403
1404     IHlink_Release(hlink);
1405 }
1406
1407 static void test_HlinkGetSetStringReference(void)
1408 {
1409     IHlink *link;
1410     static const WCHAR one[] = {'1',0};
1411     static const WCHAR two[] = {'2',0};
1412     static const WCHAR three[] = {'3',0};
1413     static const WCHAR empty[] = {0};
1414     WCHAR *fnd_tgt, *fnd_loc;
1415     HRESULT hres;
1416
1417     /* create a new hlink: target => NULL, location => one */
1418     hres = HlinkCreateFromMoniker(NULL, one, empty, NULL, 0, NULL, &IID_IHlink, (void**)&link);
1419     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1420
1421     /* test setting/getting location */
1422     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1423     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1424     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1425     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1426     CoTaskMemFree(fnd_tgt);
1427     CoTaskMemFree(fnd_loc);
1428
1429     hres = IHlink_SetStringReference(link, HLINKSETF_LOCATION, one, two);
1430     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1431
1432     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1433     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1434     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1435     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1436     CoTaskMemFree(fnd_tgt);
1437     CoTaskMemFree(fnd_loc);
1438
1439     hres = IHlink_SetStringReference(link, -HLINKSETF_LOCATION, two, one);
1440     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1441
1442     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1443     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1444     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1445     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1446     CoTaskMemFree(fnd_tgt);
1447     CoTaskMemFree(fnd_loc);
1448
1449     /* test setting/getting target */
1450     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET, two, three);
1451     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1452
1453     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1454     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1455     ok(!lstrcmpW(fnd_tgt, two), "Found target should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_tgt));
1456     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1457     CoTaskMemFree(fnd_tgt);
1458     CoTaskMemFree(fnd_loc);
1459
1460     hres = IHlink_SetStringReference(link, -HLINKSETF_TARGET, three, two);
1461     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1462
1463     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1464     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1465     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1466     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1467     CoTaskMemFree(fnd_tgt);
1468     CoTaskMemFree(fnd_loc);
1469
1470     /* test setting/getting both */
1471     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET | HLINKSETF_LOCATION, one, two);
1472     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1473
1474     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1475     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1476     ok(!lstrcmpW(fnd_tgt, one), "Found target should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_tgt));
1477     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1478     CoTaskMemFree(fnd_tgt);
1479     CoTaskMemFree(fnd_loc);
1480
1481     hres = IHlink_SetStringReference(link, -(HLINKSETF_TARGET | HLINKSETF_LOCATION), three, one);
1482     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1483
1484     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1485     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1486     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1487     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1488     CoTaskMemFree(fnd_tgt);
1489     CoTaskMemFree(fnd_loc);
1490
1491     /* test invalid flags/params */
1492     hres = IHlink_GetStringReference(link, 4, &fnd_tgt, &fnd_loc);
1493     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1494            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1495     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1496     ok(fnd_loc == NULL, "Found location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1497     CoTaskMemFree(fnd_tgt);
1498     CoTaskMemFree(fnd_loc);
1499
1500     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, NULL);
1501     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1502            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1503     CoTaskMemFree(fnd_tgt);
1504
1505     hres = IHlink_GetStringReference(link, -1, NULL, NULL);
1506     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1507
1508     hres = IHlink_GetStringReference(link, -1, NULL, &fnd_loc);
1509     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1510     CoTaskMemFree(fnd_loc);
1511
1512     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, &fnd_loc);
1513     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1514            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1515     CoTaskMemFree(fnd_tgt);
1516     CoTaskMemFree(fnd_loc);
1517
1518     hres = IHlink_GetStringReference(link, -2, &fnd_tgt, &fnd_loc);
1519     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1520            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1521     CoTaskMemFree(fnd_tgt);
1522     CoTaskMemFree(fnd_loc);
1523
1524     if (0)
1525     {
1526         /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1527         IHlink_SetStringReference(link, 4, NULL, NULL);
1528         IHlink_SetStringReference(link, -4, NULL, NULL);
1529     }
1530
1531     IHlink_Release(link);
1532 }
1533
1534 #define setStringRef(h,f,t,l) r_setStringRef(__LINE__,h,f,t,l)
1535 static void r_setStringRef(unsigned line, IHlink *hlink, DWORD flags, const WCHAR *tgt, const WCHAR *loc)
1536 {
1537     HRESULT hres;
1538     hres = IHlink_SetStringReference(hlink, flags, tgt, loc);
1539     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1540 }
1541
1542 #define getStringRef(h,t,l) r_getStringRef(__LINE__,h,t,l)
1543 static void r_getStringRef(unsigned line, IHlink *hlink, const WCHAR *exp_tgt, const WCHAR *exp_loc)
1544 {
1545     HRESULT hres;
1546     WCHAR *fnd_tgt, *fnd_loc;
1547
1548     hres = IHlink_GetStringReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1549     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1550
1551     if(exp_tgt)
1552         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));
1553     else
1554         ok_(__FILE__,line) (fnd_tgt == NULL, "Found string target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1555
1556     if(exp_loc)
1557         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));
1558     else
1559         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1560
1561     CoTaskMemFree(fnd_tgt);
1562     CoTaskMemFree(fnd_loc);
1563 }
1564
1565 #define setMonikerRef(h,f,t,l) r_setMonikerRef(__LINE__,h,f,t,l)
1566 static void r_setMonikerRef(unsigned line, IHlink *hlink, DWORD flags, IMoniker *tgt, const WCHAR *loc)
1567 {
1568     HRESULT hres;
1569     hres = IHlink_SetMonikerReference(hlink, flags, tgt, loc);
1570     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1571 }
1572
1573 /* passing 0xFFFFFFFF as exp_tgt will return the retrieved target & not test it */
1574 #define getMonikerRef(h,t,l,r) r_getMonikerRef(__LINE__,h,t,l,r)
1575 static IMoniker *r_getMonikerRef(unsigned line, IHlink *hlink, IMoniker *exp_tgt, const WCHAR *exp_loc, DWORD ref)
1576 {
1577     HRESULT hres;
1578     IMoniker *fnd_tgt;
1579     WCHAR *fnd_loc;
1580
1581     hres = IHlink_GetMonikerReference(hlink, ref, &fnd_tgt, &fnd_loc);
1582     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1583
1584     if(exp_loc)
1585         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));
1586     else
1587         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1588
1589     CoTaskMemFree(fnd_loc);
1590
1591     if(exp_tgt == (IMoniker*)0xFFFFFFFF)
1592         return fnd_tgt;
1593
1594     ok_(__FILE__,line) (fnd_tgt == exp_tgt, "Found moniker target should have been %p, was: %p\n", exp_tgt, fnd_tgt);
1595
1596     if(fnd_tgt)
1597         IMoniker_Release(fnd_tgt);
1598
1599     return NULL;
1600 }
1601
1602 static void test_HlinkMoniker(void)
1603 {
1604     IHlink *hlink;
1605     IMoniker *aMon, *file_mon;
1606     static const WCHAR emptyW[] = {0};
1607     static const WCHAR wordsW[] = {'w','o','r','d','s',0};
1608     static const WCHAR aW[] = {'a',0};
1609     static const WCHAR bW[] = {'b',0};
1610     HRESULT hres;
1611
1612     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1613     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1614     getStringRef(hlink, NULL, NULL);
1615     getMonikerRef(hlink, NULL, NULL, HLINKGETREF_RELATIVE);
1616
1617     /* setting a string target creates a moniker reference */
1618     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, aW, wordsW);
1619     getStringRef(hlink, aW, wordsW);
1620     aMon = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, wordsW, HLINKGETREF_RELATIVE);
1621     ok(aMon != NULL, "Moniker from %s target should not be NULL\n", wine_dbgstr_w(aW));
1622     if(aMon)
1623         IMoniker_Release(aMon);
1624
1625     /* setting target & location to the empty string deletes the moniker
1626      * reference */
1627     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, emptyW, emptyW);
1628     getStringRef(hlink, NULL, NULL);
1629     getMonikerRef(hlink, NULL, NULL, HLINKGETREF_RELATIVE);
1630
1631     /* setting a moniker target also sets the target string to that moniker's
1632      * display name */
1633     hres = CreateFileMoniker(bW, &file_mon);
1634     ok(hres == S_OK, "CreateFileMoniker failed: 0x%08x\n", hres);
1635
1636     setMonikerRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, file_mon, wordsW);
1637     getStringRef(hlink, bW, wordsW);
1638     getMonikerRef(hlink, file_mon, wordsW, HLINKGETREF_RELATIVE);
1639
1640     IMoniker_Release(file_mon);
1641
1642     IHlink_Release(hlink);
1643 }
1644
1645 static void test_HashLink(void)
1646 {
1647     IHlink *hlink;
1648     IMoniker *pmk;
1649     const WCHAR hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r',0};
1650     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};
1651     const WCHAR hash_no_tgtW[] = {'#','a','n','a','n','c','h','o','r',0};
1652     const WCHAR tgt_partW[] = {'a','f','i','l','e',0};
1653     const WCHAR loc_partW[] = {'a','n','a','n','c','h','o','r',0};
1654     const WCHAR two_hash_loc_partW[] = {'a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1655     const WCHAR test_locW[] = {'t','e','s','t','l','o','c',0};
1656     HRESULT hres;
1657
1658     /* simple single hash test */
1659     hres = HlinkCreateFromString(hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1660     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1661     ok(hlink != NULL, "Didn't get an hlink\n");
1662
1663     if(hlink){
1664         getStringRef(hlink, tgt_partW, loc_partW);
1665         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW, HLINKGETREF_RELATIVE);
1666         ok(pmk != NULL, "Found moniker should not be NULL\n");
1667         if(pmk)
1668             IMoniker_Release(pmk);
1669
1670         setStringRef(hlink, HLINKSETF_TARGET, hash_targetW, NULL);
1671         getStringRef(hlink, hash_targetW, loc_partW);
1672
1673         IHlink_Release(hlink);
1674     }
1675
1676     /* two hashes in the target */
1677     hres = HlinkCreateFromString(two_hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1678     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1679     ok(hlink != NULL, "Didn't get an hlink\n");
1680
1681     if(hlink){
1682         getStringRef(hlink, tgt_partW, two_hash_loc_partW);
1683         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, two_hash_loc_partW, HLINKGETREF_RELATIVE);
1684         ok(pmk != NULL, "Found moniker should not be NULL\n");
1685         if(pmk)
1686             IMoniker_Release(pmk);
1687
1688         IHlink_Release(hlink);
1689     }
1690
1691     /* target with hash plus a location string */
1692     hres = HlinkCreateFromString(hash_targetW, test_locW, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1693     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1694     ok(hlink != NULL, "Didn't get an hlink\n");
1695
1696     if(hlink){
1697         getStringRef(hlink, tgt_partW, test_locW);
1698         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, test_locW, HLINKGETREF_RELATIVE);
1699         ok(pmk != NULL, "Found moniker should not be NULL\n");
1700         if(pmk)
1701             IMoniker_Release(pmk);
1702
1703         IHlink_Release(hlink);
1704     }
1705
1706     /* target with hash containing no "target part" */
1707     hres = HlinkCreateFromString(hash_no_tgtW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1708     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1709     ok(hlink != NULL, "Didn't get an hlink\n");
1710
1711     if(hlink){
1712         getStringRef(hlink, NULL, loc_partW);
1713         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW, HLINKGETREF_RELATIVE);
1714         ok(pmk == NULL, "Found moniker should be NULL\n");
1715         if(pmk)
1716             IMoniker_Release(pmk);
1717
1718         IHlink_Release(hlink);
1719     }
1720 }
1721
1722 static WCHAR site_monikerW[] = {'S','I','T','E','_','M','O','N','I','K','E','R',0};
1723 static WCHAR ref_monikerW[] = {'R','E','F','_','M','O','N','I','K','E','R',0};
1724
1725 static HRESULT WINAPI hls_test_Moniker_BindToStorage(IMoniker *iface,
1726         IBindCtx *pbc, IMoniker *toLeft, REFIID riid, void **obj)
1727 {
1728     ok(0, "BTS: %p %p %p %p %p\n", iface, pbc, toLeft, riid, obj);
1729     return E_NOTIMPL;
1730 }
1731
1732 static HRESULT WINAPI hls_site_Moniker_ComposeWith(IMoniker *iface,
1733         IMoniker *right, BOOL onlyIfNotGeneric, IMoniker **composite)
1734 {
1735     LPOLESTR rightName;
1736     HRESULT hres;
1737
1738     ok(onlyIfNotGeneric == 0, "Expected onlyIfNotGeneric to be FALSE\n");
1739
1740     CHECK_EXPECT(ComposeWith);
1741
1742     hres = IMoniker_GetDisplayName(right, NULL, NULL, &rightName);
1743     ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres);
1744     ok(!lstrcmpW(rightName, ref_monikerW),
1745             "Expected to get moniker set via SetMonikerReference, instead got: %s\n",
1746             wine_dbgstr_w(rightName));
1747     CoTaskMemFree(rightName);
1748
1749     *composite = NULL;
1750
1751     /* unlikely error code to verify this return result is used */
1752     return E_OUTOFMEMORY;
1753 }
1754
1755 static HRESULT WINAPI hls_site_Moniker_GetDisplayName(IMoniker *iface,
1756         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1757 {
1758     *displayName = CoTaskMemAlloc(sizeof(site_monikerW));
1759     memcpy(*displayName, site_monikerW, sizeof(site_monikerW));
1760     return S_OK;
1761 }
1762
1763 static HRESULT WINAPI hls_ref_Moniker_GetDisplayName(IMoniker *iface,
1764         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1765 {
1766     *displayName = CoTaskMemAlloc(sizeof(ref_monikerW));
1767     memcpy(*displayName, ref_monikerW, sizeof(ref_monikerW));
1768     return S_OK;
1769 }
1770
1771 static HRESULT WINAPI hls_test_Moniker_IsSystemMoniker(IMoniker *iface,
1772         DWORD *mksys)
1773 {
1774     return S_FALSE;
1775 }
1776
1777 static IMonikerVtbl hls_site_MonikerVtbl = {
1778     Moniker_QueryInterface,
1779     Moniker_AddRef,
1780     Moniker_Release,
1781     Moniker_GetClassID,
1782     Moniker_IsDirty,
1783     Moniker_Load,
1784     Moniker_Save,
1785     Moniker_GetSizeMax,
1786     Moniker_BindToObject,
1787     hls_test_Moniker_BindToStorage,
1788     Moniker_Reduce,
1789     hls_site_Moniker_ComposeWith,
1790     Moniker_Enum,
1791     Moniker_IsEqual,
1792     Moniker_Hash,
1793     Moniker_IsRunning,
1794     Moniker_GetTimeOfLastChange,
1795     Moniker_Inverse,
1796     Moniker_CommonPrefixWith,
1797     Moniker_RelativePathTo,
1798     hls_site_Moniker_GetDisplayName,
1799     Moniker_ParseDisplayName,
1800     hls_test_Moniker_IsSystemMoniker
1801 };
1802
1803 static IMonikerVtbl hls_ref_MonikerVtbl = {
1804     Moniker_QueryInterface,
1805     Moniker_AddRef,
1806     Moniker_Release,
1807     Moniker_GetClassID,
1808     Moniker_IsDirty,
1809     Moniker_Load,
1810     Moniker_Save,
1811     Moniker_GetSizeMax,
1812     Moniker_BindToObject,
1813     hls_test_Moniker_BindToStorage,
1814     Moniker_Reduce,
1815     Moniker_ComposeWith,
1816     Moniker_Enum,
1817     Moniker_IsEqual,
1818     Moniker_Hash,
1819     Moniker_IsRunning,
1820     Moniker_GetTimeOfLastChange,
1821     Moniker_Inverse,
1822     Moniker_CommonPrefixWith,
1823     Moniker_RelativePathTo,
1824     hls_ref_Moniker_GetDisplayName,
1825     Moniker_ParseDisplayName,
1826     hls_test_Moniker_IsSystemMoniker
1827 };
1828
1829 static IMoniker hls_site_Moniker = { &hls_site_MonikerVtbl };
1830 static IMoniker hls_ref_Moniker = { &hls_ref_MonikerVtbl };
1831
1832 static HRESULT WINAPI hls_QueryInterface(IHlinkSite *iface, REFGUID iid,
1833         void **obj)
1834 {
1835     ok(0, "QI: %p %s %p\n", iface, debugstr_guid(iid), obj);
1836     return E_NOTIMPL;
1837 }
1838
1839 static ULONG WINAPI hls_AddRef(IHlinkSite *iface)
1840 {
1841     return 2;
1842 }
1843
1844 static ULONG WINAPI hls_Release(IHlinkSite *iface)
1845 {
1846     return 1;
1847 }
1848
1849 static HRESULT WINAPI hls_QueryService(IHlinkSite *iface, DWORD siteData,
1850         REFGUID service, REFIID riid, IUnknown **punk)
1851 {
1852     ok(0, "QS: %p %x %s %s %p\n", iface, siteData, debugstr_guid(service),
1853             debugstr_guid(riid), punk);
1854     return E_NOTIMPL;
1855 }
1856
1857 #define SITEDATA_SUCCESS 1
1858 #define SITEDATA_NOTIMPL 2
1859
1860 static HRESULT WINAPI hls_GetMoniker(IHlinkSite *iface, DWORD siteData,
1861         DWORD assign, DWORD which, IMoniker **pmk)
1862 {
1863     ok(siteData == SITEDATA_NOTIMPL ||
1864             siteData == SITEDATA_SUCCESS, "Unexpected site data: %u\n", siteData);
1865
1866     if(siteData == SITEDATA_SUCCESS){
1867         *pmk = &hls_site_Moniker;
1868         return S_OK;
1869     }
1870
1871     return E_NOTIMPL;
1872 }
1873
1874 static HRESULT WINAPI hls_ReadyToNavigate(IHlinkSite *iface, DWORD siteData,
1875         DWORD reserved)
1876 {
1877     ok(0, "RTN: %p %x %x\n", iface, siteData, reserved);
1878     return E_NOTIMPL;
1879 }
1880
1881 static HRESULT WINAPI hls_OnNavigationComplete(IHlinkSite *iface,
1882         DWORD siteData, DWORD reserved, HRESULT error, LPCWSTR errorStr)
1883 {
1884     CHECK_EXPECT(OnNavigationComplete);
1885     ok(siteData == SITEDATA_SUCCESS, "Unexpected site data: %u\n", siteData);
1886     ok(error == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", error);
1887     return E_NOTIMPL;
1888 }
1889
1890 static IHlinkSiteVtbl HlinkSiteVtbl = {
1891     hls_QueryInterface,
1892     hls_AddRef,
1893     hls_Release,
1894     hls_QueryService,
1895     hls_GetMoniker,
1896     hls_ReadyToNavigate,
1897     hls_OnNavigationComplete
1898 };
1899
1900 static IHlinkSite HlinkSite = { &HlinkSiteVtbl };
1901
1902 static void test_HlinkSite(void)
1903 {
1904     IHlink *hl;
1905     IMoniker *mon_ref;
1906     IBindCtx *pbc;
1907     HRESULT hres;
1908
1909     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
1910             &IID_IHlink, (LPVOID*)&hl);
1911     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
1912     getMonikerRef(hl, NULL, NULL, HLINKGETREF_RELATIVE);
1913
1914     hres = IHlink_SetHlinkSite(hl, &HlinkSite, SITEDATA_SUCCESS);
1915     ok(hres == S_OK, "SetHlinkSite failed: %08x\n", hres);
1916     getMonikerRef(hl, NULL, NULL, HLINKGETREF_RELATIVE);
1917     getStringRef(hl, NULL, NULL);
1918
1919     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1920     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1921     ok(mon_ref == NULL, "Didn't get expected moniker, instead: %p\n", mon_ref);
1922
1923     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1924     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1925     ok(mon_ref == &hls_site_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1926
1927     SET_EXPECT(Reduce);
1928     SET_EXPECT(Enum);
1929     hres = IHlink_SetMonikerReference(hl, HLINKSETF_TARGET, &hls_ref_Moniker, NULL);
1930     ok(hres == S_OK, "SetMonikerReference failed: %08x\n", hres);
1931     todo_wine CHECK_CALLED(Reduce);
1932     todo_wine CHECK_CALLED(Enum);
1933
1934     getMonikerRef(hl, &hls_ref_Moniker, NULL, HLINKGETREF_RELATIVE);
1935
1936     SET_EXPECT(Enum);
1937     getStringRef(hl, ref_monikerW, NULL);
1938     todo_wine CHECK_CALLED(Enum);
1939
1940     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1941     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1942     ok(mon_ref == &hls_ref_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1943     IMoniker_Release(mon_ref);
1944
1945     SET_EXPECT(ComposeWith);
1946     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1947     ok(hres == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", hres);
1948     ok(mon_ref == NULL, "Shouldn't have got a Moniker, got: %p\n", mon_ref);
1949     CHECK_CALLED(ComposeWith);
1950
1951     hres = CreateBindCtx(0, &pbc);
1952     ok(hres == S_OK, "CreateBindCtx failed: %08x\n", hres);
1953
1954     SET_EXPECT(ComposeWith);
1955     SET_EXPECT(OnNavigationComplete);
1956     hres = IHlink_Navigate(hl, 0, pbc, NULL, NULL);
1957     ok(hres == E_OUTOFMEMORY, "Navigate should've failed: %08x\n", hres);
1958     CHECK_CALLED(ComposeWith);
1959     CHECK_CALLED(OnNavigationComplete);
1960
1961     IBindCtx_Release(pbc);
1962     IHlink_Release(hl);
1963
1964     SET_EXPECT(Reduce);
1965     SET_EXPECT(Enum);
1966     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, NULL, NULL, &HlinkSite, SITEDATA_SUCCESS,
1967             NULL, &IID_IHlink, (LPVOID*)&hl);
1968     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1969     todo_wine CHECK_CALLED(Reduce);
1970     todo_wine CHECK_CALLED(Enum);
1971     getMonikerRef(hl, &hls_ref_Moniker, NULL, HLINKGETREF_RELATIVE);
1972     IHlink_Release(hl);
1973
1974     hres = HlinkCreateFromMoniker(NULL, NULL, NULL, &HlinkSite, SITEDATA_SUCCESS,
1975             NULL, &IID_IHlink, (LPVOID*)&hl);
1976     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1977     getMonikerRef(hl, NULL, NULL, HLINKGETREF_RELATIVE);
1978     IHlink_Release(hl);
1979
1980     SET_EXPECT(Reduce);
1981     SET_EXPECT(Enum);
1982     SET_EXPECT(IsSystemMoniker);
1983     SET_EXPECT(GetDisplayName);
1984     hres = HlinkCreateFromMoniker(&Moniker, NULL, NULL, &HlinkSite, SITEDATA_NOTIMPL,
1985             NULL, &IID_IHlink, (LPVOID*)&hl);
1986     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1987     getMonikerRef(hl, &Moniker, NULL, HLINKGETREF_ABSOLUTE);
1988     IHlink_Release(hl);
1989     todo_wine CHECK_CALLED(Reduce);
1990     todo_wine CHECK_CALLED(Enum);
1991     CHECK_CALLED(IsSystemMoniker);
1992     CHECK_CALLED(GetDisplayName);
1993 }
1994
1995 static void test_HlinkClone(void)
1996 {
1997     HRESULT hres;
1998     IHlink *hl, *cloned = NULL;
1999     IMoniker *dummy, *fnd_mk;
2000     IHlinkSite *fnd_site;
2001     WCHAR *fnd_name;
2002     DWORD fnd_data;
2003     const WCHAR one[] = {'1',0};
2004     const WCHAR two[] = {'2',0};
2005     const WCHAR name[] = {'a',0};
2006
2007     hres = HlinkClone(NULL, NULL, NULL, 0, NULL);
2008     ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
2009
2010     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
2011             &IID_IHlink, (void**)&hl);
2012     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
2013
2014     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, NULL);
2015     ok(hres == E_INVALIDARG, "Got wrong failure code: %08x\n", hres);
2016
2017     if (0)
2018     { 
2019         /* crash on Windows XP */
2020         HlinkClone(hl, NULL, NULL, 0, NULL);
2021
2022         HlinkClone(hl, NULL, NULL, 0, (void**)&cloned);
2023     }
2024
2025     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
2026     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
2027     ok(cloned != NULL, "Didn't get a clone\n");
2028     getMonikerRef(cloned, NULL, NULL, HLINKGETREF_RELATIVE);
2029     IHlink_Release(cloned);
2030
2031     IHlink_Release(hl);
2032
2033     SET_EXPECT(Reduce);
2034     SET_EXPECT(Enum);
2035     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, two, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hl);
2036     todo_wine CHECK_CALLED(Reduce);
2037     todo_wine CHECK_CALLED(Enum);
2038     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
2039     getMonikerRef(hl, &hls_ref_Moniker, two, HLINKGETREF_RELATIVE);
2040
2041     SET_EXPECT(Save);
2042     SET_EXPECT(GetClassID);
2043     cloned = (IHlink*)0xdeadbeef;
2044     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
2045     /* fails because of invalid CLSID given by Moniker_GetClassID */
2046     ok(hres == REGDB_E_CLASSNOTREG, "Wrong error code: %08x\n", hres);
2047     ok(cloned == NULL, "Shouldn't have gotten a clone\n");
2048     CHECK_CALLED(Save);
2049     CHECK_CALLED(GetClassID);
2050
2051     IHlink_Release(hl);
2052
2053     hres = CreateItemMoniker(one, one, &dummy);
2054     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
2055
2056     hres = HlinkCreateFromMoniker(dummy, two, name, &HlinkSite, SITEDATA_SUCCESS, NULL, &IID_IHlink, (void**)&hl);
2057     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
2058     getMonikerRef(hl, dummy, two, HLINKGETREF_RELATIVE);
2059
2060     cloned = NULL;
2061     hres = HlinkClone(hl, &IID_IHlink, NULL, 0, (void**)&cloned);
2062     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
2063     ok(cloned != NULL, "Should have gotten a clone\n");
2064
2065     fnd_mk = getMonikerRef(cloned, (IMoniker*)0xFFFFFFFF, two, HLINKGETREF_RELATIVE);
2066     ok(fnd_mk != NULL, "Expected non-null Moniker\n");
2067     ok(fnd_mk != dummy, "Expected a new Moniker to be created\n");
2068
2069     fnd_name = NULL;
2070     hres = IHlink_GetFriendlyName(cloned, HLFNAMEF_DEFAULT, &fnd_name);
2071     ok(hres == S_OK, "GetFriendlyName failed: %08x\n", hres);
2072     ok(fnd_name != NULL, "Expected friendly name to be non-NULL\n");
2073     ok(lstrcmpW(fnd_name, name) == 0, "Expected friendly name to be %s, was %s\n",
2074             wine_dbgstr_w(name), wine_dbgstr_w(fnd_name));
2075     CoTaskMemFree(fnd_name);
2076
2077     fnd_site = (IHlinkSite*)0xdeadbeef;
2078     fnd_data = 4;
2079     hres = IHlink_GetHlinkSite(cloned, &fnd_site, &fnd_data);
2080     ok(hres == S_OK, "GetHlinkSite failed: %08x\n", hres);
2081     ok(fnd_site == NULL, "Expected NULL site\n");
2082     ok(fnd_data == 4, "Expected site data to be 4, was: %d\n", fnd_data);
2083
2084     IHlink_Release(cloned);
2085     IHlink_Release(hl);
2086
2087     hres = HlinkCreateFromMoniker(dummy, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hl);
2088     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
2089     getMonikerRef(hl, dummy, NULL, HLINKGETREF_RELATIVE);
2090
2091     cloned = NULL;
2092     hres = HlinkClone(hl, &IID_IHlink, &HlinkSite, SITEDATA_SUCCESS, (void**)&cloned);
2093     ok(hres == S_OK, "HlinkClone failed: %08x\n", hres);
2094     ok(cloned != NULL, "Should have gotten a clone\n");
2095
2096     fnd_mk = getMonikerRef(cloned, (IMoniker*)0xFFFFFFFF, NULL, HLINKGETREF_RELATIVE);
2097     ok(fnd_mk != NULL, "Expected non-null Moniker\n");
2098     ok(fnd_mk != dummy, "Expected a new Moniker to be created\n");
2099
2100     fnd_site = (IHlinkSite*)0xdeadbeef;
2101     fnd_data = 4;
2102     hres = IHlink_GetHlinkSite(cloned, &fnd_site, &fnd_data);
2103     ok(hres == S_OK, "GetHlinkSite failed: %08x\n", hres);
2104     ok(fnd_site == &HlinkSite, "Expected found site to be HlinkSite, was: %p\n", fnd_site);
2105     ok(fnd_data == SITEDATA_SUCCESS, "Unexpected site data: %u\n", fnd_data);
2106
2107     IHlink_Release(cloned);
2108     IHlink_Release(hl);
2109
2110     IMoniker_Release(dummy);
2111 }
2112
2113 static void test_StdHlink(void)
2114 {
2115     IHlink *hlink;
2116     WCHAR *str;
2117     HRESULT hres;
2118
2119     static const WCHAR testW[] = {'t','e','s','t',0};
2120
2121     hres = CoCreateInstance(&CLSID_StdHlink, NULL, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
2122             &IID_IHlink, (void**)&hlink);
2123     ok(hres == S_OK, "CoCreateInstance failed: %08x\n", hres);
2124
2125     str = (void*)0xdeadbeef;
2126     hres = IHlink_GetTargetFrameName(hlink, &str);
2127     ok(hres == S_FALSE, "GetTargetFrameName failed: %08x\n", hres);
2128     ok(!str, "str = %s\n", wine_dbgstr_w(str));
2129
2130     hres = IHlink_SetTargetFrameName(hlink, testW);
2131     ok(hres == S_OK, "SetTargetFrameName failed: %08x\n", hres);
2132
2133     str = (void*)0xdeadbeef;
2134     hres = IHlink_GetTargetFrameName(hlink, &str);
2135     ok(hres == S_OK, "GetTargetFrameName failed: %08x\n", hres);
2136     ok(!lstrcmpW(str, testW), "str = %s\n", wine_dbgstr_w(str));
2137     CoTaskMemFree(str);
2138
2139     hres = IHlink_SetTargetFrameName(hlink, NULL);
2140     ok(hres == S_OK, "SetTargetFrameName failed: %08x\n", hres);
2141
2142     str = (void*)0xdeadbeef;
2143     hres = IHlink_GetTargetFrameName(hlink, &str);
2144     ok(hres == S_FALSE, "GetTargetFrameName failed: %08x\n", hres);
2145     ok(!str, "str = %s\n", wine_dbgstr_w(str));
2146
2147     IHlink_Release(hlink);
2148 }
2149
2150 static void test_Hlink_Navigate(void)
2151 {
2152     IHlink *hlink;
2153     IBindCtx *pbc;
2154     HRESULT hres;
2155
2156     hres = CreateBindCtx(0, &pbc);
2157     ok(hres == S_OK, "CreateBindCtx failed: %08x\n", hres);
2158     _bctx = pbc;
2159
2160     SET_EXPECT(Reduce);
2161     SET_EXPECT(Enum);
2162     SET_EXPECT(IsSystemMoniker);
2163     SET_EXPECT(GetDisplayName);
2164     hres = HlinkCreateFromMoniker(&Moniker, NULL, NULL, NULL,
2165             0, NULL, &IID_IHlink, (void**)&hlink);
2166     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
2167     todo_wine CHECK_CALLED(Reduce);
2168     todo_wine CHECK_CALLED(Enum);
2169     todo_wine CHECK_CALLED(IsSystemMoniker);
2170     CHECK_CALLED(GetDisplayName);
2171
2172     SET_EXPECT(IsSystemMoniker);
2173     SET_EXPECT(GetDisplayName);
2174     SET_EXPECT(HBC_GetObject);
2175     SET_EXPECT(Reduce);
2176     SET_EXPECT(BindToObject);
2177     SET_EXPECT(HT_GetBrowseContext);
2178     SET_EXPECT(HT_SetBrowseContext);
2179     SET_EXPECT(HBC_QueryInterface_IHlinkHistory);
2180     SET_EXPECT(HT_Navigate);
2181     SET_EXPECT(HT_GetFriendlyName);
2182     hres = IHlink_Navigate(hlink, 0, pbc, NULL, &HlinkBrowseContext);
2183     ok(hres == S_OK, "Navigate failed: %08x\n", hres);
2184     CHECK_CALLED(IsSystemMoniker);
2185     todo_wine CHECK_CALLED(GetDisplayName);
2186     todo_wine CHECK_CALLED(HBC_GetObject);
2187     todo_wine CHECK_CALLED(Reduce);
2188     CHECK_CALLED(BindToObject);
2189     todo_wine CHECK_CALLED(HT_GetBrowseContext);
2190     CHECK_CALLED(HT_SetBrowseContext);
2191     todo_wine CHECK_CALLED(HBC_QueryInterface_IHlinkHistory);
2192     CHECK_CALLED(HT_Navigate);
2193     todo_wine CHECK_CALLED(HT_GetFriendlyName);
2194
2195     IHlink_Release(hlink);
2196     IBindCtx_Release(pbc);
2197     _bctx = NULL;
2198 }
2199
2200 static HRESULT WINAPI hlinkframe_QueryInterface(IHlinkFrame *iface, REFIID riid, void **obj)
2201 {
2202     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IHlinkFrame))
2203     {
2204         *obj = iface;
2205         return S_OK;
2206     }
2207
2208     *obj = NULL;
2209     return E_NOINTERFACE;
2210 }
2211
2212 static ULONG WINAPI hlinkframe_AddRef(IHlinkFrame *iface)
2213 {
2214     return 2;
2215 }
2216
2217 static ULONG WINAPI hlinkframe_Release(IHlinkFrame *iface)
2218 {
2219     return 1;
2220 }
2221
2222 static HRESULT WINAPI hlinkframe_SetBrowseContext(IHlinkFrame *iface, IHlinkBrowseContext *bc)
2223 {
2224     ok(0, "unexpected %p\n", bc);
2225     return E_NOTIMPL;
2226 }
2227
2228 static HRESULT WINAPI hlinkframe_GetBrowseContext(IHlinkFrame *iface, IHlinkBrowseContext **bc)
2229 {
2230     *bc = NULL;
2231     ok(0, "unexpected %p\n", bc);
2232     return E_NOTIMPL;
2233 }
2234
2235 static HRESULT WINAPI hlinkframe_Navigate(IHlinkFrame *iface, DWORD grfHLNF, LPBC pbc, IBindStatusCallback *bsc, IHlink *navigate)
2236 {
2237     ok(0, "unexpected\n");
2238     return E_NOTIMPL;
2239 }
2240
2241 static HRESULT WINAPI hlinkframe_OnNavigate(IHlinkFrame *iface, DWORD grfHLNF, IMoniker *target, LPCWSTR location, LPCWSTR friendly_name,
2242     DWORD reserved)
2243 {
2244     ok(0, "unexpected\n");
2245     return E_NOTIMPL;
2246 }
2247
2248 static HRESULT WINAPI hlinkframe_UpdateHlink(IHlinkFrame *iface, ULONG uHLID, IMoniker *target, LPCWSTR location, LPCWSTR friendly_name)
2249 {
2250     CHECK_EXPECT(HLF_UpdateHlink);
2251     return S_OK;
2252 }
2253
2254 static IHlinkFrameVtbl hlinkframevtbl = {
2255     hlinkframe_QueryInterface,
2256     hlinkframe_AddRef,
2257     hlinkframe_Release,
2258     hlinkframe_SetBrowseContext,
2259     hlinkframe_GetBrowseContext,
2260     hlinkframe_Navigate,
2261     hlinkframe_OnNavigate,
2262     hlinkframe_UpdateHlink
2263 };
2264
2265 static IHlinkFrame testframe = { &hlinkframevtbl };
2266
2267 static void test_HlinkUpdateStackItem(void)
2268 {
2269     static const WCHAR location[] = {'l','o','c','a','t','i','o','n',0};
2270     HRESULT hr;
2271
2272     hr = HlinkUpdateStackItem(NULL, NULL, HLID_CURRENT, &Moniker, location, NULL);
2273     ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2274
2275     SET_EXPECT(HBC_UpdateHlink);
2276     hr = HlinkUpdateStackItem(NULL, &HlinkBrowseContext, HLID_CURRENT, &Moniker, location, NULL);
2277     ok(hr == S_OK, "got 0x%08x\n", hr);
2278     CHECK_CALLED(HBC_UpdateHlink);
2279
2280     SET_EXPECT(HLF_UpdateHlink);
2281     hr = HlinkUpdateStackItem(&testframe, &HlinkBrowseContext, HLID_CURRENT, &Moniker, location, NULL);
2282     ok(hr == S_OK, "got 0x%08x\n", hr);
2283     CHECK_CALLED(HLF_UpdateHlink);
2284 }
2285
2286 START_TEST(hlink)
2287 {
2288     CoInitialize(NULL);
2289
2290     test_HlinkIsShortcut();
2291     test_reference();
2292     test_persist();
2293     test_special_reference();
2294     test_HlinkCreateExtensionServices();
2295     test_HlinkParseDisplayName();
2296     test_HlinkResolveMonikerForData();
2297     test_HlinkGetSetMonikerReference();
2298     test_HlinkGetSetStringReference();
2299     test_HlinkMoniker();
2300     test_HashLink();
2301     test_HlinkSite();
2302     test_HlinkClone();
2303     test_StdHlink();
2304     test_Hlink_Navigate();
2305     test_HlinkUpdateStackItem();
2306
2307     CoUninitialize();
2308 }