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