2 * Copyright 2008 Damjan Jovanovic
4 * ShellLink's barely documented cousin that handles URLs.
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.
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.
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
23 * Implement the IShellLinkA/W interfaces
24 * Handle the SetURL flags
25 * Implement any other interfaces? Does any software actually use them?
27 * The installer for the Zuma Deluxe Popcap game is good for testing.
33 #define NONAMELESSUNION
34 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
47 IUniformResourceLocatorA uniformResourceLocatorA;
48 IUniformResourceLocatorW uniformResourceLocatorW;
49 IPersistFile persistFile;
50 IPropertySetStorage IPropertySetStorage_iface;
54 IPropertySetStorage *property_set_storage;
60 /* utility functions */
62 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
64 return CONTAINING_RECORD(iface, InternetShortcut, uniformResourceLocatorA);
67 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
69 return CONTAINING_RECORD(iface, InternetShortcut, uniformResourceLocatorW);
72 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
74 return CONTAINING_RECORD(iface, InternetShortcut, persistFile);
77 static inline InternetShortcut* impl_from_IPropertySetStorage(IPropertySetStorage *iface)
79 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, IPropertySetStorage_iface));
82 static BOOL run_winemenubuilder( const WCHAR *args )
84 static const WCHAR menubuilder[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0};
88 PROCESS_INFORMATION pi;
93 GetSystemDirectoryW( app, MAX_PATH - sizeof(menubuilder)/sizeof(WCHAR) );
94 strcatW( app, menubuilder );
96 len = (strlenW( app ) + strlenW( args ) + 1) * sizeof(WCHAR);
97 buffer = heap_alloc( len );
101 strcpyW( buffer, app );
102 strcatW( buffer, args );
104 TRACE("starting %s\n",debugstr_w(buffer));
106 memset(&si, 0, sizeof(si));
109 Wow64DisableWow64FsRedirection( &redir );
110 ret = CreateProcessW( app, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
111 Wow64RevertWow64FsRedirection( redir );
117 CloseHandle( pi.hProcess );
118 CloseHandle( pi.hThread );
124 static BOOL StartLinkProcessor( LPCOLESTR szLink )
126 static const WCHAR szFormat[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
131 len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
132 buffer = heap_alloc( len );
136 wsprintfW( buffer, szFormat, szLink );
137 ret = run_winemenubuilder( buffer );
142 /* interface functions */
144 static HRESULT Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
146 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
148 if (IsEqualGUID(&IID_IUnknown, riid))
149 *ppvObject = &This->uniformResourceLocatorA;
150 else if (IsEqualGUID(&IID_IUniformResourceLocatorA, riid))
151 *ppvObject = &This->uniformResourceLocatorA;
152 else if (IsEqualGUID(&IID_IUniformResourceLocatorW, riid))
153 *ppvObject = &This->uniformResourceLocatorW;
154 else if (IsEqualGUID(&IID_IPersistFile, riid))
155 *ppvObject = &This->persistFile;
156 else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
157 *ppvObject = &This->IPropertySetStorage_iface;
158 else if (IsEqualGUID(&IID_IShellLinkA, riid))
160 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
161 return E_NOINTERFACE;
163 else if (IsEqualGUID(&IID_IShellLinkW, riid))
165 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
166 return E_NOINTERFACE;
170 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
171 return E_NOINTERFACE;
173 IUnknown_AddRef((IUnknown*)*ppvObject);
177 static ULONG Unknown_AddRef(InternetShortcut *This)
179 TRACE("(%p)\n", This);
180 return InterlockedIncrement(&This->refCount);
183 static ULONG Unknown_Release(InternetShortcut *This)
186 TRACE("(%p)\n", This);
187 count = InterlockedDecrement(&This->refCount);
190 CoTaskMemFree(This->url);
191 CoTaskMemFree(This->currentFile);
192 IPropertySetStorage_Release(This->property_set_storage);
194 SHDOCVW_UnlockModule();
199 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
201 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
202 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
203 return Unknown_QueryInterface(This, riid, ppvObject);
206 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
208 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
209 TRACE("(%p)\n", url);
210 return Unknown_AddRef(This);
213 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
215 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
216 TRACE("(%p)\n", url);
217 return Unknown_Release(This);
220 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
222 WCHAR *newURL = NULL;
223 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
224 TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags);
226 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
229 newURL = co_strdupW(pcszURL);
231 return E_OUTOFMEMORY;
233 CoTaskMemFree(This->url);
235 This->isDirty = TRUE;
239 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
242 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
243 TRACE("(%p, %p)\n", url, ppszURL);
244 if (This->url == NULL)
248 *ppszURL = co_strdupW(This->url);
249 if (*ppszURL == NULL)
255 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
257 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
260 static const WCHAR wszURLProtocol[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0};
261 SHELLEXECUTEINFOW sei;
265 TRACE("%p %p\n", This, pCommandInfo );
267 if (pCommandInfo->dwcbSize < sizeof (URLINVOKECOMMANDINFOW))
270 if (pCommandInfo->dwFlags != IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB)
272 FIXME("(%p, %p): non-default verbs not implemented\n", url, pCommandInfo);
276 hres = CoInternetParseUrl(This->url, PARSE_SCHEMA, 0, app, sizeof(app)/sizeof(WCHAR), NULL, 0);
280 res = RegOpenKeyW(HKEY_CLASSES_ROOT, app, &hkey);
281 if(res != ERROR_SUCCESS)
284 res = RegQueryValueExW(hkey, wszURLProtocol, NULL, &type, NULL, NULL);
286 if(res != ERROR_SUCCESS || type != REG_SZ)
289 memset(&sei, 0, sizeof(sei));
290 sei.cbSize = sizeof(sei);
291 sei.lpFile = This->url;
294 if( ShellExecuteExW(&sei) )
300 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
302 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
303 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
304 return Unknown_QueryInterface(This, riid, ppvObject);
307 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
309 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
310 TRACE("(%p)\n", url);
311 return Unknown_AddRef(This);
314 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
316 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
317 TRACE("(%p)\n", url);
318 return Unknown_Release(This);
321 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
323 WCHAR *newURL = NULL;
324 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
325 TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags);
327 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
330 newURL = co_strdupAtoW(pcszURL);
332 return E_OUTOFMEMORY;
334 CoTaskMemFree(This->url);
336 This->isDirty = TRUE;
340 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
343 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
344 TRACE("(%p, %p)\n", url, ppszURL);
345 if (This->url == NULL)
349 *ppszURL = co_strdupWtoA(This->url);
350 if (*ppszURL == NULL)
356 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
358 URLINVOKECOMMANDINFOW wideCommandInfo;
362 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
364 wideCommandInfo.dwcbSize = sizeof wideCommandInfo;
365 wideCommandInfo.dwFlags = pCommandInfo->dwFlags;
366 wideCommandInfo.hwndParent = pCommandInfo->hwndParent;
368 len = MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, NULL, 0);
369 wideVerb = heap_alloc(len * sizeof(WCHAR));
370 MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, wideVerb, len);
372 wideCommandInfo.pcszVerb = wideVerb;
374 res = UniformResourceLocatorW_InvokeCommand(&This->uniformResourceLocatorW, &wideCommandInfo);
380 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
382 InternetShortcut *This = impl_from_IPersistFile(pFile);
383 TRACE("(%p, %s, %p)\n", pFile, debugstr_guid(riid), ppvObject);
384 return Unknown_QueryInterface(This, riid, ppvObject);
387 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
389 InternetShortcut *This = impl_from_IPersistFile(pFile);
390 TRACE("(%p)\n", pFile);
391 return Unknown_AddRef(This);
394 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
396 InternetShortcut *This = impl_from_IPersistFile(pFile);
397 TRACE("(%p)\n", pFile);
398 return Unknown_Release(This);
401 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
403 TRACE("(%p, %p)\n", pFile, pClassID);
404 *pClassID = CLSID_InternetShortcut;
408 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
410 InternetShortcut *This = impl_from_IPersistFile(pFile);
411 TRACE("(%p)\n", pFile);
412 return This->isDirty ? S_OK : S_FALSE;
415 /* A helper function: Allocate and fill rString. Return number of bytes read. */
416 static DWORD get_profile_string(LPCWSTR lpAppName, LPCWSTR lpKeyName,
417 LPCWSTR lpFileName, WCHAR **rString )
423 buffer = CoTaskMemAlloc(len * sizeof(*buffer));
426 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
432 realloc_buf = CoTaskMemRealloc(buffer, len * sizeof(*buffer));
433 if (realloc_buf == NULL)
435 CoTaskMemFree(buffer);
439 buffer = realloc_buf;
441 r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
449 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
451 WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
452 WCHAR str_URL[] = {'U','R','L',0};
453 WCHAR str_iconfile[] = {'i','c','o','n','f','i','l','e',0};
454 WCHAR str_iconindex[] = {'i','c','o','n','i','n','d','e','x',0};
455 WCHAR *filename = NULL;
457 InternetShortcut *This = impl_from_IPersistFile(pFile);
458 TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode);
460 FIXME("ignoring unimplemented mode 0x%x\n", dwMode);
461 filename = co_strdupW(pszFileName);
462 if (filename != NULL)
467 r = get_profile_string(str_header, str_URL, pszFileName, &url);
472 CoTaskMemFree(filename);
477 CoTaskMemFree(filename);
482 CoTaskMemFree(This->currentFile);
483 This->currentFile = filename;
484 CoTaskMemFree(This->url);
486 This->isDirty = FALSE;
489 /* Now we're going to read in the iconfile and iconindex.
490 If we don't find them, that's not a failure case -- it's possible
491 that they just aren't in there. */
494 IPropertyStorage *pPropStg;
496 WCHAR *iconindexstring;
497 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut,
498 STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
501 r = get_profile_string(str_header, str_iconfile, pszFileName, &iconfile);
502 if (iconfile != NULL)
506 ps.ulKind = PRSPEC_PROPID;
507 ps.u.propid = PID_IS_ICONFILE;
509 pv.u.pwszVal = iconfile;
510 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
513 TRACE("Failed to store the iconfile to our property storage. hr = 0x%x\n", hr);
516 CoTaskMemFree(iconfile);
519 r = get_profile_string(str_header, str_iconindex, pszFileName, &iconindexstring);
521 if (iconindexstring != NULL)
526 char *iconindexastring = co_strdupWtoA(iconindexstring);
527 sscanf(iconindexastring, "%d", &iconindex);
528 CoTaskMemFree(iconindexastring);
529 ps.ulKind = PRSPEC_PROPID;
530 ps.u.propid = PID_IS_ICONINDEX;
532 pv.u.iVal = iconindex;
533 hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
536 TRACE("Failed to store the iconindex to our property storage. hr = 0x%x\n", hr);
539 CoTaskMemFree(iconindexstring);
542 IPropertyStorage_Release(pPropStg);
552 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
557 InternetShortcut *This = impl_from_IPersistFile(pFile);
559 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
561 if (pszFileName != NULL && fRemember)
563 LPOLESTR oldFile = This->currentFile;
564 This->currentFile = co_strdupW(pszFileName);
565 if (This->currentFile == NULL)
567 This->currentFile = oldFile;
568 return E_OUTOFMEMORY;
570 CoTaskMemFree(oldFile);
572 if (This->url == NULL)
575 /* Windows seems to always write:
576 * ASCII "[InternetShortcut]" headers
577 * ASCII names in "name=value" pairs
578 * An ASCII (probably UTF8?) value in "URL=..."
580 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
581 url = heap_alloc(len);
585 WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0);
586 file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
587 if (file != INVALID_HANDLE_VALUE)
591 char str_header[] = "[InternetShortcut]";
592 char str_URL[] = "URL=";
593 char str_ICONFILE[] = "ICONFILE=";
594 char str_eol[] = "\r\n";
595 IPropertyStorage *pPropStgRead;
597 PROPVARIANT pvread[2];
598 ps[0].ulKind = PRSPEC_PROPID;
599 ps[0].u.propid = PID_IS_ICONFILE;
600 ps[1].ulKind = PRSPEC_PROPID;
601 ps[1].u.propid = PID_IS_ICONINDEX;
603 WriteFile(file, str_header, lstrlenA(str_header), &bytesWritten, NULL);
604 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
605 WriteFile(file, str_URL, lstrlenA(str_URL), &bytesWritten, NULL);
606 WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL);
607 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
609 hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStgRead);
612 hr = IPropertyStorage_ReadMultiple(pPropStgRead, 2, ps, pvread);
615 /* None of the properties are present, that's ok */
617 IPropertyStorage_Release(pPropStgRead);
619 else if SUCCEEDED(hr)
621 char indexString[50];
622 len = WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, NULL, 0, 0, 0);
623 iconfile = heap_alloc(len);
624 if (iconfile != NULL)
626 WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, iconfile, len, 0, 0);
627 WriteFile(file, str_ICONFILE, lstrlenA(str_ICONFILE), &bytesWritten, NULL);
628 WriteFile(file, iconfile, lstrlenA(iconfile), &bytesWritten, NULL);
629 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
632 sprintf(indexString, "ICONINDEX=%d", pvread[1].u.iVal);
633 WriteFile(file, indexString, lstrlenA(indexString), &bytesWritten, NULL);
634 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
636 IPropertyStorage_Release(pPropStgRead);
637 PropVariantClear(&pvread[0]);
638 PropVariantClear(&pvread[1]);
642 TRACE("Unable to read properties.\n");
647 TRACE("Unable to get the IPropertyStorage.\n");
651 if (pszFileName == NULL || fRemember)
652 This->isDirty = FALSE;
653 StartLinkProcessor(pszFileName);
665 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
667 FIXME("(%p, %p): stub\n", pFile, pszFileName);
671 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
674 InternetShortcut *This = impl_from_IPersistFile(pFile);
675 TRACE("(%p, %p)\n", pFile, ppszFileName);
676 if (This->currentFile == NULL)
677 *ppszFileName = NULL;
680 *ppszFileName = co_strdupW(This->currentFile);
681 if (*ppszFileName == NULL)
687 static HRESULT WINAPI PropertySetStorage_QueryInterface(IPropertySetStorage *iface, REFIID riid, PVOID *ppvObject)
689 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
690 TRACE("(%p)\n", iface);
691 return Unknown_QueryInterface(This, riid, ppvObject);
694 static ULONG WINAPI PropertySetStorage_AddRef(IPropertySetStorage *iface)
696 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
697 TRACE("(%p)\n", iface);
698 return Unknown_AddRef(This);
701 static ULONG WINAPI PropertySetStorage_Release(IPropertySetStorage *iface)
703 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
704 TRACE("(%p)\n", iface);
705 return Unknown_Release(This);
708 static HRESULT WINAPI PropertySetStorage_Create(
709 IPropertySetStorage* iface,
714 IPropertyStorage **ppprstg)
716 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
717 TRACE("(%s, %p, 0x%x, 0x%x, %p)\n", debugstr_guid(rfmtid), pclsid, grfFlags, grfMode, ppprstg);
719 return IPropertySetStorage_Create(This->property_set_storage,
727 static HRESULT WINAPI PropertySetStorage_Open(
728 IPropertySetStorage* iface,
731 IPropertyStorage **ppprstg)
733 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
734 TRACE("(%s, 0x%x, %p)\n", debugstr_guid(rfmtid), grfMode, ppprstg);
736 /* Note: The |STGM_SHARE_EXCLUSIVE is to cope with a bug in the implementation. Should be fixed in ole32. */
737 return IPropertySetStorage_Open(This->property_set_storage,
739 grfMode|STGM_SHARE_EXCLUSIVE,
743 static HRESULT WINAPI PropertySetStorage_Delete(IPropertySetStorage *iface, REFFMTID rfmtid)
745 InternetShortcut *This = impl_from_IPropertySetStorage(iface);
746 TRACE("(%s)\n", debugstr_guid(rfmtid));
749 return IPropertySetStorage_Delete(This->property_set_storage,
753 static HRESULT WINAPI PropertySetStorage_Enum(IPropertySetStorage *iface, IEnumSTATPROPSETSTG **ppenum)
755 FIXME("(%p): stub\n", ppenum);
759 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
760 UniformResourceLocatorW_QueryInterface,
761 UniformResourceLocatorW_AddRef,
762 UniformResourceLocatorW_Release,
763 UniformResourceLocatorW_SetUrl,
764 UniformResourceLocatorW_GetUrl,
765 UniformResourceLocatorW_InvokeCommand
768 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
769 UniformResourceLocatorA_QueryInterface,
770 UniformResourceLocatorA_AddRef,
771 UniformResourceLocatorA_Release,
772 UniformResourceLocatorA_SetUrl,
773 UniformResourceLocatorA_GetUrl,
774 UniformResourceLocatorA_InvokeCommand
777 static const IPersistFileVtbl persistFileVtbl = {
778 PersistFile_QueryInterface,
781 PersistFile_GetClassID,
785 PersistFile_SaveCompleted,
786 PersistFile_GetCurFile
789 static const IPropertySetStorageVtbl propertySetStorageVtbl = {
790 PropertySetStorage_QueryInterface,
791 PropertySetStorage_AddRef,
792 PropertySetStorage_Release,
793 PropertySetStorage_Create,
794 PropertySetStorage_Open,
795 PropertySetStorage_Delete,
796 PropertySetStorage_Enum
799 static InternetShortcut *create_shortcut(void)
801 InternetShortcut *newshortcut;
803 newshortcut = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
807 IPropertyStorage *dummy;
809 newshortcut->uniformResourceLocatorA.lpVtbl = &uniformResourceLocatorAVtbl;
810 newshortcut->uniformResourceLocatorW.lpVtbl = &uniformResourceLocatorWVtbl;
811 newshortcut->persistFile.lpVtbl = &persistFileVtbl;
812 newshortcut->IPropertySetStorage_iface.lpVtbl = &propertySetStorageVtbl;
813 newshortcut->refCount = 0;
814 hr = StgCreateStorageEx(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, STGFMT_STORAGE, 0, NULL, NULL, &IID_IPropertySetStorage, (void **) &newshortcut->property_set_storage);
817 TRACE("Failed to create the storage object needed for the shortcut.\n");
818 heap_free(newshortcut);
822 hr = IPropertySetStorage_Create(newshortcut->property_set_storage, &FMTID_Intshcut, NULL, PROPSETFLAG_DEFAULT, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &dummy);
825 TRACE("Failed to create the property object needed for the shortcut.\n");
826 IPropertySetStorage_Release(newshortcut->property_set_storage);
827 heap_free(newshortcut);
830 IPropertySetStorage_Release(dummy);
836 HRESULT InternetShortcut_Create(IUnknown *pOuter, REFIID riid, void **ppv)
838 InternetShortcut *This;
841 TRACE("(%p, %s, %p)\n", pOuter, debugstr_guid(riid), ppv);
846 return CLASS_E_NOAGGREGATION;
848 This = create_shortcut();
851 hr = Unknown_QueryInterface(This, riid, ppv);
853 SHDOCVW_LockModule();
859 return E_OUTOFMEMORY;
863 /**********************************************************************
864 * OpenURL (SHDOCVW.@)
866 void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd)
868 InternetShortcut *shortcut;
869 WCHAR* urlfilepath = NULL;
870 shortcut = create_shortcut();
876 len = MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, NULL, 0);
877 urlfilepath = heap_alloc(len * sizeof(WCHAR));
878 MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, urlfilepath, len);
880 if(SUCCEEDED(IPersistFile_Load(&shortcut->persistFile, urlfilepath, 0)))
882 URLINVOKECOMMANDINFOW ici;
884 memset( &ici, 0, sizeof ici );
885 ici.dwcbSize = sizeof ici;
886 ici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
887 ici.hwndParent = hWnd;
889 if FAILED(UniformResourceLocatorW_InvokeCommand(&shortcut->uniformResourceLocatorW, (PURLINVOKECOMMANDINFOW) &ici))
890 TRACE("failed to open URL: %s\n", debugstr_a(lpcstrUrl));
894 heap_free(urlfilepath);