Sync with trunk r58687.
[reactos.git] / dll / win32 / shdocvw / intshcut.c
1 /*
2 * Copyright 2008 Damjan Jovanovic
3 *
4 * ShellLink's barely documented cousin that handles URLs.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 /*
22 * TODO:
23 * Implement the IShellLinkA/W interfaces
24 * Handle the SetURL flags
25 * Implement any other interfaces? Does any software actually use them?
26 *
27 * The installer for the Zuma Deluxe Popcap game is good for testing.
28 */
29
30 //#include <stdarg.h>
31 //#include <stdio.h>
32
33 #include <wine/debug.h>
34 #include "shdocvw.h"
35 //#include "objidl.h"
36 //#include "shobjidl.h"
37 #include <intshcut.h>
38 //#include "shellapi.h"
39 //#include "winreg.h"
40 //#include "shlwapi.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
43
44 typedef struct
45 {
46 IUniformResourceLocatorA uniformResourceLocatorA;
47 IUniformResourceLocatorW uniformResourceLocatorW;
48 IPersistFile persistFile;
49
50 LONG refCount;
51
52 WCHAR *url;
53 BOOLEAN isDirty;
54 LPOLESTR currentFile;
55 } InternetShortcut;
56
57 /* utility functions */
58
59 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
60 {
61 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, uniformResourceLocatorA));
62 }
63
64 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
65 {
66 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, uniformResourceLocatorW));
67 }
68
69 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
70 {
71 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, persistFile));
72 }
73
74 static BOOL run_winemenubuilder( const WCHAR *args )
75 {
76 static const WCHAR menubuilder[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0};
77 LONG len;
78 LPWSTR buffer;
79 STARTUPINFOW si;
80 PROCESS_INFORMATION pi;
81 BOOL ret;
82 WCHAR app[MAX_PATH];
83 void *redir;
84
85 GetSystemDirectoryW( app, MAX_PATH - sizeof(menubuilder)/sizeof(WCHAR) );
86 strcatW( app, menubuilder );
87
88 len = (strlenW( app ) + strlenW( args ) + 1) * sizeof(WCHAR);
89 buffer = heap_alloc( len );
90 if( !buffer )
91 return FALSE;
92
93 strcpyW( buffer, app );
94 strcatW( buffer, args );
95
96 TRACE("starting %s\n",debugstr_w(buffer));
97
98 memset(&si, 0, sizeof(si));
99 si.cb = sizeof(si);
100
101 Wow64DisableWow64FsRedirection( &redir );
102 ret = CreateProcessW( app, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
103 Wow64RevertWow64FsRedirection( redir );
104
105 heap_free( buffer );
106
107 if (ret)
108 {
109 CloseHandle( pi.hProcess );
110 CloseHandle( pi.hThread );
111 }
112
113 return ret;
114 }
115
116 static BOOL StartLinkProcessor( LPCOLESTR szLink )
117 {
118 static const WCHAR szFormat[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
119 LONG len;
120 LPWSTR buffer;
121 BOOL ret;
122
123 len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
124 buffer = heap_alloc( len );
125 if( !buffer )
126 return FALSE;
127
128 wsprintfW( buffer, szFormat, szLink );
129 ret = run_winemenubuilder( buffer );
130 heap_free( buffer );
131 return ret;
132 }
133
134 /* interface functions */
135
136 static HRESULT Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
137 {
138 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
139 *ppvObject = NULL;
140 if (IsEqualGUID(&IID_IUnknown, riid))
141 *ppvObject = &This->uniformResourceLocatorA;
142 else if (IsEqualGUID(&IID_IUniformResourceLocatorA, riid))
143 *ppvObject = &This->uniformResourceLocatorA;
144 else if (IsEqualGUID(&IID_IUniformResourceLocatorW, riid))
145 *ppvObject = &This->uniformResourceLocatorW;
146 else if (IsEqualGUID(&IID_IPersistFile, riid))
147 *ppvObject = &This->persistFile;
148 else if (IsEqualGUID(&IID_IShellLinkA, riid))
149 {
150 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
151 return E_NOINTERFACE;
152 }
153 else if (IsEqualGUID(&IID_IShellLinkW, riid))
154 {
155 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
156 return E_NOINTERFACE;
157 }
158 else
159 {
160 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
161 return E_NOINTERFACE;
162 }
163 IUnknown_AddRef((IUnknown*)*ppvObject);
164 return S_OK;
165 }
166
167 static ULONG Unknown_AddRef(InternetShortcut *This)
168 {
169 TRACE("(%p)\n", This);
170 return InterlockedIncrement(&This->refCount);
171 }
172
173 static ULONG Unknown_Release(InternetShortcut *This)
174 {
175 ULONG count;
176 TRACE("(%p)\n", This);
177 count = InterlockedDecrement(&This->refCount);
178 if (count == 0)
179 {
180 CoTaskMemFree(This->url);
181 CoTaskMemFree(This->currentFile);
182 heap_free(This);
183 SHDOCVW_UnlockModule();
184 }
185 return count;
186 }
187
188 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
189 {
190 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
191 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
192 return Unknown_QueryInterface(This, riid, ppvObject);
193 }
194
195 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
196 {
197 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
198 TRACE("(%p)\n", url);
199 return Unknown_AddRef(This);
200 }
201
202 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
203 {
204 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
205 TRACE("(%p)\n", url);
206 return Unknown_Release(This);
207 }
208
209 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
210 {
211 WCHAR *newURL = NULL;
212 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
213 TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags);
214 if (dwInFlags != 0)
215 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
216 if (pcszURL != NULL)
217 {
218 newURL = co_strdupW(pcszURL);
219 if (newURL == NULL)
220 return E_OUTOFMEMORY;
221 }
222 CoTaskMemFree(This->url);
223 This->url = newURL;
224 This->isDirty = TRUE;
225 return S_OK;
226 }
227
228 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
229 {
230 HRESULT hr = S_OK;
231 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
232 TRACE("(%p, %p)\n", url, ppszURL);
233 if (This->url == NULL)
234 *ppszURL = NULL;
235 else
236 {
237 *ppszURL = co_strdupW(This->url);
238 if (*ppszURL == NULL)
239 hr = E_OUTOFMEMORY;
240 }
241 return hr;
242 }
243
244 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
245 {
246 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
247 WCHAR app[64];
248 HKEY hkey;
249 static const WCHAR wszURLProtocol[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0};
250 SHELLEXECUTEINFOW sei;
251 DWORD res, type;
252 HRESULT hres;
253
254 TRACE("%p %p\n", This, pCommandInfo );
255
256 if (pCommandInfo->dwcbSize < sizeof (URLINVOKECOMMANDINFOW))
257 return E_INVALIDARG;
258
259 if (pCommandInfo->dwFlags != IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB)
260 {
261 FIXME("(%p, %p): non-default verbs not implemented\n", url, pCommandInfo);
262 return E_NOTIMPL;
263 }
264
265 hres = CoInternetParseUrl(This->url, PARSE_SCHEMA, 0, app, sizeof(app)/sizeof(WCHAR), NULL, 0);
266 if(FAILED(hres))
267 return E_FAIL;
268
269 res = RegOpenKeyW(HKEY_CLASSES_ROOT, app, &hkey);
270 if(res != ERROR_SUCCESS)
271 return E_FAIL;
272
273 res = RegQueryValueExW(hkey, wszURLProtocol, NULL, &type, NULL, NULL);
274 RegCloseKey(hkey);
275 if(res != ERROR_SUCCESS || type != REG_SZ)
276 return E_FAIL;
277
278 memset(&sei, 0, sizeof(sei));
279 sei.cbSize = sizeof(sei);
280 sei.lpFile = This->url;
281 sei.nShow = SW_SHOW;
282
283 if( ShellExecuteExW(&sei) )
284 return S_OK;
285 else
286 return E_FAIL;
287 }
288
289 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
290 {
291 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
292 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
293 return Unknown_QueryInterface(This, riid, ppvObject);
294 }
295
296 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
297 {
298 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
299 TRACE("(%p)\n", url);
300 return Unknown_AddRef(This);
301 }
302
303 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
304 {
305 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
306 TRACE("(%p)\n", url);
307 return Unknown_Release(This);
308 }
309
310 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
311 {
312 WCHAR *newURL = NULL;
313 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
314 TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags);
315 if (dwInFlags != 0)
316 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
317 if (pcszURL != NULL)
318 {
319 newURL = co_strdupAtoW(pcszURL);
320 if (newURL == NULL)
321 return E_OUTOFMEMORY;
322 }
323 CoTaskMemFree(This->url);
324 This->url = newURL;
325 This->isDirty = TRUE;
326 return S_OK;
327 }
328
329 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
330 {
331 HRESULT hr = S_OK;
332 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
333 TRACE("(%p, %p)\n", url, ppszURL);
334 if (This->url == NULL)
335 *ppszURL = NULL;
336 else
337 {
338 *ppszURL = co_strdupWtoA(This->url);
339 if (*ppszURL == NULL)
340 hr = E_OUTOFMEMORY;
341 }
342 return hr;
343 }
344
345 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
346 {
347 URLINVOKECOMMANDINFOW wideCommandInfo;
348 int len;
349 WCHAR *wideVerb;
350 HRESULT res;
351 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
352
353 wideCommandInfo.dwcbSize = sizeof wideCommandInfo;
354 wideCommandInfo.dwFlags = pCommandInfo->dwFlags;
355 wideCommandInfo.hwndParent = pCommandInfo->hwndParent;
356
357 len = MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, NULL, 0);
358 wideVerb = heap_alloc(len * sizeof(WCHAR));
359 MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, wideVerb, len);
360
361 wideCommandInfo.pcszVerb = wideVerb;
362
363 res = UniformResourceLocatorW_InvokeCommand(&This->uniformResourceLocatorW, &wideCommandInfo);
364 heap_free(wideVerb);
365
366 return res;
367 }
368
369 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
370 {
371 InternetShortcut *This = impl_from_IPersistFile(pFile);
372 TRACE("(%p, %s, %p)\n", pFile, debugstr_guid(riid), ppvObject);
373 return Unknown_QueryInterface(This, riid, ppvObject);
374 }
375
376 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
377 {
378 InternetShortcut *This = impl_from_IPersistFile(pFile);
379 TRACE("(%p)\n", pFile);
380 return Unknown_AddRef(This);
381 }
382
383 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
384 {
385 InternetShortcut *This = impl_from_IPersistFile(pFile);
386 TRACE("(%p)\n", pFile);
387 return Unknown_Release(This);
388 }
389
390 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
391 {
392 TRACE("(%p, %p)\n", pFile, pClassID);
393 *pClassID = CLSID_InternetShortcut;
394 return S_OK;
395 }
396
397 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
398 {
399 InternetShortcut *This = impl_from_IPersistFile(pFile);
400 TRACE("(%p)\n", pFile);
401 return This->isDirty ? S_OK : S_FALSE;
402 }
403
404 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
405 {
406 WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
407 WCHAR str_URL[] = {'U','R','L',0};
408 WCHAR *filename = NULL;
409 HRESULT hr;
410 InternetShortcut *This = impl_from_IPersistFile(pFile);
411 TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode);
412 if (dwMode != 0)
413 FIXME("ignoring unimplemented mode 0x%x\n", dwMode);
414 filename = co_strdupW(pszFileName);
415 if (filename != NULL)
416 {
417 DWORD len = 128;
418 DWORD r;
419 WCHAR *url = CoTaskMemAlloc(len*sizeof(WCHAR));
420 if (url != NULL)
421 {
422 r = GetPrivateProfileStringW(str_header, str_URL, NULL, url, len, pszFileName);
423 while (r == len-1)
424 {
425 CoTaskMemFree(url);
426 len *= 2;
427 url = CoTaskMemAlloc(len*sizeof(WCHAR));
428 if (url == NULL)
429 break;
430 r = GetPrivateProfileStringW(str_header, str_URL, NULL, url, len, pszFileName);
431 }
432 if (r == 0)
433 hr = E_FAIL;
434 else if (url != NULL)
435 {
436 CoTaskMemFree(This->currentFile);
437 This->currentFile = filename;
438 CoTaskMemFree(This->url);
439 This->url = url;
440 This->isDirty = FALSE;
441 return S_OK;
442 }
443 else
444 hr = E_OUTOFMEMORY;
445 CoTaskMemFree(url);
446 }
447 else
448 hr = E_OUTOFMEMORY;
449 CoTaskMemFree(filename);
450 }
451 else
452 hr = E_OUTOFMEMORY;
453 return hr;
454 }
455
456 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
457 {
458 HRESULT hr = S_OK;
459 INT len;
460 CHAR *url;
461 InternetShortcut *This = impl_from_IPersistFile(pFile);
462
463 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
464
465 if (pszFileName != NULL && fRemember)
466 {
467 LPOLESTR oldFile = This->currentFile;
468 This->currentFile = co_strdupW(pszFileName);
469 if (This->currentFile == NULL)
470 {
471 This->currentFile = oldFile;
472 return E_OUTOFMEMORY;
473 }
474 CoTaskMemFree(oldFile);
475 }
476 if (This->url == NULL)
477 return E_FAIL;
478
479 /* Windows seems to always write:
480 * ASCII "[InternetShortcut]" headers
481 * ASCII names in "name=value" pairs
482 * An ASCII (probably UTF8?) value in "URL=..."
483 */
484 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
485 url = heap_alloc(len);
486 if (url != NULL)
487 {
488 HANDLE file;
489 WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0);
490 file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
491 if (file != INVALID_HANDLE_VALUE)
492 {
493 DWORD bytesWritten;
494 char str_header[] = "[InternetShortcut]";
495 char str_URL[] = "URL=";
496 char str_eol[] = "\r\n";
497
498 WriteFile(file, str_header, lstrlenA(str_header), &bytesWritten, NULL);
499 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
500 WriteFile(file, str_URL, lstrlenA(str_URL), &bytesWritten, NULL);
501 WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL);
502 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
503 CloseHandle(file);
504 if (pszFileName == NULL || fRemember)
505 This->isDirty = FALSE;
506 StartLinkProcessor(pszFileName);
507 }
508 else
509 hr = E_FAIL;
510 heap_free(url);
511 }
512 else
513 hr = E_OUTOFMEMORY;
514
515 return hr;
516 }
517
518 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
519 {
520 FIXME("(%p, %p): stub\n", pFile, pszFileName);
521 return E_NOTIMPL;
522 }
523
524 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
525 {
526 HRESULT hr = S_OK;
527 InternetShortcut *This = impl_from_IPersistFile(pFile);
528 TRACE("(%p, %p)\n", pFile, ppszFileName);
529 if (This->currentFile == NULL)
530 *ppszFileName = NULL;
531 else
532 {
533 *ppszFileName = co_strdupW(This->currentFile);
534 if (*ppszFileName == NULL)
535 hr = E_OUTOFMEMORY;
536 }
537 return hr;
538 }
539
540
541
542 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
543 UniformResourceLocatorW_QueryInterface,
544 UniformResourceLocatorW_AddRef,
545 UniformResourceLocatorW_Release,
546 UniformResourceLocatorW_SetUrl,
547 UniformResourceLocatorW_GetUrl,
548 UniformResourceLocatorW_InvokeCommand
549 };
550
551 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
552 UniformResourceLocatorA_QueryInterface,
553 UniformResourceLocatorA_AddRef,
554 UniformResourceLocatorA_Release,
555 UniformResourceLocatorA_SetUrl,
556 UniformResourceLocatorA_GetUrl,
557 UniformResourceLocatorA_InvokeCommand
558 };
559
560 static const IPersistFileVtbl persistFileVtbl = {
561 PersistFile_QueryInterface,
562 PersistFile_AddRef,
563 PersistFile_Release,
564 PersistFile_GetClassID,
565 PersistFile_IsDirty,
566 PersistFile_Load,
567 PersistFile_Save,
568 PersistFile_SaveCompleted,
569 PersistFile_GetCurFile
570 };
571
572 static InternetShortcut *create_shortcut(void)
573 {
574 InternetShortcut *newshortcut;
575
576 newshortcut = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
577 if (newshortcut)
578 {
579 newshortcut->uniformResourceLocatorA.lpVtbl = &uniformResourceLocatorAVtbl;
580 newshortcut->uniformResourceLocatorW.lpVtbl = &uniformResourceLocatorWVtbl;
581 newshortcut->persistFile.lpVtbl = &persistFileVtbl;
582 newshortcut->refCount = 0;
583 }
584
585 return newshortcut;
586 }
587
588 HRESULT InternetShortcut_Create(IUnknown *pOuter, REFIID riid, void **ppv)
589 {
590 InternetShortcut *This;
591 HRESULT hr;
592
593 TRACE("(%p, %s, %p)\n", pOuter, debugstr_guid(riid), ppv);
594
595 *ppv = NULL;
596
597 if(pOuter)
598 return CLASS_E_NOAGGREGATION;
599
600 This = create_shortcut();
601 if (This)
602 {
603 hr = Unknown_QueryInterface(This, riid, ppv);
604 if (SUCCEEDED(hr))
605 SHDOCVW_LockModule();
606 else
607 heap_free(This);
608 return hr;
609 }
610 else
611 return E_OUTOFMEMORY;
612 }
613
614
615 /**********************************************************************
616 * OpenURL (SHDOCVW.@)
617 */
618 void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd)
619 {
620 InternetShortcut *shortcut;
621 WCHAR* urlfilepath = NULL;
622 shortcut = create_shortcut();
623
624 if (shortcut)
625 {
626 int len;
627
628 len = MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, NULL, 0);
629 urlfilepath = heap_alloc(len * sizeof(WCHAR));
630 MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, urlfilepath, len);
631
632 if(SUCCEEDED(IPersistFile_Load(&shortcut->persistFile, urlfilepath, 0)))
633 {
634 URLINVOKECOMMANDINFOW ici;
635
636 memset( &ici, 0, sizeof ici );
637 ici.dwcbSize = sizeof ici;
638 ici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
639 ici.hwndParent = hWnd;
640
641 if FAILED(UniformResourceLocatorW_InvokeCommand(&shortcut->uniformResourceLocatorW, (PURLINVOKECOMMANDINFOW) &ici))
642 TRACE("failed to open URL: %s\n.",debugstr_a(lpcstrUrl));
643 }
644
645 heap_free(shortcut);
646 heap_free(urlfilepath);
647 }
648 }