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
);