msvcrt: Export the 64-bit version of the C++ mangled names for all implemented functions.
[wine] / dlls / hlink / tests / hlink.c
1 /*
2  * Implementation of hyperlinking (hlink.dll)
3  *
4  * Copyright 2006 Mike McCormack
5  * Copyright 2007-2008 Jacek Caban for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #define COBJMACROS
23
24 #include <stdio.h>
25
26 #include <initguid.h>
27 #include <hlink.h>
28 #include <hlguids.h>
29
30 #include "wine/test.h"
31
32 #define DEFINE_EXPECT(func) \
33     static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
34
35 #define SET_EXPECT(func) \
36     expect_ ## func = TRUE
37
38 #define CHECK_EXPECT2(func) \
39     do { \
40         ok(expect_ ##func, "unexpected call " #func "\n"); \
41         called_ ## func = TRUE; \
42     }while(0)
43
44 #define CHECK_EXPECT(func) \
45     do { \
46         CHECK_EXPECT2(func); \
47         expect_ ## func = FALSE; \
48     }while(0)
49
50 #define CHECK_CALLED(func) \
51     do { \
52         ok(called_ ## func, "expected " #func "\n"); \
53         expect_ ## func = called_ ## func = FALSE; \
54     }while(0)
55
56 DEFINE_EXPECT(IsSystemMoniker);
57 DEFINE_EXPECT(BindToStorage);
58 DEFINE_EXPECT(GetDisplayName);
59
60 DEFINE_EXPECT(ComposeWith);
61 DEFINE_EXPECT(OnNavigationComplete);
62 DEFINE_EXPECT(Enum);
63 DEFINE_EXPECT(Reduce);
64
65 static const char *debugstr_guid(REFIID riid)
66 {
67     static char buf[50];
68
69     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
70             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
71             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
72             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
73
74     return buf;
75 }
76
77 static void test_HlinkIsShortcut(void)
78 {
79     UINT i;
80     HRESULT hres;
81
82     static const WCHAR file0[] = {'f','i','l','e',0};
83     static const WCHAR file1[] = {'f','i','l','e','.','u','r','l',0};
84     static const WCHAR file2[] = {'f','i','l','e','.','l','n','k',0};
85     static const WCHAR file3[] = {'f','i','l','e','.','u','R','l',0};
86     static const WCHAR file4[] = {'f','i','l','e','u','r','l',0};
87     static const WCHAR file5[] = {'c',':','\\','f','i','l','e','.','u','r','l',0};
88     static const WCHAR file6[] = {'c',':','\\','f','i','l','e','.','l','n','k',0};
89     static const WCHAR file7[] = {'.','u','r','l',0};
90
91     static struct {
92         LPCWSTR file;
93         HRESULT hres;
94     } shortcut_test[] = {
95         {file0, S_FALSE},
96         {file1, S_OK},
97         {file2, S_FALSE},
98         {file3, S_OK},
99         {file4, S_FALSE},
100         {file5, S_OK},
101         {file6, S_FALSE},
102         {file7, S_OK},
103         {NULL,  E_INVALIDARG}
104     };
105
106     for(i=0; i<sizeof(shortcut_test)/sizeof(shortcut_test[0]); i++) {
107         hres = HlinkIsShortcut(shortcut_test[i].file);
108         ok(hres == shortcut_test[i].hres, "[%d] HlinkIsShortcut returned %08x, expected %08x\n",
109            i, hres, shortcut_test[i].hres);
110     }
111 }
112
113 static void test_reference(void)
114 {
115     HRESULT r;
116     IHlink *lnk = NULL;
117     IMoniker *mk = NULL;
118     const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
119     const WCHAR url2[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g','/',0 };
120     LPWSTR str = NULL;
121
122     r = HlinkCreateFromString(url, NULL, NULL, NULL,
123                               0, NULL, &IID_IHlink, (LPVOID*) &lnk);
124     ok(r == S_OK, "failed to create link\n");
125     if (FAILED(r))
126         return;
127
128     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
129     ok(r == S_OK, "failed\n");
130
131     r = IHlink_GetMonikerReference(lnk, HLINKGETREF_DEFAULT, &mk, &str);
132     ok(r == S_OK, "failed\n");
133     ok(mk != NULL, "no moniker\n");
134     ok(str == NULL, "string should be null\n");
135
136     r = IMoniker_Release(mk);
137     ok( r == 1, "moniker refcount wrong\n");
138
139     r = IHlink_GetStringReference(lnk, -1, &str, NULL);
140     ok(r == S_OK, "failed\n");
141     CoTaskMemFree(str);
142
143     r = IHlink_GetStringReference(lnk, -1, NULL, NULL);
144     ok(r == S_OK, "failed, r=%08x\n", r);
145
146     r = IHlink_GetStringReference(lnk, -1, NULL, &str);
147     ok(r == S_OK, "failed, r=%08x\n", r);
148     ok(str == NULL, "string should be null\n");
149
150     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, &str, NULL);
151     ok(r == S_OK, "failed\n");
152     ok(!lstrcmpW(str, url2), "url wrong\n");
153     CoTaskMemFree(str);
154
155     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
156     ok(r == S_OK, "failed\n");
157
158     r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, &str);
159     ok(r == S_OK, "failed\n");
160     ok(str == NULL, "string should be null\n");
161
162     /* Unimplented functions checks */
163     r = IHlink_GetAdditionalParams(lnk, NULL);
164     ok(r == E_NOTIMPL, "failed\n");
165
166     r = IHlink_SetAdditionalParams(lnk, NULL);
167     ok(r == E_NOTIMPL, "failed\n");
168
169     IHlink_Release(lnk);
170 }
171
172 /* url only */
173 static const unsigned char expected_hlink_data[] =
174 {
175     0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
176     0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
177     0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
178     0x26,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
179     0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
180     0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
181     0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
182     0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
183     0x00,0x00,
184 };
185
186 /* url only (IE7) */
187 static const unsigned char expected_hlink_data_ie7[] =
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     0x3e,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,0x79,0x58,0x81,0xf4,0x3b,0x1d,
198     0x7f,0x48,0xaf,0x2c,0x82,0x5d,0xc4,0x85,
199     0x27,0x63,0x00,0x00,0x00,0x00,0xa5,0xab,
200     0x00,0x00,
201 };
202
203 /* url + friendly name */
204 static const unsigned char expected_hlink_data2[] =
205 {
206     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
207     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
208     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
209     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
210     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
211     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
212     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
213     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
214     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
215     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
216     0x67,0x00,0x2f,0x00,0x00,0x00,
217 };
218
219 /* url + friendly name (IE7) */
220 static const unsigned char expected_hlink_data2_ie7[] =
221 {
222     0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
223     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
224     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
225     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
226     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
227     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
228     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
229     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
230     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
231     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
232     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
233     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
234     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
235     0x00,0x00,0xa5,0xab,0x00,0x00,
236 };
237
238 /* url + friendly name + location */
239 static const unsigned char expected_hlink_data3[] =
240 {
241     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
242     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
243     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
244     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
245     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
246     0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
247     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
248     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
249     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
250     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
251     0x67,0x00,0x2f,0x00,0x00,0x00,0x07,0x00,
252     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
253     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
254 };
255
256 /* url + friendly name + location (IE7) */
257 static const unsigned char expected_hlink_data3_ie7[] =
258 {
259     0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
260     0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
261     0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
262     0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
263     0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
264     0x00,0x4b,0xa9,0x0b,0x3e,0x00,0x00,0x00,
265     0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
266     0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
267     0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
268     0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
269     0x67,0x00,0x2f,0x00,0x00,0x00,0x79,0x58,
270     0x81,0xf4,0x3b,0x1d,0x7f,0x48,0xaf,0x2c,
271     0x82,0x5d,0xc4,0x85,0x27,0x63,0x00,0x00,
272     0x00,0x00,0xa5,0xab,0x00,0x00,0x07,0x00,
273     0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
274     0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
275 };
276
277 /* relative url */
278 static const unsigned char expected_hlink_data4[] =
279 {
280     0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
281     0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
282     0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
283     0x00,0x00,0x0b,0x00,0x00,0x00,0x69,0x6e,
284     0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,
285     0x00,0xff,0xff,0xad,0xde,0x00,0x00,0x00,
286     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
287     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
288     0x00,0x00,0x00,0x00,0x00,
289 };
290
291 /* url + target frame name */
292 static const unsigned char expected_hlink_data5[] =
293 {
294     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
295     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
296     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
297     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
298     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
299     0xa9,0x0b,0x26,0x00,0x00,0x00,0x68,0x00,
300     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
301     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
302     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
303     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
304     0x2f,0x00,0x00,0x00,
305 };
306
307 /* url + target frame name (IE7) */
308 static const unsigned char expected_hlink_data5_ie7[] =
309 {
310     0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
311     0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
312     0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
313     0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
314     0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
315     0xa9,0x0b,0x3e,0x00,0x00,0x00,0x68,0x00,
316     0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
317     0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
318     0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
319     0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
320     0x2f,0x00,0x00,0x00,0x79,0x58,0x81,0xf4,
321     0x3b,0x1d,0x7f,0x48,0xaf,0x2c,0x82,0x5d,
322     0xc4,0x85,0x27,0x63,0x00,0x00,0x00,0x00,
323     0xa5,0xab,0x00,0x00,
324 };
325
326 /* filename */
327 static const unsigned char expected_hlink_data6[] =
328 {
329      0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
330      0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
331      0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
332      0x00,0x00,0x04,0x00,0x00,0x00,0x63,0x3a,
333      0x5c,0x00,0xff,0xff,0xad,0xde,0x00,0x00,
334      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
335      0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
336      0x00,0x00,0x0c,0x00,0x00,0x00,0x06,0x00,
337      0x00,0x00,0x03,0x00,0x63,0x00,0x3a,0x00,
338      0x5c,0x00,
339 };
340
341 static void test_persist_save_data(const char *testname, IHlink *lnk,
342                                    const unsigned char *expected_data,
343                                    unsigned int expected_data_size,
344                                    const unsigned char *expected_data_alt,
345                                    unsigned int expected_data_alt_size)
346 {
347     HRESULT hr;
348     IStream *stream;
349     IPersistStream *ps;
350     HGLOBAL hglobal;
351     DWORD data_size;
352     const unsigned char *data;
353     DWORD i;
354     BOOL same;
355     unsigned int expected_data_win9x_size = 0;
356
357     hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
358     ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
359
360     hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
361     ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
362
363     hr = IPersistStream_Save(ps, stream, TRUE);
364     ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
365
366     hr = GetHGlobalFromStream(stream, &hglobal);
367     ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
368
369     data_size = GlobalSize(hglobal);
370
371     data = GlobalLock(hglobal);
372
373     if (expected_data_size % 4)
374         expected_data_win9x_size =  4 * ((expected_data_size / 4) + 1);
375
376     /* first check we have the right amount of data */
377     ok((data_size == expected_data_size) ||
378        (data_size == expected_data_alt_size) ||
379        broken(data_size == expected_data_win9x_size), /* Win9x and WinMe */
380        "%s: Size of saved data differs (expected %d or %d, actual %d)\n",
381        testname, expected_data_size, expected_data_alt_size, data_size);
382
383     same = TRUE;
384     /* then do a byte-by-byte comparison */
385     for (i = 0; i < min(data_size, expected_data_size); i++)
386     {
387         if ((expected_data[i] != data[i]) &&
388             (((expected_data != expected_hlink_data2) &&
389               (expected_data != expected_hlink_data3)) ||
390              ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
391         {
392             same = FALSE;
393             break;
394         }
395     }
396
397     if (!same && (expected_data_alt != expected_data))
398     {
399         /* then try the alternate data */
400         same = TRUE;
401         for (i = 0; i < min(data_size, expected_data_alt_size); i++)
402         {
403             if ((expected_data_alt[i] != data[i]) &&
404                 (((expected_data_alt != expected_hlink_data2) &&
405                   (expected_data_alt != expected_hlink_data3)) ||
406                  ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
407             {
408                 same = FALSE;
409                 break;
410             }
411         }
412     }
413
414     ok(same, "%s: Saved data differs\n", testname);
415     if (!same)
416     {
417         for (i = 0; i < data_size; i++)
418         {
419             if (i % 8 == 0) printf("    ");
420             printf("0x%02x,", data[i]);
421             if (i % 8 == 7) printf("\n");
422         }
423         printf("\n");
424     }
425
426     GlobalUnlock(hglobal);
427
428     IStream_Release(stream);
429     IPersistStream_Release(ps);
430 }
431
432 static void test_persist(void)
433 {
434     static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
435     static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
436     static const WCHAR filename[] = { 'c',':','\\',0 };
437     static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
438     static const WCHAR location[] = { '_','b','l','a','n','k',0 };
439     static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
440     HRESULT hr;
441     IHlink *lnk;
442
443     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
444                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
445     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
446     if (!lnk) {
447         skip("Can't create lnk, skipping test_persist.\n");
448         return;
449     }
450     test_persist_save_data("url only", lnk,
451         expected_hlink_data, sizeof(expected_hlink_data),
452         expected_hlink_data_ie7, sizeof(expected_hlink_data_ie7));
453     IHlink_Release(lnk);
454
455     hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
456                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
457     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
458     test_persist_save_data("url + friendly name", lnk,
459         expected_hlink_data2, sizeof(expected_hlink_data2),
460         expected_hlink_data2_ie7, sizeof(expected_hlink_data2_ie7));
461     IHlink_Release(lnk);
462
463     hr = HlinkCreateFromString(url, location, friendly_name, NULL,
464                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
465     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
466     test_persist_save_data("url + friendly_name + location", lnk,
467         expected_hlink_data3, sizeof(expected_hlink_data3),
468         expected_hlink_data3_ie7, sizeof(expected_hlink_data3_ie7));
469     IHlink_Release(lnk);
470
471     hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
472                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
473     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
474     test_persist_save_data("relative url", lnk,
475         expected_hlink_data4, sizeof(expected_hlink_data4),
476         expected_hlink_data4, sizeof(expected_hlink_data4));
477     IHlink_Release(lnk);
478
479     hr = HlinkCreateFromString(url, NULL, NULL, NULL,
480                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
481     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
482     hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
483     ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
484     test_persist_save_data("url + target frame name", lnk,
485         expected_hlink_data5, sizeof(expected_hlink_data5),
486         expected_hlink_data5_ie7, sizeof(expected_hlink_data5_ie7));
487     IHlink_Release(lnk);
488
489     hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
490                                0, NULL, &IID_IHlink, (LPVOID*) &lnk);
491     ok(hr == S_OK, "HlinkCreateFromString failed with error 0x%08x\n", hr);
492     test_persist_save_data("filename", lnk,
493         expected_hlink_data6, sizeof(expected_hlink_data6),
494         expected_hlink_data6, sizeof(expected_hlink_data6));
495     IHlink_Release(lnk);
496 }
497
498 static void test_special_reference(void)
499 {
500     LPWSTR ref;
501     HRESULT hres;
502
503     hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
504     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
505     ok(ref != NULL, "ref == NULL\n");
506     CoTaskMemFree(ref);
507
508     hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
509     ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
510     ok(ref != NULL, "ref == NULL\n");
511     CoTaskMemFree(ref);
512
513     ref = (void*)0xdeadbeef;
514     hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
515     ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
516     ok(ref == NULL, "ref=%p\n", ref);
517
518     ref = (void*)0xdeadbeef;
519     hres = HlinkGetSpecialReference(4, &ref);
520     ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
521     ok(ref == NULL, "ref=%p\n", ref);
522 }
523
524 static void test_HlinkCreateExtensionServices(void)
525 {
526     IAuthenticate *authenticate;
527     IHttpNegotiate *http_negotiate;
528     LPWSTR password, username, headers;
529     HWND hwnd;
530     HRESULT hres;
531
532     static const WCHAR usernameW[] = {'u','s','e','r',0};
533     static const WCHAR passwordW[] = {'p','a','s','s',0};
534     static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
535     static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
536
537     hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
538                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
539     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
540     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
541
542     password = username = (void*)0xdeadbeef;
543     hwnd = (void*)0xdeadbeef;
544     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
545     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
546     ok(!hwnd, "hwnd != NULL\n");
547     ok(!username, "username != NULL\n");
548     ok(!password, "password != NULL\n");
549
550     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
551     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
552
553     headers = (void*)0xdeadbeef;
554     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
555                                                0, &headers);
556     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
557     ok(headers == NULL, "headers != NULL\n");
558
559     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
560                                                0, NULL);
561     ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
562
563     headers = (void*)0xdeadbeef;
564     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
565     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
566     ok(headers == NULL, "headers != NULL\n");
567
568     IHttpNegotiate_Release(http_negotiate);
569     IAuthenticate_Release(authenticate);
570
571
572     hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
573                                         NULL, &IID_IAuthenticate, (void**)&authenticate);
574     ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
575     ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
576
577     password = username = NULL;
578     hwnd = NULL;
579     hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
580     ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
581     ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
582     ok(!lstrcmpW(username, usernameW), "unexpected username\n");
583     ok(!lstrcmpW(password, passwordW), "unexpected password\n");
584     CoTaskMemFree(username);
585     CoTaskMemFree(password);
586
587     password = username = (void*)0xdeadbeef;
588     hwnd = (void*)0xdeadbeef;
589     hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
590     ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
591     ok(password == (void*)0xdeadbeef, "password = %p\n", password);
592     ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
593
594     hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
595     ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
596
597     headers = (void*)0xdeadbeef;
598     hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
599                                                0, &headers);
600     ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
601     ok(!lstrcmpW(headers, headersexW), "unexpected headers %s\n", wine_dbgstr_w(headers));
602     CoTaskMemFree(headers);
603
604     headers = (void*)0xdeadbeef;
605     hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
606     ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
607     ok(headers == NULL, "unexpected headers %s\n", wine_dbgstr_w(headers));
608
609     IHttpNegotiate_Release(http_negotiate);
610     IAuthenticate_Release(authenticate);
611 }
612
613 static void test_HlinkParseDisplayName(void)
614 {
615     IMoniker *mon = NULL;
616     LPWSTR name;
617     DWORD issys;
618     ULONG eaten = 0;
619     IBindCtx *bctx;
620     HRESULT hres;
621
622     static const WCHAR winehq_urlW[] =
623             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
624              '/','s','i','t','e','/','a','b','o','u','t',0};
625     static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
626     static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':',
627             '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8',
628             '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0};
629
630     CreateBindCtx(0, &bctx);
631
632     hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon);
633     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
634     ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
635     ok(mon != NULL, "mon == NULL\n");
636
637     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
638     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
639     ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
640     CoTaskMemFree(name);
641
642     hres = IMoniker_IsSystemMoniker(mon, &issys);
643     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
644     ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys);
645
646     IMoniker_Release(mon);
647
648     hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon);
649     ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
650     ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
651     ok(mon != NULL, "mon == NULL\n");
652
653     hres = IMoniker_IsSystemMoniker(mon, &issys);
654     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
655     ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys);
656
657     IMoniker_Release(mon);
658
659     hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon);
660      ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
661     ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
662     ok(mon != NULL, "mon == NULL\n");
663
664     hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
665     ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
666     ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", wine_dbgstr_w(name));
667     CoTaskMemFree(name);
668
669     hres = IMoniker_IsSystemMoniker(mon, &issys);
670     ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
671     ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys);
672
673     IMoniker_Release(mon);
674     IBindCtx_Release(bctx);
675 }
676
677 static IBindCtx *_bctx;
678
679 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
680 {
681     ok(0, "unexpected call\n");
682     return E_NOINTERFACE;
683 }
684
685 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
686 {
687     return 2;
688 }
689
690 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
691 {
692     return 1;
693 }
694
695 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
696         REFGUID guidService, REFIID riid, void **ppv)
697 {
698     ok(0, "unexpected service %s\n", debugstr_guid(guidService));
699     return E_NOINTERFACE;
700 }
701
702 static IServiceProviderVtbl ServiceProviderVtbl = {
703     ServiceProvider_QueryInterface,
704     ServiceProvider_AddRef,
705     ServiceProvider_Release,
706     ServiceProvider_QueryService
707 };
708
709 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
710
711 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
712 {
713     *ppv = NULL;
714
715     if(IsEqualGUID(riid, &IID_IServiceProvider)) {
716         *ppv = &ServiceProvider;
717         return S_OK;
718     }
719
720     ok(0, "unexpected interface %s\n", debugstr_guid(riid));
721     return E_NOINTERFACE;
722 }
723
724 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
725 {
726     return 2;
727 }
728
729 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
730 {
731     return 1;
732 }
733
734 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
735         IBinding *pib)
736 {
737     ok(0, "unexpected call\n");
738     return E_NOTIMPL;
739 }
740
741 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
742 {
743     ok(0, "unexpected call\n");
744     return E_NOTIMPL;
745 }
746
747 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
748 {
749     ok(0, "unexpected call\n");
750     return E_NOTIMPL;
751 }
752
753 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
754         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
755 {
756     ok(0, "unexpected call\n");
757     return E_NOTIMPL;
758 }
759
760 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
761 {
762     ok(0, "unexpected call\n");
763     return E_NOTIMPL;
764 }
765
766 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
767 {
768     ok(0, "unexpected call\n");
769     return E_NOTIMPL;
770 }
771
772 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
773         DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
774 {
775     ok(0, "unexpected call\n");
776     return E_NOTIMPL;
777 }
778
779 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
780 {
781     ok(0, "unexpected call\n");
782     return E_NOTIMPL;
783 }
784
785 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
786     BindStatusCallback_QueryInterface,
787     BindStatusCallback_AddRef,
788     BindStatusCallback_Release,
789     BindStatusCallback_OnStartBinding,
790     BindStatusCallback_GetPriority,
791     BindStatusCallback_OnLowResource,
792     BindStatusCallback_OnProgress,
793     BindStatusCallback_OnStopBinding,
794     BindStatusCallback_GetBindInfo,
795     BindStatusCallback_OnDataAvailable,
796     BindStatusCallback_OnObjectAvailable
797 };
798
799 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
800
801 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
802 {
803     *ppv = NULL;
804
805     ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
806     return E_NOINTERFACE;
807 }
808
809 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
810 {
811     return 2;
812 }
813
814 static ULONG WINAPI Moniker_Release(IMoniker *iface)
815 {
816     return 1;
817 }
818
819 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
820 {
821     ok(0, "unexpected call\n");
822     return E_NOTIMPL;
823 }
824
825 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
826 {
827     ok(0, "unexpected call\n");
828     return E_NOTIMPL;
829 }
830
831 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
832 {
833     ok(0, "unexpected call\n");
834     return E_NOTIMPL;
835 }
836
837 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
838 {
839     ok(0, "unexpected call\n");
840     return E_NOTIMPL;
841 }
842
843 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
844 {
845     ok(0, "unexpected call\n");
846     return E_NOTIMPL;
847 }
848
849 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft,
850         REFIID riidResult, void **ppvResult)
851 {
852     ok(0, "unexpected call\n");
853     return E_NOTIMPL;
854 }
855
856 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
857         REFIID riid, void **ppv)
858 {
859     IUnknown *unk;
860     HRESULT hres;
861
862     static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
863
864     CHECK_EXPECT(BindToStorage);
865
866     ok(pbc == _bctx, "pbc != _bctx\n");
867     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
868     ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
869     ok(ppv != NULL, "ppv == NULL\n");
870     ok(*ppv == NULL, "*ppv=%p\n", *ppv);
871
872     hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
873     ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
874     ok(unk != NULL, "unk == NULL\n");
875
876     IUnknown_Release(unk);
877
878     return S_OK;
879 }
880
881 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
882         IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
883 {
884     CHECK_EXPECT(Reduce);
885     return E_NOTIMPL;
886 }
887
888 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
889         BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
890 {
891     ok(0, "unexpected call\n");
892     return E_NOTIMPL;
893 }
894
895 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
896 {
897     CHECK_EXPECT(Enum);
898     return E_NOTIMPL;
899 }
900
901 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
902 {
903     ok(0, "unexpected call\n");
904     return E_NOTIMPL;
905 }
906
907 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
908 {
909     ok(0, "unexpected call\n");
910     return E_NOTIMPL;
911 }
912
913 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
914         IMoniker *pmkNewlyRunning)
915 {
916     ok(0, "unexpected call\n");
917     return E_NOTIMPL;
918 }
919
920 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
921         IMoniker *pmkToLeft, FILETIME *pFileTime)
922 {
923     ok(0, "unexpected call\n");
924     return E_NOTIMPL;
925 }
926
927 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
928 {
929     ok(0, "unexpected call\n");
930     return E_NOTIMPL;
931 }
932
933 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
934         IMoniker **ppmkPrefix)
935 {
936     ok(0, "unexpected call\n");
937     return E_NOTIMPL;
938 }
939
940 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
941         IMoniker **pmkRelPath)
942 {
943     ok(0, "unexpected call\n");
944     return E_NOTIMPL;
945 }
946
947 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
948         IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
949 {
950     static const WCHAR winehq_urlW[] =
951             {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
952              '/','s','i','t','e','/','a','b','o','u','t',0};
953
954     CHECK_EXPECT(GetDisplayName);
955
956     ok(pbc != NULL, "pbc == NULL\n");
957     ok(pbc != _bctx, "pbc == _bctx\n");
958     ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
959
960     *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
961     memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
962     return S_OK;
963 }
964
965 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
966         IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
967 {
968     ok(0, "unexpected call\n");
969     return E_NOTIMPL;
970 }
971
972 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
973 {
974     CHECK_EXPECT2(IsSystemMoniker);
975
976     *pdwMksys = MKSYS_URLMONIKER;
977     return S_OK;
978 }
979
980 static IMonikerVtbl MonikerVtbl = {
981     Moniker_QueryInterface,
982     Moniker_AddRef,
983     Moniker_Release,
984     Moniker_GetClassID,
985     Moniker_IsDirty,
986     Moniker_Load,
987     Moniker_Save,
988     Moniker_GetSizeMax,
989     Moniker_BindToObject,
990     Moniker_BindToStorage,
991     Moniker_Reduce,
992     Moniker_ComposeWith,
993     Moniker_Enum,
994     Moniker_IsEqual,
995     Moniker_Hash,
996     Moniker_IsRunning,
997     Moniker_GetTimeOfLastChange,
998     Moniker_Inverse,
999     Moniker_CommonPrefixWith,
1000     Moniker_RelativePathTo,
1001     Moniker_GetDisplayName,
1002     Moniker_ParseDisplayName,
1003     Moniker_IsSystemMoniker
1004 };
1005
1006 static IMoniker Moniker = { &MonikerVtbl };
1007
1008 static void test_HlinkResolveMonikerForData(void)
1009 {
1010     IBindCtx *bctx;
1011     HRESULT hres;
1012
1013     CreateBindCtx(0, &bctx);
1014     _bctx = bctx;
1015
1016     SET_EXPECT(IsSystemMoniker);
1017     SET_EXPECT(GetDisplayName);
1018     SET_EXPECT(BindToStorage);
1019
1020     hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
1021     ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
1022
1023     CHECK_CALLED(IsSystemMoniker);
1024     CHECK_CALLED(GetDisplayName);
1025     CHECK_CALLED(BindToStorage);
1026
1027     IBindCtx_Release(bctx);
1028 }
1029
1030 static void test_HlinkGetSetMonikerReference(void)
1031 {
1032     IMoniker *found_trgt, *dummy, *dummy2;
1033     IHlink *hlink;
1034     HRESULT hres;
1035     const WCHAR one[] = {'1',0};
1036     const WCHAR two[] = {'2',0};
1037     const WCHAR name[] = {'a',0};
1038     WCHAR *found_loc;
1039
1040     /* create two dummy monikers to use as targets */
1041     hres = CreateItemMoniker(one, one, &dummy);
1042     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1043
1044     hres = CreateItemMoniker(two, two, &dummy2);
1045     ok(hres == S_OK, "CreateItemMoniker failed: 0x%08x\n", hres);
1046
1047     /* create a new hlink: target => dummy, location => one */
1048     hres = HlinkCreateFromMoniker(dummy, one, name, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1049     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1050
1051     /* validate the target and location */
1052     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1053     ok(hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1054     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1055     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1056     IMoniker_Release(found_trgt);
1057     CoTaskMemFree(found_loc);
1058
1059     /* set location => two */
1060     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_LOCATION, dummy2, two);
1061     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1062
1063     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1064     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1065     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1066     IMoniker_Release(found_trgt);
1067     CoTaskMemFree(found_loc);
1068
1069     /* set target => dummy2 */
1070     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET, dummy2, one);
1071     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1072
1073     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1074     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1075     ok(lstrcmpW(found_loc, two) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(found_loc));
1076     IMoniker_Release(found_trgt);
1077     CoTaskMemFree(found_loc);
1078
1079     /* set target => dummy, location => one */
1080     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, dummy, one);
1081     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1082
1083     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1084     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1085     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1086     IMoniker_Release(found_trgt);
1087     CoTaskMemFree(found_loc);
1088
1089     /* no HLINKSETF flags */
1090     hres = IHlink_SetMonikerReference(hlink, 0, dummy2, two);
1091     ok(hres == E_INVALIDARG, "IHlink_SetMonikerReference should've failed with E_INVALIDARG (0x%08x), failed with 0x%08x\n", E_INVALIDARG, hres);
1092
1093     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1094     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1095     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1096     IMoniker_Release(found_trgt);
1097     CoTaskMemFree(found_loc);
1098
1099     /* invalid HLINKSETF flags */
1100     hres = IHlink_SetMonikerReference(hlink, 12, dummy2, two);
1101     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1102     if (0) ok(hres == 12, "IHlink_SetMonikerReference should've failed with 0x%08x, failed with 0x%08x\n", 12, hres);
1103
1104     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1105     ok(found_trgt == dummy, "Found target should've been %p, was: %p\n", dummy, found_trgt);
1106     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1107     IMoniker_Release(found_trgt);
1108     CoTaskMemFree(found_loc);
1109
1110     /* valid & invalid HLINKSETF flags */
1111     hres = IHlink_SetMonikerReference(hlink, 12 | HLINKSETF_TARGET, dummy2, two);
1112     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1113
1114     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1115     ok(found_trgt == dummy2, "Found target should've been %p, was: %p\n", dummy2, found_trgt);
1116     ok(lstrcmpW(found_loc, one) == 0, "Found location should've been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(found_loc));
1117     IMoniker_Release(found_trgt);
1118     CoTaskMemFree(found_loc);
1119
1120     /* NULL args */
1121     hres = IHlink_SetMonikerReference(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, NULL, NULL);
1122     ok(hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1123
1124     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &found_trgt, &found_loc);
1125     ok(found_trgt == NULL, "Found target should've been %p, was: %p\n", NULL, found_trgt);
1126     ok(found_loc == NULL, "Found location should've been %s, was: %s\n", wine_dbgstr_w(NULL), wine_dbgstr_w(found_loc));
1127     if(found_trgt)
1128         IMoniker_Release(found_trgt);
1129
1130     IHlink_Release(hlink);
1131     IMoniker_Release(dummy2);
1132     IMoniker_Release(dummy);
1133 }
1134
1135 static void test_HlinkGetSetStringReference(void)
1136 {
1137     IHlink *link;
1138     static const WCHAR one[] = {'1',0};
1139     static const WCHAR two[] = {'2',0};
1140     static const WCHAR three[] = {'3',0};
1141     static const WCHAR empty[] = {0};
1142     WCHAR *fnd_tgt, *fnd_loc;
1143     HRESULT hres;
1144
1145     /* create a new hlink: target => NULL, location => one */
1146     hres = HlinkCreateFromMoniker(NULL, one, empty, NULL, 0, NULL, &IID_IHlink, (void**)&link);
1147     ok(hres == S_OK, "HlinkCreateFromMoniker failed: 0x%08x\n", hres);
1148
1149     /* test setting/getting location */
1150     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1151     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1152     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1153     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1154     CoTaskMemFree(fnd_tgt);
1155     CoTaskMemFree(fnd_loc);
1156
1157     hres = IHlink_SetStringReference(link, HLINKSETF_LOCATION, one, two);
1158     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1159
1160     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1161     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1162     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1163     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1164     CoTaskMemFree(fnd_tgt);
1165     CoTaskMemFree(fnd_loc);
1166
1167     hres = IHlink_SetStringReference(link, -HLINKSETF_LOCATION, two, one);
1168     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1169
1170     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1171     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1172     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1173     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1174     CoTaskMemFree(fnd_tgt);
1175     CoTaskMemFree(fnd_loc);
1176
1177     /* test setting/getting target */
1178     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET, two, three);
1179     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1180
1181     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1182     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1183     ok(!lstrcmpW(fnd_tgt, two), "Found target should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_tgt));
1184     ok(!lstrcmpW(fnd_loc, one), "Found location should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_loc));
1185     CoTaskMemFree(fnd_tgt);
1186     CoTaskMemFree(fnd_loc);
1187
1188     hres = IHlink_SetStringReference(link, -HLINKSETF_TARGET, three, two);
1189     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1190
1191     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1192     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1193     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1194     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1195     CoTaskMemFree(fnd_tgt);
1196     CoTaskMemFree(fnd_loc);
1197
1198     /* test setting/getting both */
1199     hres = IHlink_SetStringReference(link, HLINKSETF_TARGET | HLINKSETF_LOCATION, one, two);
1200     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1201
1202     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1203     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1204     ok(!lstrcmpW(fnd_tgt, one), "Found target should have been %s, was: %s\n", wine_dbgstr_w(one), wine_dbgstr_w(fnd_tgt));
1205     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1206     CoTaskMemFree(fnd_tgt);
1207     CoTaskMemFree(fnd_loc);
1208
1209     hres = IHlink_SetStringReference(link, -(HLINKSETF_TARGET | HLINKSETF_LOCATION), three, one);
1210     ok(hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1211
1212     hres = IHlink_GetStringReference(link, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1213     ok(hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1214     ok(!lstrcmpW(fnd_tgt, three), "Found target should have been %s, was: %s\n", wine_dbgstr_w(three), wine_dbgstr_w(fnd_tgt));
1215     ok(!lstrcmpW(fnd_loc, two), "Found location should have been %s, was: %s\n", wine_dbgstr_w(two), wine_dbgstr_w(fnd_loc));
1216     CoTaskMemFree(fnd_tgt);
1217     CoTaskMemFree(fnd_loc);
1218
1219     /* test invalid flags/params */
1220     hres = IHlink_GetStringReference(link, 4, &fnd_tgt, &fnd_loc);
1221     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1222            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1223     ok(fnd_tgt == NULL, "Found target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1224     ok(fnd_loc == NULL, "Found location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1225     CoTaskMemFree(fnd_tgt);
1226     CoTaskMemFree(fnd_loc);
1227
1228     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, NULL);
1229     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1230            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1231     CoTaskMemFree(fnd_tgt);
1232
1233     hres = IHlink_GetStringReference(link, -1, NULL, NULL);
1234     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1235
1236     hres = IHlink_GetStringReference(link, -1, NULL, &fnd_loc);
1237     ok(hres == S_OK, "failed, hres=%08x\n", hres);
1238     CoTaskMemFree(fnd_loc);
1239
1240     hres = IHlink_GetStringReference(link, -1, &fnd_tgt, &fnd_loc);
1241     todo_wine ok(hres == E_FAIL, "IHlink_GetStringReference should have failed "
1242            "with E_FAIL (0x%08x), instead: 0x%08x\n", E_FAIL, hres);
1243     CoTaskMemFree(fnd_tgt);
1244     CoTaskMemFree(fnd_loc);
1245
1246     hres = IHlink_GetStringReference(link, -2, &fnd_tgt, &fnd_loc);
1247     ok(hres == E_INVALIDARG, "IHlink_GetStringReference should have failed "
1248            "with E_INVALIDARG (0x%08x), instead: 0x%08x\n", E_INVALIDARG, hres);
1249     CoTaskMemFree(fnd_tgt);
1250     CoTaskMemFree(fnd_loc);
1251
1252     hres = IHlink_SetStringReference(link, 4, NULL, NULL);
1253     /* Windows returns garbage; on 32-bit it returns the flags probably because the compiler happened to store them in %eax at some point */
1254     if (0) ok(hres == 4, "IHlink_SetStringReference should have failed with 0x4, instead: 0x%08x\n", hres);
1255
1256     hres = IHlink_SetStringReference(link, -4, NULL, NULL);
1257     if (0) ok(hres == -4, "IHlink_SetStringReference should have failed with 0xFFFFFFFC, instead: 0x%08x\n", hres);
1258
1259     IHlink_Release(link);
1260 }
1261
1262 #define setStringRef(h,f,t,l) r_setStringRef(__LINE__,h,f,t,l)
1263 static void r_setStringRef(unsigned line, IHlink *hlink, DWORD flags, const WCHAR *tgt, const WCHAR *loc)
1264 {
1265     HRESULT hres;
1266     hres = IHlink_SetStringReference(hlink, flags, tgt, loc);
1267     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetStringReference failed: 0x%08x\n", hres);
1268 }
1269
1270 #define getStringRef(h,t,l) r_getStringRef(__LINE__,h,t,l)
1271 static void r_getStringRef(unsigned line, IHlink *hlink, const WCHAR *exp_tgt, const WCHAR *exp_loc)
1272 {
1273     HRESULT hres;
1274     WCHAR *fnd_tgt, *fnd_loc;
1275
1276     hres = IHlink_GetStringReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1277     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetStringReference failed: 0x%08x\n", hres);
1278
1279     if(exp_tgt)
1280         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));
1281     else
1282         ok_(__FILE__,line) (fnd_tgt == NULL, "Found string target should have been NULL, was: %s\n", wine_dbgstr_w(fnd_tgt));
1283
1284     if(exp_loc)
1285         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));
1286     else
1287         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1288
1289     CoTaskMemFree(fnd_tgt);
1290     CoTaskMemFree(fnd_loc);
1291 }
1292
1293 #define setMonikerRef(h,f,t,l) r_setMonikerRef(__LINE__,h,f,t,l)
1294 static void r_setMonikerRef(unsigned line, IHlink *hlink, DWORD flags, IMoniker *tgt, const WCHAR *loc)
1295 {
1296     HRESULT hres;
1297     hres = IHlink_SetMonikerReference(hlink, flags, tgt, loc);
1298     ok_(__FILE__,line) (hres == S_OK, "IHlink_SetMonikerReference failed: 0x%08x\n", hres);
1299 }
1300
1301 /* passing 0xFFFFFFFF as exp_tgt will return the retrieved target & not test it */
1302 #define getMonikerRef(h,t,l) r_getMonikerRef(__LINE__,h,t,l)
1303 static IMoniker *r_getMonikerRef(unsigned line, IHlink *hlink, IMoniker *exp_tgt, const WCHAR *exp_loc)
1304 {
1305     HRESULT hres;
1306     IMoniker *fnd_tgt;
1307     WCHAR *fnd_loc;
1308
1309     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &fnd_tgt, &fnd_loc);
1310     ok_(__FILE__,line) (hres == S_OK, "IHlink_GetMonikerReference failed: 0x%08x\n", hres);
1311
1312     if(exp_loc)
1313         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));
1314     else
1315         ok_(__FILE__,line) (fnd_loc == NULL, "Found string location should have been NULL, was: %s\n", wine_dbgstr_w(fnd_loc));
1316
1317     CoTaskMemFree(fnd_loc);
1318
1319     if(exp_tgt == (IMoniker*)0xFFFFFFFF)
1320         return fnd_tgt;
1321
1322     ok_(__FILE__,line) (fnd_tgt == exp_tgt, "Found moniker target should have been %p, was: %p\n", exp_tgt, fnd_tgt);
1323
1324     if(fnd_tgt)
1325         IMoniker_Release(fnd_tgt);
1326
1327     return NULL;
1328 }
1329
1330 static void test_HlinkMoniker(void)
1331 {
1332     IHlink *hlink;
1333     IMoniker *aMon, *file_mon;
1334     static const WCHAR emptyW[] = {0};
1335     static const WCHAR wordsW[] = {'w','o','r','d','s',0};
1336     static const WCHAR aW[] = {'a',0};
1337     static const WCHAR bW[] = {'b',0};
1338     HRESULT hres;
1339
1340     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void**)&hlink);
1341     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1342     getStringRef(hlink, NULL, NULL);
1343     getMonikerRef(hlink, NULL, NULL);
1344
1345     /* setting a string target creates a moniker reference */
1346     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, aW, wordsW);
1347     getStringRef(hlink, aW, wordsW);
1348     aMon = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, wordsW);
1349     ok(aMon != NULL, "Moniker from %s target should not be NULL\n", wine_dbgstr_w(aW));
1350     if(aMon)
1351         IMoniker_Release(aMon);
1352
1353     /* setting target & location to the empty string deletes the moniker
1354      * reference */
1355     setStringRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, emptyW, emptyW);
1356     getStringRef(hlink, NULL, NULL);
1357     getMonikerRef(hlink, NULL, NULL);
1358
1359     /* setting a moniker target also sets the target string to that moniker's
1360      * display name */
1361     hres = CreateFileMoniker(bW, &file_mon);
1362     ok(hres == S_OK, "CreateFileMoniker failed: 0x%08x\n", hres);
1363
1364     setMonikerRef(hlink, HLINKSETF_TARGET | HLINKSETF_LOCATION, file_mon, wordsW);
1365     getStringRef(hlink, bW, wordsW);
1366     getMonikerRef(hlink, file_mon, wordsW);
1367
1368     IMoniker_Release(file_mon);
1369
1370     IHlink_Release(hlink);
1371 }
1372
1373 static void test_HashLink(void)
1374 {
1375     IHlink *hlink;
1376     IMoniker *pmk;
1377     const WCHAR hash_targetW[] = {'a','f','i','l','e','#','a','n','a','n','c','h','o','r',0};
1378     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};
1379     const WCHAR hash_no_tgtW[] = {'#','a','n','a','n','c','h','o','r',0};
1380     const WCHAR tgt_partW[] = {'a','f','i','l','e',0};
1381     const WCHAR loc_partW[] = {'a','n','a','n','c','h','o','r',0};
1382     const WCHAR two_hash_loc_partW[] = {'a','n','a','n','c','h','o','r','#','a','n','o','t','h','e','r',0};
1383     const WCHAR test_locW[] = {'t','e','s','t','l','o','c',0};
1384     HRESULT hres;
1385
1386     /* simple single hash test */
1387     hres = HlinkCreateFromString(hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1388     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1389     ok(hlink != NULL, "Didn't get an hlink\n");
1390
1391     if(hlink){
1392         getStringRef(hlink, tgt_partW, loc_partW);
1393         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1394         ok(pmk != NULL, "Found moniker should not be NULL\n");
1395         if(pmk)
1396             IMoniker_Release(pmk);
1397
1398         setStringRef(hlink, HLINKSETF_TARGET, hash_targetW, NULL);
1399         getStringRef(hlink, hash_targetW, loc_partW);
1400
1401         IHlink_Release(hlink);
1402     }
1403
1404     /* two hashes in the target */
1405     hres = HlinkCreateFromString(two_hash_targetW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1406     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1407     ok(hlink != NULL, "Didn't get an hlink\n");
1408
1409     if(hlink){
1410         getStringRef(hlink, tgt_partW, two_hash_loc_partW);
1411         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, two_hash_loc_partW);
1412         ok(pmk != NULL, "Found moniker should not be NULL\n");
1413         if(pmk)
1414             IMoniker_Release(pmk);
1415
1416         IHlink_Release(hlink);
1417     }
1418
1419     /* target with hash plus a location string */
1420     hres = HlinkCreateFromString(hash_targetW, test_locW, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1421     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1422     ok(hlink != NULL, "Didn't get an hlink\n");
1423
1424     if(hlink){
1425         getStringRef(hlink, tgt_partW, test_locW);
1426         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, test_locW);
1427         ok(pmk != NULL, "Found moniker should not be NULL\n");
1428         if(pmk)
1429             IMoniker_Release(pmk);
1430
1431         IHlink_Release(hlink);
1432     }
1433
1434     /* target with hash containing no "target part" */
1435     hres = HlinkCreateFromString(hash_no_tgtW, NULL, NULL, NULL, 0, NULL, &IID_IHlink, (void*)&hlink);
1436     ok(hres == S_OK, "HlinkCreateFromString failed: 0x%08x\n", hres);
1437     ok(hlink != NULL, "Didn't get an hlink\n");
1438
1439     if(hlink){
1440         getStringRef(hlink, NULL, loc_partW);
1441         pmk = getMonikerRef(hlink, (IMoniker*)0xFFFFFFFF, loc_partW);
1442         ok(pmk == NULL, "Found moniker should be NULL\n");
1443         if(pmk)
1444             IMoniker_Release(pmk);
1445
1446         IHlink_Release(hlink);
1447     }
1448 }
1449
1450 static WCHAR site_monikerW[] = {'S','I','T','E','_','M','O','N','I','K','E','R',0};
1451 static WCHAR ref_monikerW[] = {'R','E','F','_','M','O','N','I','K','E','R',0};
1452
1453 static HRESULT WINAPI hls_test_Moniker_BindToStorage(IMoniker *iface,
1454         IBindCtx *pbc, IMoniker *toLeft, REFIID riid, void **obj)
1455 {
1456     ok(0, "BTS: %p %p %p %p %p\n", iface, pbc, toLeft, riid, obj);
1457     return E_NOTIMPL;
1458 }
1459
1460 static HRESULT WINAPI hls_site_Moniker_ComposeWith(IMoniker *iface,
1461         IMoniker *right, BOOL onlyIfNotGeneric, IMoniker **composite)
1462 {
1463     LPOLESTR rightName;
1464     HRESULT hres;
1465
1466     ok(onlyIfNotGeneric == 0, "Expected onlyIfNotGeneric to be FALSE\n");
1467
1468     CHECK_EXPECT(ComposeWith);
1469
1470     hres = IMoniker_GetDisplayName(right, NULL, NULL, &rightName);
1471     ok(hres == S_OK, "GetDisplayName failed: %08x\n", hres);
1472     ok(!lstrcmpW(rightName, ref_monikerW),
1473             "Expected to get moniker set via SetMonikerReference, instead got: %s\n",
1474             wine_dbgstr_w(rightName));
1475     CoTaskMemFree(rightName);
1476
1477     *composite = NULL;
1478
1479     /* unlikely error code to verify this return result is used */
1480     return E_OUTOFMEMORY;
1481 }
1482
1483 static HRESULT WINAPI hls_site_Moniker_GetDisplayName(IMoniker *iface,
1484         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1485 {
1486     *displayName = CoTaskMemAlloc(sizeof(site_monikerW));
1487     memcpy(*displayName, site_monikerW, sizeof(site_monikerW));
1488     return S_OK;
1489 }
1490
1491 static HRESULT WINAPI hls_ref_Moniker_GetDisplayName(IMoniker *iface,
1492         IBindCtx *pbc, IMoniker *toLeft, LPOLESTR *displayName)
1493 {
1494     *displayName = CoTaskMemAlloc(sizeof(ref_monikerW));
1495     memcpy(*displayName, ref_monikerW, sizeof(ref_monikerW));
1496     return S_OK;
1497 }
1498
1499 static HRESULT WINAPI hls_test_Moniker_IsSystemMoniker(IMoniker *iface,
1500         DWORD *mksys)
1501 {
1502     return S_FALSE;
1503 }
1504
1505 static IMonikerVtbl hls_site_MonikerVtbl = {
1506     Moniker_QueryInterface,
1507     Moniker_AddRef,
1508     Moniker_Release,
1509     Moniker_GetClassID,
1510     Moniker_IsDirty,
1511     Moniker_Load,
1512     Moniker_Save,
1513     Moniker_GetSizeMax,
1514     Moniker_BindToObject,
1515     hls_test_Moniker_BindToStorage,
1516     Moniker_Reduce,
1517     hls_site_Moniker_ComposeWith,
1518     Moniker_Enum,
1519     Moniker_IsEqual,
1520     Moniker_Hash,
1521     Moniker_IsRunning,
1522     Moniker_GetTimeOfLastChange,
1523     Moniker_Inverse,
1524     Moniker_CommonPrefixWith,
1525     Moniker_RelativePathTo,
1526     hls_site_Moniker_GetDisplayName,
1527     Moniker_ParseDisplayName,
1528     hls_test_Moniker_IsSystemMoniker
1529 };
1530
1531 static IMonikerVtbl hls_ref_MonikerVtbl = {
1532     Moniker_QueryInterface,
1533     Moniker_AddRef,
1534     Moniker_Release,
1535     Moniker_GetClassID,
1536     Moniker_IsDirty,
1537     Moniker_Load,
1538     Moniker_Save,
1539     Moniker_GetSizeMax,
1540     Moniker_BindToObject,
1541     hls_test_Moniker_BindToStorage,
1542     Moniker_Reduce,
1543     Moniker_ComposeWith,
1544     Moniker_Enum,
1545     Moniker_IsEqual,
1546     Moniker_Hash,
1547     Moniker_IsRunning,
1548     Moniker_GetTimeOfLastChange,
1549     Moniker_Inverse,
1550     Moniker_CommonPrefixWith,
1551     Moniker_RelativePathTo,
1552     hls_ref_Moniker_GetDisplayName,
1553     Moniker_ParseDisplayName,
1554     hls_test_Moniker_IsSystemMoniker
1555 };
1556
1557 static IMoniker hls_site_Moniker = { &hls_site_MonikerVtbl };
1558 static IMoniker hls_ref_Moniker = { &hls_ref_MonikerVtbl };
1559
1560 static HRESULT WINAPI hls_QueryInterface(IHlinkSite *iface, REFGUID iid,
1561         void **obj)
1562 {
1563     ok(0, "QI: %p %s %p\n", iface, debugstr_guid(iid), obj);
1564     return E_NOTIMPL;
1565 }
1566
1567 static ULONG WINAPI hls_AddRef(IHlinkSite *iface)
1568 {
1569     return 2;
1570 }
1571
1572 static ULONG WINAPI hls_Release(IHlinkSite *iface)
1573 {
1574     return 1;
1575 }
1576
1577 static HRESULT WINAPI hls_QueryService(IHlinkSite *iface, DWORD siteData,
1578         REFGUID service, REFIID riid, IUnknown **punk)
1579 {
1580     ok(0, "QS: %p %x %s %s %p\n", iface, siteData, debugstr_guid(service),
1581             debugstr_guid(riid), punk);
1582     return E_NOTIMPL;
1583 }
1584
1585 static HRESULT WINAPI hls_GetMoniker(IHlinkSite *iface, DWORD siteData,
1586         DWORD assign, DWORD which, IMoniker **pmk)
1587 {
1588     ok(siteData == 17, "Expected siteData == 17, got: %d\n", siteData);
1589     *pmk = &hls_site_Moniker;
1590     return S_OK;
1591 }
1592
1593 static HRESULT WINAPI hls_ReadyToNavigate(IHlinkSite *iface, DWORD siteData,
1594         DWORD reserved)
1595 {
1596     ok(0, "RTN: %p %x %x\n", iface, siteData, reserved);
1597     return E_NOTIMPL;
1598 }
1599
1600 static HRESULT WINAPI hls_OnNavigationComplete(IHlinkSite *iface,
1601         DWORD siteData, DWORD reserved, HRESULT error, LPCWSTR errorStr)
1602 {
1603     CHECK_EXPECT(OnNavigationComplete);
1604     ok(siteData == 17, "Expected siteData == 17, got: %d\n", siteData);
1605     ok(error == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", error);
1606     return E_NOTIMPL;
1607 }
1608
1609 static IHlinkSiteVtbl HlinkSiteVtbl = {
1610     hls_QueryInterface,
1611     hls_AddRef,
1612     hls_Release,
1613     hls_QueryService,
1614     hls_GetMoniker,
1615     hls_ReadyToNavigate,
1616     hls_OnNavigationComplete
1617 };
1618
1619 static IHlinkSite HlinkSite = { &HlinkSiteVtbl };
1620
1621 static void test_HlinkSite(void)
1622 {
1623     IHlink *hl;
1624     IMoniker *mon_ref;
1625     IBindCtx *pbc;
1626     HRESULT hres;
1627
1628     hres = HlinkCreateFromString(NULL, NULL, NULL, NULL, 0, NULL,
1629             &IID_IHlink, (LPVOID*)&hl);
1630     ok(hres == S_OK, "HlinkCreateFromString failed: %08x\n", hres);
1631     getMonikerRef(hl, NULL, NULL);
1632
1633     hres = IHlink_SetHlinkSite(hl, &HlinkSite, 17);
1634     ok(hres == S_OK, "SetHlinkSite failed: %08x\n", hres);
1635     getMonikerRef(hl, NULL, NULL);
1636     getStringRef(hl, NULL, NULL);
1637
1638     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1639     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1640     ok(mon_ref == NULL, "Didn't get expected moniker, instead: %p\n", mon_ref);
1641
1642     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1643     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1644     ok(mon_ref == &hls_site_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1645
1646     SET_EXPECT(Reduce);
1647     SET_EXPECT(Enum);
1648     hres = IHlink_SetMonikerReference(hl, HLINKSETF_TARGET, &hls_ref_Moniker, NULL);
1649     ok(hres == S_OK, "SetMonikerReference failed: %08x\n", hres);
1650     todo_wine CHECK_CALLED(Reduce);
1651     todo_wine CHECK_CALLED(Enum);
1652
1653     getMonikerRef(hl, &hls_ref_Moniker, NULL);
1654
1655     SET_EXPECT(Enum);
1656     getStringRef(hl, ref_monikerW, NULL);
1657     todo_wine CHECK_CALLED(Enum);
1658
1659     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_RELATIVE, &mon_ref, NULL);
1660     ok(hres == S_OK, "GetMonikerReference failed: %08x\n", hres);
1661     ok(mon_ref == &hls_ref_Moniker, "Didn't get expected moniker, instead: %p\n", mon_ref);
1662     IMoniker_Release(mon_ref);
1663
1664     SET_EXPECT(ComposeWith);
1665     hres = IHlink_GetMonikerReference(hl, HLINKGETREF_ABSOLUTE, &mon_ref, NULL);
1666     ok(hres == E_OUTOFMEMORY, "Expected E_OUTOFMEMORY, got: %08x\n", hres);
1667     ok(mon_ref == NULL, "Shouldn't have got a Moniker, got: %p\n", mon_ref);
1668     CHECK_CALLED(ComposeWith);
1669
1670     hres = CreateBindCtx(0, &pbc);
1671     ok(hres == S_OK, "CreateBindCtx failed: %08x\n", hres);
1672
1673     SET_EXPECT(ComposeWith);
1674     SET_EXPECT(OnNavigationComplete);
1675     hres = IHlink_Navigate(hl, 0, pbc, NULL, NULL);
1676     ok(hres == E_OUTOFMEMORY, "Navigate should've failed: %08x\n", hres);
1677     CHECK_CALLED(ComposeWith);
1678     CHECK_CALLED(OnNavigationComplete);
1679
1680     IBindCtx_Release(pbc);
1681     IHlink_Release(hl);
1682
1683     SET_EXPECT(Reduce);
1684     SET_EXPECT(Enum);
1685     hres = HlinkCreateFromMoniker(&hls_ref_Moniker, NULL, NULL, &HlinkSite, 17,
1686             NULL, &IID_IHlink, (LPVOID*)&hl);
1687     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1688     todo_wine CHECK_CALLED(Reduce);
1689     todo_wine CHECK_CALLED(Enum);
1690     getMonikerRef(hl, &hls_ref_Moniker, NULL);
1691     IHlink_Release(hl);
1692
1693     hres = HlinkCreateFromMoniker(NULL, NULL, NULL, &HlinkSite, 17,
1694             NULL, &IID_IHlink, (LPVOID*)&hl);
1695     ok(hres == S_OK, "HlinkCreateFromMoniker failed: %08x\n", hres);
1696     getMonikerRef(hl, NULL, NULL);
1697     IHlink_Release(hl);
1698 }
1699
1700 START_TEST(hlink)
1701 {
1702     CoInitialize(NULL);
1703
1704     test_HlinkIsShortcut();
1705     test_reference();
1706     test_persist();
1707     test_special_reference();
1708     test_HlinkCreateExtensionServices();
1709     test_HlinkParseDisplayName();
1710     test_HlinkResolveMonikerForData();
1711     test_HlinkGetSetMonikerReference();
1712     test_HlinkGetSetStringReference();
1713     test_HlinkMoniker();
1714     test_HashLink();
1715     test_HlinkSite();
1716
1717     CoUninitialize();
1718 }