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