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