Autosyncing with Wine HEAD
[reactos.git] / rostests / winetests / hlink / 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 <hlink.h>
27 #include <hlguids.h>
28
29 #include "wine/test.h"
30
31 #define DEFINE_EXPECT(func) \
32 static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
33
34 #define SET_EXPECT(func) \
35 expect_ ## func = TRUE
36
37 #define CHECK_EXPECT2(func) \
38 do { \
39 ok(expect_ ##func, "unexpected call " #func "\n"); \
40 called_ ## func = TRUE; \
41 }while(0)
42
43 #define CHECK_EXPECT(func) \
44 do { \
45 CHECK_EXPECT2(func); \
46 expect_ ## func = FALSE; \
47 }while(0)
48
49 #define CHECK_CALLED(func) \
50 do { \
51 ok(called_ ## func, "expected " #func "\n"); \
52 expect_ ## func = called_ ## func = FALSE; \
53 }while(0)
54
55 DEFINE_EXPECT(IsSystemMoniker);
56 DEFINE_EXPECT(BindToStorage);
57 DEFINE_EXPECT(GetDisplayName);
58
59 static const char *debugstr_w(LPCWSTR str)
60 {
61 static char buf[1024];
62 if(!str)
63 return "(null)";
64 WideCharToMultiByte(CP_ACP, 0, str, -1, buf, sizeof(buf), NULL, NULL);
65 return buf;
66 }
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 int 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, HLINKGETREF_DEFAULT, &str, NULL);
147 ok(r == S_OK, "failed\n");
148 todo_wine {
149 ok(!lstrcmpW(str, url2), "url wrong\n");
150 }
151 CoTaskMemFree(str);
152
153 r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, NULL);
154 ok(r == S_OK, "failed\n");
155
156 r = IHlink_GetStringReference(lnk, HLINKGETREF_DEFAULT, NULL, &str);
157 ok(r == S_OK, "failed\n");
158 ok(str == NULL, "string should be null\n");
159
160 IHlink_Release(lnk);
161 }
162
163 /* url only */
164 static const unsigned char expected_hlink_data[] =
165 {
166 0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
167 0xe0,0xc9,0xea,0x79,0xf9,0xba,0xce,0x11,
168 0x8c,0x82,0x00,0xaa,0x00,0x4b,0xa9,0x0b,
169 0x26,0x00,0x00,0x00,0x68,0x00,0x74,0x00,
170 0x74,0x00,0x70,0x00,0x3a,0x00,0x2f,0x00,
171 0x2f,0x00,0x77,0x00,0x69,0x00,0x6e,0x00,
172 0x65,0x00,0x68,0x00,0x71,0x00,0x2e,0x00,
173 0x6f,0x00,0x72,0x00,0x67,0x00,0x2f,0x00,
174 0x00,0x00,
175 };
176
177 /* url + friendly name */
178 static const unsigned char expected_hlink_data2[] =
179 {
180 0x02,0x00,0x00,0x00,0x17,0x00,0x00,0x00,
181 0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
182 0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
183 0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
184 0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
185 0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
186 0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
187 0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
188 0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
189 0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
190 0x67,0x00,0x2f,0x00,0x00,0x00,
191 };
192
193 /* url + friendly name + location */
194 static const unsigned char expected_hlink_data3[] =
195 {
196 0x02,0x00,0x00,0x00,0x1f,0x00,0x00,0x00,
197 0x08,0x00,0x00,0x00,0x57,0x00,0x69,0x00,
198 0x6e,0x00,0x65,0x00,0x20,0x00,0x48,0x00,
199 0x51,0x00,0x00,0x00,0xe0,0xc9,0xea,0x79,
200 0xf9,0xba,0xce,0x11,0x8c,0x82,0x00,0xaa,
201 0x00,0x4b,0xa9,0x0b,0x26,0x00,0x00,0x00,
202 0x68,0x00,0x74,0x00,0x74,0x00,0x70,0x00,
203 0x3a,0x00,0x2f,0x00,0x2f,0x00,0x77,0x00,
204 0x69,0x00,0x6e,0x00,0x65,0x00,0x68,0x00,
205 0x71,0x00,0x2e,0x00,0x6f,0x00,0x72,0x00,
206 0x67,0x00,0x2f,0x00,0x00,0x00,0x07,0x00,
207 0x00,0x00,0x5f,0x00,0x62,0x00,0x6c,0x00,
208 0x61,0x00,0x6e,0x00,0x6b,0x00,0x00,0x00,
209 };
210
211 /* relative url */
212 static const unsigned char expected_hlink_data4[] =
213 {
214 0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00,
215 0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
216 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
217 0x00,0x00,0x0b,0x00,0x00,0x00,0x69,0x6e,
218 0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,
219 0x00,0xff,0xff,0xad,0xde,0x00,0x00,0x00,
220 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
221 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
222 0x00,0x00,0x00,0x00,0x00,
223 };
224
225 /* url + target frame name */
226 static const unsigned char expected_hlink_data5[] =
227 {
228 0x02,0x00,0x00,0x00,0x83,0x00,0x00,0x00,
229 0x07,0x00,0x00,0x00,0x74,0x00,0x67,0x00,
230 0x74,0x00,0x66,0x00,0x72,0x00,0x6d,0x00,
231 0x00,0x00,0xe0,0xc9,0xea,0x79,0xf9,0xba,
232 0xce,0x11,0x8c,0x82,0x00,0xaa,0x00,0x4b,
233 0xa9,0x0b,0x26,0x00,0x00,0x00,0x68,0x00,
234 0x74,0x00,0x74,0x00,0x70,0x00,0x3a,0x00,
235 0x2f,0x00,0x2f,0x00,0x77,0x00,0x69,0x00,
236 0x6e,0x00,0x65,0x00,0x68,0x00,0x71,0x00,
237 0x2e,0x00,0x6f,0x00,0x72,0x00,0x67,0x00,
238 0x2f,0x00,0x00,0x00,
239 };
240
241 /* filename */
242 static const unsigned char expected_hlink_data6[] =
243 {
244 0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00,
245 0x03,0x03,0x00,0x00,0x00,0x00,0x00,0x00,
246 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46,
247 0x00,0x00,0x04,0x00,0x00,0x00,0x63,0x3a,
248 0x5c,0x00,0xff,0xff,0xad,0xde,0x00,0x00,
249 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
250 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
251 0x00,0x00,0x0c,0x00,0x00,0x00,0x06,0x00,
252 0x00,0x00,0x03,0x00,0x63,0x00,0x3a,0x00,
253 0x5c,0x00,
254 };
255
256 static void test_persist_save_data(const char *testname, IHlink *lnk,
257 const unsigned char *expected_data,
258 unsigned int expected_data_size)
259 {
260 HRESULT hr;
261 IStream *stream;
262 IPersistStream *ps;
263 HGLOBAL hglobal;
264 DWORD data_size;
265 const unsigned char *data;
266 DWORD i;
267 BOOL same;
268
269 hr = IHlink_QueryInterface(lnk, &IID_IPersistStream, (void **)&ps);
270 ok(hr == S_OK, "IHlink_QueryInterface failed with error 0x%08x\n", hr);
271
272 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
273 ok(hr == S_OK, "CreateStreamOnHGlobal failed with error 0x%08x\n", hr);
274
275 hr = IPersistStream_Save(ps, stream, TRUE);
276 ok(hr == S_OK, "IPersistStream_Save failed with error 0x%08x\n", hr);
277
278 hr = GetHGlobalFromStream(stream, &hglobal);
279 ok(hr == S_OK, "GetHGlobalFromStream failed with error 0x%08x\n", hr);
280
281 data_size = GlobalSize(hglobal);
282
283 data = GlobalLock(hglobal);
284
285 /* first check we have the right amount of data */
286 ok(data_size == expected_data_size,
287 "%s: Size of saved data differs (expected %d, actual %d)\n",
288 testname, expected_data_size, data_size);
289
290 same = TRUE;
291 /* then do a byte-by-byte comparison */
292 for (i = 0; i < min(data_size, expected_data_size); i++)
293 {
294 if ((expected_data[i] != data[i]) &&
295 (((expected_data != expected_hlink_data2) &&
296 (expected_data != expected_hlink_data3)) ||
297 ((i < 52 || i >= 56) && (i < 80 || i >= 84))))
298 {
299 same = FALSE;
300 break;
301 }
302 }
303
304 ok(same, "%s: Saved data differs\n", testname);
305 if (!same)
306 {
307 for (i = 0; i < data_size; i++)
308 {
309 if (i % 8 == 0) printf(" ");
310 printf("0x%02x,", data[i]);
311 if (i % 8 == 7) printf("\n");
312 }
313 printf("\n");
314 }
315
316 GlobalUnlock(hglobal);
317
318 IStream_Release(stream);
319 IPersistStream_Release(ps);
320 }
321
322 static void test_persist(void)
323 {
324 static const WCHAR url[] = { 'h','t','t','p',':','/','/','w','i','n','e','h','q','.','o','r','g',0 };
325 static const WCHAR rel_url[] = { 'i','n','d','e','x','.','h','t','m','l',0 };
326 static const WCHAR filename[] = { 'c',':','\\',0 };
327 static const WCHAR friendly_name[] = { 'W','i','n','e',' ','H','Q',0 };
328 static const WCHAR location[] = { '_','b','l','a','n','k',0 };
329 static const WCHAR target_frame_name[] = { 't','g','t','f','r','m',0 };
330 HRESULT hr;
331 IHlink *lnk;
332
333 hr = HlinkCreateFromString(url, NULL, NULL, NULL,
334 0, NULL, &IID_IHlink, (LPVOID*) &lnk);
335 ok(hr == S_OK, "IHlinkCreateFromString failed with error 0x%08x\n", hr);
336 if (!lnk) {
337 skip("Can't create lnk, skipping test_persist. Was wineprefixcreate run properly?\n");
338 return;
339 }
340 test_persist_save_data("url only", lnk, expected_hlink_data, sizeof(expected_hlink_data));
341 IHlink_Release(lnk);
342
343 hr = HlinkCreateFromString(url, NULL, friendly_name, NULL,
344 0, NULL, &IID_IHlink, (LPVOID*) &lnk);
345 ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
346 test_persist_save_data("url + friendly name", lnk, expected_hlink_data2, sizeof(expected_hlink_data2));
347 IHlink_Release(lnk);
348
349 hr = HlinkCreateFromString(url, location, friendly_name, NULL,
350 0, NULL, &IID_IHlink, (LPVOID*) &lnk);
351 ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
352 test_persist_save_data("url + friendly_name + location", lnk, expected_hlink_data3, sizeof(expected_hlink_data3));
353 IHlink_Release(lnk);
354
355 hr = HlinkCreateFromString(rel_url, NULL, NULL, NULL,
356 0, NULL, &IID_IHlink, (LPVOID*) &lnk);
357 ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
358 test_persist_save_data("relative url", lnk, expected_hlink_data4, sizeof(expected_hlink_data4));
359 IHlink_Release(lnk);
360
361 hr = HlinkCreateFromString(url, NULL, NULL, NULL,
362 0, NULL, &IID_IHlink, (LPVOID*) &lnk);
363 ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
364 hr = IHlink_SetTargetFrameName(lnk, target_frame_name);
365 ok(hr == S_OK, "IHlink_SetTargetFrameName failed with error 0x%08x\n", hr);
366 test_persist_save_data("url + target frame name", lnk, expected_hlink_data5, sizeof(expected_hlink_data5));
367 IHlink_Release(lnk);
368
369 hr = HlinkCreateFromString(filename, NULL, NULL, NULL,
370 0, NULL, &IID_IHlink, (LPVOID*) &lnk);
371 ok(hr == S_OK, "IHlinCreateFromString failed with error 0x%08x\n", hr);
372 test_persist_save_data("filename", lnk, expected_hlink_data6, sizeof(expected_hlink_data6));
373 IHlink_Release(lnk);
374 }
375
376 static void test_special_reference(void)
377 {
378 LPWSTR ref;
379 HRESULT hres;
380
381 hres = HlinkGetSpecialReference(HLSR_HOME, &ref);
382 ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_HOME) failed: %08x\n", hres);
383 ok(ref != NULL, "ref == NULL\n");
384 CoTaskMemFree(ref);
385
386 hres = HlinkGetSpecialReference(HLSR_SEARCHPAGE, &ref);
387 ok(hres == S_OK, "HlinkGetSpecialReference(HLSR_SEARCHPAGE) failed: %08x\n", hres);
388 ok(ref != NULL, "ref == NULL\n");
389 CoTaskMemFree(ref);
390
391 ref = (void*)0xdeadbeef;
392 hres = HlinkGetSpecialReference(HLSR_HISTORYFOLDER, &ref);
393 ok(hres == E_NOTIMPL, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
394 ok(ref == NULL, "ref=%p\n", ref);
395
396 ref = (void*)0xdeadbeef;
397 hres = HlinkGetSpecialReference(4, &ref);
398 ok(hres == E_INVALIDARG, "HlinkGetSpecialReference(HLSR_HISTORYFOLDER) failed: %08x\n", hres);
399 ok(ref == NULL, "ref=%p\n", ref);
400 }
401
402 static void test_HlinkCreateExtensionServices(void)
403 {
404 IAuthenticate *authenticate;
405 IHttpNegotiate *http_negotiate;
406 LPWSTR password, username, headers;
407 HWND hwnd;
408 HRESULT hres;
409
410 static const WCHAR usernameW[] = {'u','s','e','r',0};
411 static const WCHAR passwordW[] = {'p','a','s','s',0};
412 static const WCHAR headersW[] = {'h','e','a','d','e','r','s',0};
413 static const WCHAR headersexW[] = {'h','e','a','d','e','r','s','\r','\n',0};
414
415 hres = HlinkCreateExtensionServices(NULL, NULL, NULL, NULL,
416 NULL, &IID_IAuthenticate, (void**)&authenticate);
417 ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
418 ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
419
420 password = username = (void*)0xdeadbeef;
421 hwnd = (void*)0xdeadbeef;
422 hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
423 ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
424 ok(!hwnd, "hwnd != NULL\n");
425 ok(!username, "username != NULL\n");
426 ok(!password, "password != NULL\n");
427
428 hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
429 ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
430
431 headers = (void*)0xdeadbeef;
432 hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
433 0, &headers);
434 ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
435 ok(headers == NULL, "headers != NULL\n");
436
437 hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
438 0, NULL);
439 ok(hres == E_INVALIDARG, "BeginningTransaction failed: %08x, expected E_INVALIDARG\n", hres);
440
441 headers = (void*)0xdeadbeef;
442 hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
443 ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
444 ok(headers == NULL, "headers != NULL\n");
445
446 IHttpNegotiate_Release(http_negotiate);
447 IAuthenticate_Release(authenticate);
448
449
450 hres = HlinkCreateExtensionServices(headersW, (HWND)0xfefefefe, usernameW, passwordW,
451 NULL, &IID_IAuthenticate, (void**)&authenticate);
452 ok(hres == S_OK, "HlinkCreateExtensionServices failed: %08x\n", hres);
453 ok(authenticate != NULL, "HlinkCreateExtensionServices returned NULL\n");
454
455 password = username = NULL;
456 hwnd = NULL;
457 hres = IAuthenticate_Authenticate(authenticate, &hwnd, &username, &password);
458 ok(hres == S_OK, "Authenticate failed: %08x\n", hres);
459 ok(hwnd == (HWND)0xfefefefe, "hwnd=%p\n", hwnd);
460 ok(!lstrcmpW(username, usernameW), "unexpected username\n");
461 ok(!lstrcmpW(password, passwordW), "unexpected password\n");
462 CoTaskMemFree(username);
463 CoTaskMemFree(password);
464
465 password = username = (void*)0xdeadbeef;
466 hwnd = (void*)0xdeadbeef;
467 hres = IAuthenticate_Authenticate(authenticate, &hwnd, NULL, &password);
468 ok(hres == E_INVALIDARG, "Authenticate failed: %08x\n", hres);
469 ok(password == (void*)0xdeadbeef, "password = %p\n", password);
470 ok(hwnd == (void*)0xdeadbeef, "hwnd = %p\n", hwnd);
471
472 hres = IAuthenticate_QueryInterface(authenticate, &IID_IHttpNegotiate, (void**)&http_negotiate);
473 ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
474
475 headers = (void*)0xdeadbeef;
476 hres = IHttpNegotiate_BeginningTransaction(http_negotiate, (void*)0xdeadbeef, (void*)0xdeadbeef,
477 0, &headers);
478 ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
479 ok(!lstrcmpW(headers, headersexW), "unexpected headers \"%s\"\n", debugstr_w(headers));
480 CoTaskMemFree(headers);
481
482 headers = (void*)0xdeadbeef;
483 hres = IHttpNegotiate_OnResponse(http_negotiate, 200, (void*)0xdeadbeef, (void*)0xdeadbeef, &headers);
484 ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
485 ok(headers == NULL, "unexpected headers \"%s\"\n", debugstr_w(headers));
486
487 IHttpNegotiate_Release(http_negotiate);
488 IAuthenticate_Release(authenticate);
489 }
490
491 static void test_HlinkParseDisplayName(void)
492 {
493 IMoniker *mon = NULL;
494 LPWSTR name;
495 DWORD issys;
496 ULONG eaten = 0;
497 IBindCtx *bctx;
498 HRESULT hres;
499
500 static const WCHAR winehq_urlW[] =
501 {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
502 '/','s','i','t','e','/','a','b','o','u','t',0};
503 static const WCHAR invalid_urlW[] = {'t','e','s','t',':','1','2','3','a','b','c',0};
504 static const WCHAR clsid_nameW[] = {'c','l','s','i','d',':',
505 '2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-','A','2','D','8',
506 '-','0','8','0','0','2','B','3','0','3','0','9','D',':',0};
507
508 CreateBindCtx(0, &bctx);
509
510 hres = HlinkParseDisplayName(bctx, winehq_urlW, FALSE, &eaten, &mon);
511 ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
512 ok(eaten == sizeof(winehq_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
513 ok(mon != NULL, "mon == NULL\n");
514
515 hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
516 ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
517 ok(!lstrcmpW(name, winehq_urlW), "wrong display name %s\n", debugstr_w(name));
518 CoTaskMemFree(name);
519
520 hres = IMoniker_IsSystemMoniker(mon, &issys);
521 ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
522 ok(issys == MKSYS_URLMONIKER, "issys=%x\n", issys);
523
524 IMoniker_Release(mon);
525
526 hres = HlinkParseDisplayName(bctx, clsid_nameW, FALSE, &eaten, &mon);
527 ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
528 ok(eaten == sizeof(clsid_nameW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
529 ok(mon != NULL, "mon == NULL\n");
530
531 hres = IMoniker_IsSystemMoniker(mon, &issys);
532 ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
533 ok(issys == MKSYS_CLASSMONIKER, "issys=%x\n", issys);
534
535 IMoniker_Release(mon);
536
537 hres = HlinkParseDisplayName(bctx, invalid_urlW, FALSE, &eaten, &mon);
538 ok(hres == S_OK, "HlinkParseDisplayName failed: %08x\n", hres);
539 ok(eaten == sizeof(invalid_urlW)/sizeof(WCHAR)-1, "eaten=%d\n", eaten);
540 ok(mon != NULL, "mon == NULL\n");
541
542 hres = IMoniker_GetDisplayName(mon, bctx, 0, &name);
543 ok(hres == S_OK, "GetDiasplayName failed: %08x\n", hres);
544 ok(!lstrcmpW(name, invalid_urlW), "wrong display name %s\n", debugstr_w(name));
545 CoTaskMemFree(name);
546
547 hres = IMoniker_IsSystemMoniker(mon, &issys);
548 ok(hres == S_OK, "IsSystemMoniker failed: %08x\n", hres);
549 ok(issys == MKSYS_FILEMONIKER, "issys=%x\n", issys);
550
551 IBindCtx_Release(bctx);
552 }
553
554 static IBindCtx *_bctx;
555
556 static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
557 {
558 ok(0, "unexpected call\n");
559 return E_NOINTERFACE;
560 }
561
562 static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
563 {
564 return 2;
565 }
566
567 static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
568 {
569 return 1;
570 }
571
572 static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
573 REFGUID guidService, REFIID riid, void **ppv)
574 {
575 ok(0, "unexpected service %s\n", debugstr_guid(guidService));
576 return E_NOINTERFACE;
577 }
578
579 static IServiceProviderVtbl ServiceProviderVtbl = {
580 ServiceProvider_QueryInterface,
581 ServiceProvider_AddRef,
582 ServiceProvider_Release,
583 ServiceProvider_QueryService
584 };
585
586 static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
587
588 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
589 {
590 *ppv = NULL;
591
592 if(IsEqualGUID(riid, &IID_IServiceProvider)) {
593 *ppv = &ServiceProvider;
594 return S_OK;
595 }
596
597 ok(0, "unexpected interface %s\n", debugstr_guid(riid));
598 return E_NOINTERFACE;
599 }
600
601 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
602 {
603 return 2;
604 }
605
606 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
607 {
608 return 1;
609 }
610
611 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface, DWORD dwReserved,
612 IBinding *pib)
613 {
614 ok(0, "unexpected call\n");
615 return E_NOTIMPL;
616 }
617
618 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface, LONG *pnPriority)
619 {
620 ok(0, "unexpected call\n");
621 return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface, DWORD reserved)
625 {
626 ok(0, "unexpected call\n");
627 return E_NOTIMPL;
628 }
629
630 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress,
631 ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
632 {
633 ok(0, "unexpected call\n");
634 return E_NOTIMPL;
635 }
636
637 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError)
638 {
639 ok(0, "unexpected call\n");
640 return E_NOTIMPL;
641 }
642
643 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface, DWORD *grfBINDF, BINDINFO *pbindinfo)
644 {
645 ok(0, "unexpected call\n");
646 return E_NOTIMPL;
647 }
648
649 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF,
650 DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed)
651 {
652 ok(0, "unexpected call\n");
653 return E_NOTIMPL;
654 }
655
656 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface, REFIID riid, IUnknown *punk)
657 {
658 ok(0, "unexpected call\n");
659 return E_NOTIMPL;
660 }
661
662 static IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
663 BindStatusCallback_QueryInterface,
664 BindStatusCallback_AddRef,
665 BindStatusCallback_Release,
666 BindStatusCallback_OnStartBinding,
667 BindStatusCallback_GetPriority,
668 BindStatusCallback_OnLowResource,
669 BindStatusCallback_OnProgress,
670 BindStatusCallback_OnStopBinding,
671 BindStatusCallback_GetBindInfo,
672 BindStatusCallback_OnDataAvailable,
673 BindStatusCallback_OnObjectAvailable
674 };
675
676 static IBindStatusCallback BindStatusCallback = { &BindStatusCallbackVtbl };
677
678 static HRESULT WINAPI Moniker_QueryInterface(IMoniker *iface, REFIID riid, void **ppv)
679 {
680 *ppv = NULL;
681
682 ok(0, "unexpected riid: %s\n", debugstr_guid(riid));
683 return E_NOINTERFACE;
684 }
685
686 static ULONG WINAPI Moniker_AddRef(IMoniker *iface)
687 {
688 return 2;
689 }
690
691 static ULONG WINAPI Moniker_Release(IMoniker *iface)
692 {
693 return 1;
694 }
695
696 static HRESULT WINAPI Moniker_GetClassID(IMoniker *iface, CLSID *pClassID)
697 {
698 ok(0, "unexpected call\n");
699 return E_NOTIMPL;
700 }
701
702 static HRESULT WINAPI Moniker_IsDirty(IMoniker *iface)
703 {
704 ok(0, "unexpected call\n");
705 return E_NOTIMPL;
706 }
707
708 static HRESULT WINAPI Moniker_Load(IMoniker *iface, IStream *pStm)
709 {
710 ok(0, "unexpected call\n");
711 return E_NOTIMPL;
712 }
713
714 static HRESULT WINAPI Moniker_Save(IMoniker *iface, IStream *pStm, BOOL fClearDirty)
715 {
716 ok(0, "unexpected call\n");
717 return E_NOTIMPL;
718 }
719
720 static HRESULT WINAPI Moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *pcbSize)
721 {
722 ok(0, "unexpected call\n");
723 return E_NOTIMPL;
724 }
725
726 static HRESULT WINAPI Moniker_BindToObject(IMoniker *iface, IBindCtx *pcb, IMoniker *pmkToLeft,
727 REFIID riidResult, void **ppvResult)
728 {
729 ok(0, "unexpected call\n");
730 return E_NOTIMPL;
731 }
732
733 static HRESULT WINAPI Moniker_BindToStorage(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
734 REFIID riid, void **ppv)
735 {
736 IUnknown *unk;
737 HRESULT hres;
738
739 static OLECHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
740
741 CHECK_EXPECT(BindToStorage);
742
743 ok(pbc == _bctx, "pbc != _bctx\n");
744 ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
745 ok(IsEqualGUID(&IID_IUnknown, riid), "unexpected riid %s\n", debugstr_guid(riid));
746 ok(ppv != NULL, "ppv == NULL\n");
747 ok(*ppv == NULL, "*ppv=%p\n", *ppv);
748
749 hres = IBindCtx_GetObjectParam(pbc, BSCBHolder, &unk);
750 ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
751 ok(unk != NULL, "unk == NULL\n");
752
753 IUnknown_Release(unk);
754
755 return S_OK;
756 }
757
758 static HRESULT WINAPI Moniker_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD dwReduceHowFar,
759 IMoniker **ppmkToLeft, IMoniker **ppmkReduced)
760 {
761 ok(0, "unexpected call\n");
762 return E_NOTIMPL;
763 }
764
765 static HRESULT WINAPI Moniker_ComposeWith(IMoniker *iface, IMoniker *pmkRight,
766 BOOL fOnlyIfNotGeneric, IMoniker **ppnkComposite)
767 {
768 ok(0, "unexpected call\n");
769 return E_NOTIMPL;
770 }
771
772 static HRESULT WINAPI Moniker_Enum(IMoniker *iface, BOOL fForwrd, IEnumMoniker **ppenumMoniker)
773 {
774 ok(0, "unexpected call\n");
775 return E_NOTIMPL;
776 }
777
778 static HRESULT WINAPI Moniker_IsEqual(IMoniker *iface, IMoniker *pmkOtherMoniker)
779 {
780 ok(0, "unexpected call\n");
781 return E_NOTIMPL;
782 }
783
784 static HRESULT WINAPI Moniker_Hash(IMoniker *iface, DWORD *pdwHash)
785 {
786 ok(0, "unexpected call\n");
787 return E_NOTIMPL;
788 }
789
790 static HRESULT WINAPI Moniker_IsRunning(IMoniker *iface, IBindCtx *pbc, IMoniker *pmkToLeft,
791 IMoniker *pmkNewlyRunning)
792 {
793 ok(0, "unexpected call\n");
794 return E_NOTIMPL;
795 }
796
797 static HRESULT WINAPI Moniker_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
798 IMoniker *pmkToLeft, FILETIME *pFileTime)
799 {
800 ok(0, "unexpected call\n");
801 return E_NOTIMPL;
802 }
803
804 static HRESULT WINAPI Moniker_Inverse(IMoniker *iface, IMoniker **ppmk)
805 {
806 ok(0, "unexpected call\n");
807 return E_NOTIMPL;
808 }
809
810 static HRESULT WINAPI Moniker_CommonPrefixWith(IMoniker *iface, IMoniker *pmkOther,
811 IMoniker **ppmkPrefix)
812 {
813 ok(0, "unexpected call\n");
814 return E_NOTIMPL;
815 }
816
817 static HRESULT WINAPI Moniker_RelativePathTo(IMoniker *iface, IMoniker *pmkOther,
818 IMoniker **pmkRelPath)
819 {
820 ok(0, "unexpected call\n");
821 return E_NOTIMPL;
822 }
823
824 static HRESULT WINAPI Moniker_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
825 IMoniker *pmkToLeft, LPOLESTR *ppszDisplayName)
826 {
827 static const WCHAR winehq_urlW[] =
828 {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g',
829 '/','s','i','t','e','/','a','b','o','u','t',0};
830
831 CHECK_EXPECT(GetDisplayName);
832
833 ok(pbc != NULL, "pbc == NULL\n");
834 ok(pbc != _bctx, "pbc == _bctx\n");
835 ok(pmkToLeft == NULL, "pmkToLeft=%p\n", pmkToLeft);
836
837 *ppszDisplayName = CoTaskMemAlloc(sizeof(winehq_urlW));
838 memcpy(*ppszDisplayName, winehq_urlW, sizeof(winehq_urlW));
839 return S_OK;
840 }
841
842 static HRESULT WINAPI Moniker_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
843 IMoniker *pmkToLeft, LPOLESTR pszDisplayName, ULONG *pchEaten, IMoniker **ppmkOut)
844 {
845 ok(0, "unexpected call\n");
846 return E_NOTIMPL;
847 }
848
849 static HRESULT WINAPI Moniker_IsSystemMoniker(IMoniker *iface, DWORD *pdwMksys)
850 {
851 CHECK_EXPECT2(IsSystemMoniker);
852
853 *pdwMksys = MKSYS_URLMONIKER;
854 return S_OK;
855 }
856
857 static IMonikerVtbl MonikerVtbl = {
858 Moniker_QueryInterface,
859 Moniker_AddRef,
860 Moniker_Release,
861 Moniker_GetClassID,
862 Moniker_IsDirty,
863 Moniker_Load,
864 Moniker_Save,
865 Moniker_GetSizeMax,
866 Moniker_BindToObject,
867 Moniker_BindToStorage,
868 Moniker_Reduce,
869 Moniker_ComposeWith,
870 Moniker_Enum,
871 Moniker_IsEqual,
872 Moniker_Hash,
873 Moniker_IsRunning,
874 Moniker_GetTimeOfLastChange,
875 Moniker_Inverse,
876 Moniker_CommonPrefixWith,
877 Moniker_RelativePathTo,
878 Moniker_GetDisplayName,
879 Moniker_ParseDisplayName,
880 Moniker_IsSystemMoniker
881 };
882
883 static IMoniker Moniker = { &MonikerVtbl };
884
885 static void test_HlinkResolveMonikerForData(void)
886 {
887 IBindCtx *bctx;
888 HRESULT hres;
889
890 CreateBindCtx(0, &bctx);
891 _bctx = bctx;
892
893 SET_EXPECT(IsSystemMoniker);
894 SET_EXPECT(GetDisplayName);
895 SET_EXPECT(BindToStorage);
896
897 hres = HlinkResolveMonikerForData(&Moniker, 0, bctx, 0, NULL, &BindStatusCallback, NULL);
898 ok(hres == S_OK, "HlinkResolveMonikerForData failed: %08x\n", hres);
899
900 CHECK_CALLED(IsSystemMoniker);
901 CHECK_CALLED(GetDisplayName);
902 CHECK_CALLED(BindToStorage);
903
904 IBindCtx_Release(bctx);
905 }
906
907 START_TEST(hlink)
908 {
909 CoInitialize(NULL);
910
911 test_HlinkIsShortcut();
912 test_reference();
913 test_persist();
914 test_special_reference();
915 test_HlinkCreateExtensionServices();
916 test_HlinkParseDisplayName();
917 test_HlinkResolveMonikerForData();
918
919 CoUninitialize();
920 }