xref: /reactos/dll/win32/ieframe/intshcut.c (revision c3cabdbf)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Copyright 2008 Damjan Jovanovic
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * ShellLink's barely documented cousin that handles URLs.
5c2c66affSColin Finck  *
6c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck  * License as published by the Free Software Foundation; either
9c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck  *
11c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14c2c66affSColin Finck  * Lesser General Public License for more details.
15c2c66affSColin Finck  *
16c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck  */
20c2c66affSColin Finck 
21c2c66affSColin Finck /*
22c2c66affSColin Finck  * TODO:
23c2c66affSColin Finck  * Implement the IShellLinkA/W interfaces
24c2c66affSColin Finck  * Handle the SetURL flags
25c2c66affSColin Finck  * Implement any other interfaces? Does any software actually use them?
26c2c66affSColin Finck  *
27c2c66affSColin Finck  * The installer for the Zuma Deluxe Popcap game is good for testing.
28c2c66affSColin Finck  */
29c2c66affSColin Finck 
30fc19c80dSAmine Khaldi #include <stdio.h>
31fc19c80dSAmine Khaldi 
32fc19c80dSAmine Khaldi #define NONAMELESSUNION
33fc19c80dSAmine Khaldi 
34c2c66affSColin Finck #include "ieframe.h"
35c2c66affSColin Finck 
36fc19c80dSAmine Khaldi #include "shlobj.h"
37fc19c80dSAmine Khaldi #include "shobjidl.h"
38fc19c80dSAmine Khaldi #include "intshcut.h"
39fc19c80dSAmine Khaldi #include "shellapi.h"
40fc19c80dSAmine Khaldi #include "winreg.h"
41fc19c80dSAmine Khaldi #include "shlwapi.h"
42fc19c80dSAmine Khaldi #include "shlguid.h"
43fc19c80dSAmine Khaldi 
44fc19c80dSAmine Khaldi #include "wine/debug.h"
45fc19c80dSAmine Khaldi 
46fc19c80dSAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(ieframe);
47fc19c80dSAmine Khaldi 
48c2c66affSColin Finck typedef struct
49c2c66affSColin Finck {
50c2c66affSColin Finck     IUniformResourceLocatorA IUniformResourceLocatorA_iface;
51c2c66affSColin Finck     IUniformResourceLocatorW IUniformResourceLocatorW_iface;
52c2c66affSColin Finck     IPersistFile IPersistFile_iface;
53c2c66affSColin Finck     IPropertySetStorage IPropertySetStorage_iface;
54c2c66affSColin Finck 
55c2c66affSColin Finck     LONG refCount;
56c2c66affSColin Finck 
57c2c66affSColin Finck     IPropertySetStorage *property_set_storage;
58c2c66affSColin Finck     WCHAR *url;
59c2c66affSColin Finck     BOOLEAN isDirty;
60c2c66affSColin Finck     LPOLESTR currentFile;
61c2c66affSColin Finck } InternetShortcut;
62c2c66affSColin Finck 
63c2c66affSColin Finck /* utility functions */
64c2c66affSColin Finck 
impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA * iface)65c2c66affSColin Finck static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
66c2c66affSColin Finck {
67c2c66affSColin Finck     return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorA_iface);
68c2c66affSColin Finck }
69c2c66affSColin Finck 
impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW * iface)70c2c66affSColin Finck static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
71c2c66affSColin Finck {
72c2c66affSColin Finck     return CONTAINING_RECORD(iface, InternetShortcut, IUniformResourceLocatorW_iface);
73c2c66affSColin Finck }
74c2c66affSColin Finck 
impl_from_IPersistFile(IPersistFile * iface)75c2c66affSColin Finck static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
76c2c66affSColin Finck {
77c2c66affSColin Finck     return CONTAINING_RECORD(iface, InternetShortcut, IPersistFile_iface);
78c2c66affSColin Finck }
79c2c66affSColin Finck 
impl_from_IPropertySetStorage(IPropertySetStorage * iface)80c2c66affSColin Finck static inline InternetShortcut* impl_from_IPropertySetStorage(IPropertySetStorage *iface)
81c2c66affSColin Finck {
82c2c66affSColin Finck     return CONTAINING_RECORD(iface, InternetShortcut, IPropertySetStorage_iface);
83c2c66affSColin Finck }
84c2c66affSColin Finck 
run_winemenubuilder(const WCHAR * args)85c2c66affSColin Finck static BOOL run_winemenubuilder( const WCHAR *args )
86c2c66affSColin Finck {
87c2c66affSColin Finck     static const WCHAR menubuilder[] = {'\\','w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',0};
88c2c66affSColin Finck     LONG len;
89c2c66affSColin Finck     LPWSTR buffer;
90c2c66affSColin Finck     STARTUPINFOW si;
91c2c66affSColin Finck     PROCESS_INFORMATION pi;
92c2c66affSColin Finck     BOOL ret;
93c2c66affSColin Finck     WCHAR app[MAX_PATH];
94c2c66affSColin Finck     void *redir;
95c2c66affSColin Finck 
96336b2a45SAmine Khaldi     GetSystemDirectoryW( app, MAX_PATH - ARRAY_SIZE( menubuilder ));
97*c3cabdbfSAmine Khaldi     lstrcatW( app, menubuilder );
98c2c66affSColin Finck 
99*c3cabdbfSAmine Khaldi     len = (lstrlenW( app ) + lstrlenW( args ) + 1) * sizeof(WCHAR);
100c2c66affSColin Finck     buffer = heap_alloc( len );
101c2c66affSColin Finck     if( !buffer )
102c2c66affSColin Finck         return FALSE;
103c2c66affSColin Finck 
104*c3cabdbfSAmine Khaldi     lstrcpyW( buffer, app );
105*c3cabdbfSAmine Khaldi     lstrcatW( buffer, args );
106c2c66affSColin Finck 
107c2c66affSColin Finck     TRACE("starting %s\n",debugstr_w(buffer));
108c2c66affSColin Finck 
109c2c66affSColin Finck     memset(&si, 0, sizeof(si));
110c2c66affSColin Finck     si.cb = sizeof(si);
111c2c66affSColin Finck 
112c2c66affSColin Finck     Wow64DisableWow64FsRedirection( &redir );
113c2c66affSColin Finck     ret = CreateProcessW( app, buffer, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi );
114c2c66affSColin Finck     Wow64RevertWow64FsRedirection( redir );
115c2c66affSColin Finck 
116c2c66affSColin Finck     heap_free( buffer );
117c2c66affSColin Finck 
118c2c66affSColin Finck     if (ret)
119c2c66affSColin Finck     {
120c2c66affSColin Finck         CloseHandle( pi.hProcess );
121c2c66affSColin Finck         CloseHandle( pi.hThread );
122c2c66affSColin Finck     }
123c2c66affSColin Finck 
124c2c66affSColin Finck     return ret;
125c2c66affSColin Finck }
126c2c66affSColin Finck 
StartLinkProcessor(LPCOLESTR szLink)127c2c66affSColin Finck static BOOL StartLinkProcessor( LPCOLESTR szLink )
128c2c66affSColin Finck {
129c2c66affSColin Finck     static const WCHAR szFormat[] = { ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
130c2c66affSColin Finck     LONG len;
131c2c66affSColin Finck     LPWSTR buffer;
132c2c66affSColin Finck     BOOL ret;
133c2c66affSColin Finck 
134c2c66affSColin Finck     len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
135c2c66affSColin Finck     buffer = heap_alloc( len );
136c2c66affSColin Finck     if( !buffer )
137c2c66affSColin Finck         return FALSE;
138c2c66affSColin Finck 
139*c3cabdbfSAmine Khaldi     swprintf( buffer, szFormat, szLink );
140c2c66affSColin Finck     ret = run_winemenubuilder( buffer );
141c2c66affSColin Finck     heap_free( buffer );
142c2c66affSColin Finck     return ret;
143c2c66affSColin Finck }
144c2c66affSColin Finck 
145c2c66affSColin Finck /* interface functions */
146c2c66affSColin Finck 
Unknown_QueryInterface(InternetShortcut * This,REFIID riid,PVOID * ppvObject)147c2c66affSColin Finck static HRESULT Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
148c2c66affSColin Finck {
149c2c66affSColin Finck     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
150c2c66affSColin Finck     *ppvObject = NULL;
151c2c66affSColin Finck     if (IsEqualGUID(&IID_IUnknown, riid))
152c2c66affSColin Finck         *ppvObject = &This->IUniformResourceLocatorA_iface;
153c2c66affSColin Finck     else if (IsEqualGUID(&IID_IUniformResourceLocatorA, riid))
154c2c66affSColin Finck         *ppvObject = &This->IUniformResourceLocatorA_iface;
155c2c66affSColin Finck     else if (IsEqualGUID(&IID_IUniformResourceLocatorW, riid))
156c2c66affSColin Finck         *ppvObject = &This->IUniformResourceLocatorW_iface;
157c2c66affSColin Finck     else if (IsEqualGUID(&IID_IPersistFile, riid))
158c2c66affSColin Finck         *ppvObject = &This->IPersistFile_iface;
159c2c66affSColin Finck     else if (IsEqualGUID(&IID_IPropertySetStorage, riid))
160c2c66affSColin Finck         *ppvObject = &This->IPropertySetStorage_iface;
161c2c66affSColin Finck     else if (IsEqualGUID(&IID_IShellLinkA, riid))
162c2c66affSColin Finck     {
163c2c66affSColin Finck         FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
164c2c66affSColin Finck         return E_NOINTERFACE;
165c2c66affSColin Finck     }
166c2c66affSColin Finck     else if (IsEqualGUID(&IID_IShellLinkW, riid))
167c2c66affSColin Finck     {
168c2c66affSColin Finck         FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
169c2c66affSColin Finck         return E_NOINTERFACE;
170c2c66affSColin Finck     }
171c2c66affSColin Finck     else
172c2c66affSColin Finck     {
173c2c66affSColin Finck         FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
174c2c66affSColin Finck         return E_NOINTERFACE;
175c2c66affSColin Finck     }
176c2c66affSColin Finck     IUnknown_AddRef((IUnknown*)*ppvObject);
177c2c66affSColin Finck     return S_OK;
178c2c66affSColin Finck }
179c2c66affSColin Finck 
Unknown_AddRef(InternetShortcut * This)180c2c66affSColin Finck static ULONG Unknown_AddRef(InternetShortcut *This)
181c2c66affSColin Finck {
182c2c66affSColin Finck     TRACE("(%p)\n", This);
183c2c66affSColin Finck     return InterlockedIncrement(&This->refCount);
184c2c66affSColin Finck }
185c2c66affSColin Finck 
Unknown_Release(InternetShortcut * This)186c2c66affSColin Finck static ULONG Unknown_Release(InternetShortcut *This)
187c2c66affSColin Finck {
188c2c66affSColin Finck     ULONG count;
189c2c66affSColin Finck     TRACE("(%p)\n", This);
190c2c66affSColin Finck     count = InterlockedDecrement(&This->refCount);
191c2c66affSColin Finck     if (count == 0)
192c2c66affSColin Finck     {
193c2c66affSColin Finck         CoTaskMemFree(This->url);
194c2c66affSColin Finck         CoTaskMemFree(This->currentFile);
195c2c66affSColin Finck         IPropertySetStorage_Release(This->property_set_storage);
196c2c66affSColin Finck         heap_free(This);
197c2c66affSColin Finck         unlock_module();
198c2c66affSColin Finck     }
199c2c66affSColin Finck     return count;
200c2c66affSColin Finck }
201c2c66affSColin Finck 
UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW * url,REFIID riid,PVOID * ppvObject)202c2c66affSColin Finck static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
203c2c66affSColin Finck {
204c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
205c2c66affSColin Finck     TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
206c2c66affSColin Finck     return Unknown_QueryInterface(This, riid, ppvObject);
207c2c66affSColin Finck }
208c2c66affSColin Finck 
UniformResourceLocatorW_AddRef(IUniformResourceLocatorW * url)209c2c66affSColin Finck static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
210c2c66affSColin Finck {
211c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
212c2c66affSColin Finck     TRACE("(%p)\n", url);
213c2c66affSColin Finck     return Unknown_AddRef(This);
214c2c66affSColin Finck }
215c2c66affSColin Finck 
UniformResourceLocatorW_Release(IUniformResourceLocatorW * url)216c2c66affSColin Finck static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
217c2c66affSColin Finck {
218c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
219c2c66affSColin Finck     TRACE("(%p)\n", url);
220c2c66affSColin Finck     return Unknown_Release(This);
221c2c66affSColin Finck }
222c2c66affSColin Finck 
UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW * url,LPCWSTR pcszURL,DWORD dwInFlags)223c2c66affSColin Finck static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
224c2c66affSColin Finck {
225c2c66affSColin Finck     WCHAR *newURL = NULL;
226c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
227c2c66affSColin Finck     TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags);
228c2c66affSColin Finck     if (dwInFlags != 0)
229c2c66affSColin Finck         FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
230c2c66affSColin Finck     if (pcszURL != NULL)
231c2c66affSColin Finck     {
232c2c66affSColin Finck         newURL = co_strdupW(pcszURL);
233c2c66affSColin Finck         if (newURL == NULL)
234c2c66affSColin Finck             return E_OUTOFMEMORY;
235c2c66affSColin Finck     }
236c2c66affSColin Finck     CoTaskMemFree(This->url);
237c2c66affSColin Finck     This->url = newURL;
238c2c66affSColin Finck     This->isDirty = TRUE;
239c2c66affSColin Finck     return S_OK;
240c2c66affSColin Finck }
241c2c66affSColin Finck 
UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW * url,LPWSTR * ppszURL)242c2c66affSColin Finck static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
243c2c66affSColin Finck {
244c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
245c2c66affSColin Finck 
246c2c66affSColin Finck     TRACE("(%p, %p)\n", url, ppszURL);
247c2c66affSColin Finck 
248c2c66affSColin Finck     if (!This->url) {
249c2c66affSColin Finck         *ppszURL = NULL;
250c2c66affSColin Finck         return S_FALSE;
251c2c66affSColin Finck     }
252c2c66affSColin Finck 
253c2c66affSColin Finck     *ppszURL = co_strdupW(This->url);
254c2c66affSColin Finck     if (!*ppszURL)
255c2c66affSColin Finck         return E_OUTOFMEMORY;
256c2c66affSColin Finck 
257c2c66affSColin Finck     return S_OK;
258c2c66affSColin Finck }
259c2c66affSColin Finck 
UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW * url,PURLINVOKECOMMANDINFOW pCommandInfo)260c2c66affSColin Finck static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
261c2c66affSColin Finck {
262c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
263c2c66affSColin Finck     WCHAR app[64];
264c2c66affSColin Finck     HKEY hkey;
265c2c66affSColin Finck     static const WCHAR wszURLProtocol[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0};
266c2c66affSColin Finck     SHELLEXECUTEINFOW sei;
267c2c66affSColin Finck     DWORD res, type;
268c2c66affSColin Finck     HRESULT hres;
269c2c66affSColin Finck 
270c2c66affSColin Finck     TRACE("%p %p\n", This, pCommandInfo );
271c2c66affSColin Finck 
272c2c66affSColin Finck     if (pCommandInfo->dwcbSize < sizeof (URLINVOKECOMMANDINFOW))
273c2c66affSColin Finck         return E_INVALIDARG;
274c2c66affSColin Finck 
275c2c66affSColin Finck     if (pCommandInfo->dwFlags != IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB)
276c2c66affSColin Finck     {
277c2c66affSColin Finck         FIXME("(%p, %p): non-default verbs not implemented\n", url, pCommandInfo);
278c2c66affSColin Finck         return E_NOTIMPL;
279c2c66affSColin Finck     }
280c2c66affSColin Finck 
281336b2a45SAmine Khaldi     hres = CoInternetParseUrl(This->url, PARSE_SCHEMA, 0, app, ARRAY_SIZE(app), NULL, 0);
282c2c66affSColin Finck     if(FAILED(hres))
283c2c66affSColin Finck         return E_FAIL;
284c2c66affSColin Finck 
285c2c66affSColin Finck     res = RegOpenKeyW(HKEY_CLASSES_ROOT, app, &hkey);
286c2c66affSColin Finck     if(res != ERROR_SUCCESS)
287c2c66affSColin Finck         return E_FAIL;
288c2c66affSColin Finck 
289c2c66affSColin Finck     res = RegQueryValueExW(hkey, wszURLProtocol, NULL, &type, NULL, NULL);
290c2c66affSColin Finck     RegCloseKey(hkey);
291c2c66affSColin Finck     if(res != ERROR_SUCCESS || type != REG_SZ)
292c2c66affSColin Finck         return E_FAIL;
293c2c66affSColin Finck 
294c2c66affSColin Finck     memset(&sei, 0, sizeof(sei));
295c2c66affSColin Finck     sei.cbSize = sizeof(sei);
296c2c66affSColin Finck     sei.lpFile = This->url;
297c2c66affSColin Finck     sei.nShow = SW_SHOW;
298c2c66affSColin Finck 
299c2c66affSColin Finck     if( ShellExecuteExW(&sei) )
300c2c66affSColin Finck         return S_OK;
301c2c66affSColin Finck     else
302c2c66affSColin Finck         return E_FAIL;
303c2c66affSColin Finck }
304c2c66affSColin Finck 
UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA * url,REFIID riid,PVOID * ppvObject)305c2c66affSColin Finck static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
306c2c66affSColin Finck {
307c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
308c2c66affSColin Finck     TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
309c2c66affSColin Finck     return Unknown_QueryInterface(This, riid, ppvObject);
310c2c66affSColin Finck }
311c2c66affSColin Finck 
UniformResourceLocatorA_AddRef(IUniformResourceLocatorA * url)312c2c66affSColin Finck static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
313c2c66affSColin Finck {
314c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
315c2c66affSColin Finck     TRACE("(%p)\n", url);
316c2c66affSColin Finck     return Unknown_AddRef(This);
317c2c66affSColin Finck }
318c2c66affSColin Finck 
UniformResourceLocatorA_Release(IUniformResourceLocatorA * url)319c2c66affSColin Finck static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
320c2c66affSColin Finck {
321c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
322c2c66affSColin Finck     TRACE("(%p)\n", url);
323c2c66affSColin Finck     return Unknown_Release(This);
324c2c66affSColin Finck }
325c2c66affSColin Finck 
UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA * url,LPCSTR pcszURL,DWORD dwInFlags)326c2c66affSColin Finck static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
327c2c66affSColin Finck {
328c2c66affSColin Finck     WCHAR *newURL = NULL;
329c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
330c2c66affSColin Finck     TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags);
331c2c66affSColin Finck     if (dwInFlags != 0)
332c2c66affSColin Finck         FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
333c2c66affSColin Finck     if (pcszURL != NULL)
334c2c66affSColin Finck     {
335c2c66affSColin Finck         newURL = co_strdupAtoW(pcszURL);
336c2c66affSColin Finck         if (newURL == NULL)
337c2c66affSColin Finck             return E_OUTOFMEMORY;
338c2c66affSColin Finck     }
339c2c66affSColin Finck     CoTaskMemFree(This->url);
340c2c66affSColin Finck     This->url = newURL;
341c2c66affSColin Finck     This->isDirty = TRUE;
342c2c66affSColin Finck     return S_OK;
343c2c66affSColin Finck }
344c2c66affSColin Finck 
UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA * url,LPSTR * ppszURL)345c2c66affSColin Finck static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
346c2c66affSColin Finck {
347c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
348c2c66affSColin Finck 
349c2c66affSColin Finck     TRACE("(%p, %p)\n", url, ppszURL);
350c2c66affSColin Finck 
351c2c66affSColin Finck     if (!This->url) {
352c2c66affSColin Finck         *ppszURL = NULL;
353c2c66affSColin Finck         return S_FALSE;
354c2c66affSColin Finck 
355c2c66affSColin Finck     }
356c2c66affSColin Finck 
357c2c66affSColin Finck     *ppszURL = co_strdupWtoA(This->url);
358c2c66affSColin Finck     if (!*ppszURL)
359c2c66affSColin Finck         return E_OUTOFMEMORY;
360c2c66affSColin Finck 
361c2c66affSColin Finck     return S_OK;
362c2c66affSColin Finck }
363c2c66affSColin Finck 
UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA * url,PURLINVOKECOMMANDINFOA pCommandInfo)364c2c66affSColin Finck static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
365c2c66affSColin Finck {
366c2c66affSColin Finck     URLINVOKECOMMANDINFOW wideCommandInfo;
367c2c66affSColin Finck     int len;
368c2c66affSColin Finck     WCHAR *wideVerb;
369c2c66affSColin Finck     HRESULT res;
370c2c66affSColin Finck     InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
371c2c66affSColin Finck 
372c2c66affSColin Finck     wideCommandInfo.dwcbSize = sizeof wideCommandInfo;
373c2c66affSColin Finck     wideCommandInfo.dwFlags = pCommandInfo->dwFlags;
374c2c66affSColin Finck     wideCommandInfo.hwndParent = pCommandInfo->hwndParent;
375c2c66affSColin Finck 
376c2c66affSColin Finck     len = MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, NULL, 0);
377c2c66affSColin Finck     wideVerb = heap_alloc(len * sizeof(WCHAR));
378c2c66affSColin Finck     MultiByteToWideChar(CP_ACP, 0, pCommandInfo->pcszVerb, -1, wideVerb, len);
379c2c66affSColin Finck 
380c2c66affSColin Finck     wideCommandInfo.pcszVerb = wideVerb;
381c2c66affSColin Finck 
382c2c66affSColin Finck     res = UniformResourceLocatorW_InvokeCommand(&This->IUniformResourceLocatorW_iface, &wideCommandInfo);
383c2c66affSColin Finck     heap_free(wideVerb);
384c2c66affSColin Finck 
385c2c66affSColin Finck     return res;
386c2c66affSColin Finck }
387c2c66affSColin Finck 
PersistFile_QueryInterface(IPersistFile * pFile,REFIID riid,PVOID * ppvObject)388c2c66affSColin Finck static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
389c2c66affSColin Finck {
390c2c66affSColin Finck     InternetShortcut *This = impl_from_IPersistFile(pFile);
391c2c66affSColin Finck     TRACE("(%p, %s, %p)\n", pFile, debugstr_guid(riid), ppvObject);
392c2c66affSColin Finck     return Unknown_QueryInterface(This, riid, ppvObject);
393c2c66affSColin Finck }
394c2c66affSColin Finck 
PersistFile_AddRef(IPersistFile * pFile)395c2c66affSColin Finck static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
396c2c66affSColin Finck {
397c2c66affSColin Finck     InternetShortcut *This = impl_from_IPersistFile(pFile);
398c2c66affSColin Finck     TRACE("(%p)\n", pFile);
399c2c66affSColin Finck     return Unknown_AddRef(This);
400c2c66affSColin Finck }
401c2c66affSColin Finck 
PersistFile_Release(IPersistFile * pFile)402c2c66affSColin Finck static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
403c2c66affSColin Finck {
404c2c66affSColin Finck     InternetShortcut *This = impl_from_IPersistFile(pFile);
405c2c66affSColin Finck     TRACE("(%p)\n", pFile);
406c2c66affSColin Finck     return Unknown_Release(This);
407c2c66affSColin Finck }
408c2c66affSColin Finck 
PersistFile_GetClassID(IPersistFile * pFile,CLSID * pClassID)409c2c66affSColin Finck static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
410c2c66affSColin Finck {
411c2c66affSColin Finck     TRACE("(%p, %p)\n", pFile, pClassID);
412c2c66affSColin Finck     *pClassID = CLSID_InternetShortcut;
413c2c66affSColin Finck     return S_OK;
414c2c66affSColin Finck }
415c2c66affSColin Finck 
PersistFile_IsDirty(IPersistFile * pFile)416c2c66affSColin Finck static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
417c2c66affSColin Finck {
418c2c66affSColin Finck     InternetShortcut *This = impl_from_IPersistFile(pFile);
419c2c66affSColin Finck     TRACE("(%p)\n", pFile);
420c2c66affSColin Finck     return This->isDirty ? S_OK : S_FALSE;
421c2c66affSColin Finck }
422c2c66affSColin Finck 
423c2c66affSColin Finck /* Returns allocated profile string and a standard return code. */
get_profile_string(LPCWSTR lpAppName,LPCWSTR lpKeyName,LPCWSTR lpFileName,WCHAR ** rString)424c2c66affSColin Finck static HRESULT get_profile_string(LPCWSTR lpAppName, LPCWSTR lpKeyName,
425c2c66affSColin Finck                                 LPCWSTR lpFileName, WCHAR **rString )
426c2c66affSColin Finck {
427c2c66affSColin Finck     DWORD r = 0;
428c2c66affSColin Finck     DWORD len = 128;
429c2c66affSColin Finck     WCHAR *buffer;
430c2c66affSColin Finck 
431c2c66affSColin Finck     *rString = NULL;
432c2c66affSColin Finck     buffer = CoTaskMemAlloc(len * sizeof(*buffer));
433c2c66affSColin Finck     if (!buffer)
434c2c66affSColin Finck         return E_OUTOFMEMORY;
435c2c66affSColin Finck 
436c2c66affSColin Finck     r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
437c2c66affSColin Finck     while (r == len-1)
438c2c66affSColin Finck     {
439c2c66affSColin Finck         WCHAR *realloc_buf;
440c2c66affSColin Finck 
441c2c66affSColin Finck         len *= 2;
442c2c66affSColin Finck         realloc_buf = CoTaskMemRealloc(buffer, len * sizeof(*buffer));
443c2c66affSColin Finck         if (realloc_buf == NULL)
444c2c66affSColin Finck         {
445c2c66affSColin Finck             CoTaskMemFree(buffer);
446c2c66affSColin Finck             return E_OUTOFMEMORY;
447c2c66affSColin Finck         }
448c2c66affSColin Finck         buffer = realloc_buf;
449c2c66affSColin Finck 
450c2c66affSColin Finck         r = GetPrivateProfileStringW(lpAppName, lpKeyName, NULL, buffer, len, lpFileName);
451c2c66affSColin Finck     }
452c2c66affSColin Finck 
453c2c66affSColin Finck     *rString = buffer;
454c2c66affSColin Finck     return r ? S_OK : E_FAIL;
455c2c66affSColin Finck }
456c2c66affSColin Finck 
PersistFile_Load(IPersistFile * pFile,LPCOLESTR pszFileName,DWORD dwMode)457c2c66affSColin Finck static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
458c2c66affSColin Finck {
459ec33091aSAmine Khaldi     static const WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
460ec33091aSAmine Khaldi     static const WCHAR str_URL[] = {'U','R','L',0};
461ec33091aSAmine Khaldi     static const WCHAR str_iconfile[] = {'i','c','o','n','f','i','l','e',0};
462ec33091aSAmine Khaldi     static const WCHAR str_iconindex[] = {'i','c','o','n','i','n','d','e','x',0};
463c2c66affSColin Finck     InternetShortcut *This = impl_from_IPersistFile(pFile);
464c2c66affSColin Finck     WCHAR *filename = NULL;
465c2c66affSColin Finck     WCHAR *url;
466c2c66affSColin Finck     HRESULT hr;
467c2c66affSColin Finck     IPropertyStorage *pPropStg;
468c2c66affSColin Finck     WCHAR *iconfile;
469c2c66affSColin Finck     WCHAR *iconindexstring;
470c2c66affSColin Finck 
471c2c66affSColin Finck     TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode);
472c2c66affSColin Finck 
473c2c66affSColin Finck     if (dwMode != 0)
474c2c66affSColin Finck         FIXME("ignoring unimplemented mode 0x%x\n", dwMode);
475c2c66affSColin Finck 
476c2c66affSColin Finck     filename = co_strdupW(pszFileName);
477c2c66affSColin Finck     if (!filename)
478c2c66affSColin Finck         return E_OUTOFMEMORY;
479c2c66affSColin Finck 
480c2c66affSColin Finck     if (FAILED(hr = get_profile_string(str_header, str_URL, pszFileName, &url)))
481c2c66affSColin Finck     {
482c2c66affSColin Finck         CoTaskMemFree(filename);
483c2c66affSColin Finck         return hr;
484c2c66affSColin Finck     }
485c2c66affSColin Finck 
486c2c66affSColin Finck     hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut,
487c2c66affSColin Finck                 STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &pPropStg);
488c2c66affSColin Finck     if (FAILED(hr))
489c2c66affSColin Finck     {
490c2c66affSColin Finck         CoTaskMemFree(filename);
491c2c66affSColin Finck         CoTaskMemFree(url);
492c2c66affSColin Finck         return hr;
493c2c66affSColin Finck     }
494c2c66affSColin Finck 
495c2c66affSColin Finck     CoTaskMemFree(This->currentFile);
496c2c66affSColin Finck     This->currentFile = filename;
497c2c66affSColin Finck     CoTaskMemFree(This->url);
498c2c66affSColin Finck     This->url = url;
499c2c66affSColin Finck     This->isDirty = FALSE;
500c2c66affSColin Finck 
501c2c66affSColin Finck     /* Now we're going to read in the iconfile and iconindex.
502c2c66affSColin Finck        If we don't find them, that's not a failure case -- it's possible
503c2c66affSColin Finck        that they just aren't in there. */
504c2c66affSColin Finck 
505c2c66affSColin Finck     if (get_profile_string(str_header, str_iconfile, pszFileName, &iconfile) == S_OK)
506c2c66affSColin Finck     {
507c2c66affSColin Finck         PROPSPEC ps;
508c2c66affSColin Finck         PROPVARIANT pv;
509c2c66affSColin Finck         ps.ulKind = PRSPEC_PROPID;
510c2c66affSColin Finck         ps.u.propid = PID_IS_ICONFILE;
511c2c66affSColin Finck         pv.vt = VT_LPWSTR;
512c2c66affSColin Finck         pv.u.pwszVal = iconfile;
513c2c66affSColin Finck         hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
514c2c66affSColin Finck         if (FAILED(hr))
515c2c66affSColin Finck             TRACE("Failed to store the iconfile to our property storage.  hr = 0x%x\n", hr);
516c2c66affSColin Finck     }
517c2c66affSColin Finck     CoTaskMemFree(iconfile);
518c2c66affSColin Finck 
519c2c66affSColin Finck     if (get_profile_string(str_header, str_iconindex, pszFileName, &iconindexstring) == S_OK)
520c2c66affSColin Finck     {
521c2c66affSColin Finck         int iconindex;
522c2c66affSColin Finck         PROPSPEC ps;
523c2c66affSColin Finck         PROPVARIANT pv;
524*c3cabdbfSAmine Khaldi         iconindex = wcstol(iconindexstring, NULL, 10);
525c2c66affSColin Finck         ps.ulKind = PRSPEC_PROPID;
526c2c66affSColin Finck         ps.u.propid = PID_IS_ICONINDEX;
527c2c66affSColin Finck         pv.vt = VT_I4;
528c2c66affSColin Finck         pv.u.iVal = iconindex;
529c2c66affSColin Finck         hr = IPropertyStorage_WriteMultiple(pPropStg, 1, &ps, &pv, 0);
530c2c66affSColin Finck         if (FAILED(hr))
531c2c66affSColin Finck            TRACE("Failed to store the iconindex to our property storage.  hr = 0x%x\n", hr);
532c2c66affSColin Finck     }
533c2c66affSColin Finck     CoTaskMemFree(iconindexstring);
534c2c66affSColin Finck 
535c2c66affSColin Finck     IPropertyStorage_Release(pPropStg);
536c2c66affSColin Finck     return hr;
537c2c66affSColin Finck }
538c2c66affSColin Finck 
PersistFile_Save(IPersistFile * pFile,LPCOLESTR pszFileName,BOOL fRemember)539c2c66affSColin Finck static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
540c2c66affSColin Finck {
541c2c66affSColin Finck     HRESULT hr = S_OK;
542c2c66affSColin Finck     INT len;
543c2c66affSColin Finck     CHAR *url;
544c2c66affSColin Finck     InternetShortcut *This = impl_from_IPersistFile(pFile);
545c2c66affSColin Finck 
546c2c66affSColin Finck     TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
547c2c66affSColin Finck 
548c2c66affSColin Finck     if (pszFileName != NULL && fRemember)
549c2c66affSColin Finck     {
550c2c66affSColin Finck         LPOLESTR oldFile = This->currentFile;
551c2c66affSColin Finck         This->currentFile = co_strdupW(pszFileName);
552c2c66affSColin Finck         if (This->currentFile == NULL)
553c2c66affSColin Finck         {
554c2c66affSColin Finck             This->currentFile = oldFile;
555c2c66affSColin Finck             return E_OUTOFMEMORY;
556c2c66affSColin Finck         }
557c2c66affSColin Finck         CoTaskMemFree(oldFile);
558c2c66affSColin Finck     }
559c2c66affSColin Finck     if (This->url == NULL)
560c2c66affSColin Finck         return E_FAIL;
561c2c66affSColin Finck 
562c2c66affSColin Finck     /* Windows seems to always write:
563c2c66affSColin Finck      *   ASCII "[InternetShortcut]" headers
564c2c66affSColin Finck      *   ASCII names in "name=value" pairs
565c2c66affSColin Finck      *   An ASCII (probably UTF8?) value in "URL=..."
566c2c66affSColin Finck      */
567c2c66affSColin Finck     len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
568c2c66affSColin Finck     url = heap_alloc(len);
569c2c66affSColin Finck     if (url != NULL)
570c2c66affSColin Finck     {
571c2c66affSColin Finck         HANDLE file;
572c2c66affSColin Finck         WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0);
573c2c66affSColin Finck         file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
574c2c66affSColin Finck         if (file != INVALID_HANDLE_VALUE)
575c2c66affSColin Finck         {
576ec33091aSAmine Khaldi             static const char str_header[] = "[InternetShortcut]";
577ec33091aSAmine Khaldi             static const char str_URL[] = "URL=";
578ec33091aSAmine Khaldi             static const char str_ICONFILE[] = "ICONFILE=";
579ec33091aSAmine Khaldi             static const char str_eol[] = "\r\n";
580c2c66affSColin Finck             DWORD bytesWritten;
581c2c66affSColin Finck             char *iconfile;
582c2c66affSColin Finck             IPropertyStorage *pPropStgRead;
583c2c66affSColin Finck             PROPSPEC ps[2];
584c2c66affSColin Finck             PROPVARIANT pvread[2];
585c2c66affSColin Finck             ps[0].ulKind = PRSPEC_PROPID;
586c2c66affSColin Finck             ps[0].u.propid = PID_IS_ICONFILE;
587c2c66affSColin Finck             ps[1].ulKind = PRSPEC_PROPID;
588c2c66affSColin Finck             ps[1].u.propid = PID_IS_ICONINDEX;
589c2c66affSColin Finck 
590ec33091aSAmine Khaldi             WriteFile(file, str_header, ARRAY_SIZE(str_header) - 1, &bytesWritten, NULL);
591ec33091aSAmine Khaldi             WriteFile(file, str_eol, ARRAY_SIZE(str_eol) - 1, &bytesWritten, NULL);
592ec33091aSAmine Khaldi             WriteFile(file, str_URL, ARRAY_SIZE(str_URL) - 1, &bytesWritten, NULL);
593c2c66affSColin Finck             WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL);
594ec33091aSAmine Khaldi             WriteFile(file, str_eol, ARRAY_SIZE(str_eol) - 1, &bytesWritten, NULL);
595c2c66affSColin Finck 
596c2c66affSColin Finck             hr = IPropertySetStorage_Open(This->property_set_storage, &FMTID_Intshcut, STGM_READ|STGM_SHARE_EXCLUSIVE, &pPropStgRead);
597c2c66affSColin Finck             if (SUCCEEDED(hr))
598c2c66affSColin Finck             {
599c2c66affSColin Finck                 hr = IPropertyStorage_ReadMultiple(pPropStgRead, 2, ps, pvread);
600c2c66affSColin Finck                 if (hr == S_FALSE)
601c2c66affSColin Finck                 {
602c2c66affSColin Finck                     /* None of the properties are present, that's ok */
603c2c66affSColin Finck                     hr = S_OK;
604c2c66affSColin Finck                     IPropertyStorage_Release(pPropStgRead);
605c2c66affSColin Finck                 }
606c2c66affSColin Finck                 else if (SUCCEEDED(hr))
607c2c66affSColin Finck                 {
608c2c66affSColin Finck                     char indexString[50];
609c2c66affSColin Finck                     len = WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, NULL, 0, 0, 0);
610c2c66affSColin Finck                     iconfile = heap_alloc(len);
611c2c66affSColin Finck                     if (iconfile != NULL)
612c2c66affSColin Finck                     {
613c2c66affSColin Finck                         WideCharToMultiByte(CP_UTF8, 0, pvread[0].u.pwszVal, -1, iconfile, len, 0, 0);
614c2c66affSColin Finck                         WriteFile(file, str_ICONFILE, lstrlenA(str_ICONFILE), &bytesWritten, NULL);
615c2c66affSColin Finck                         WriteFile(file, iconfile, lstrlenA(iconfile), &bytesWritten, NULL);
616c2c66affSColin Finck                         WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
617c2c66affSColin Finck                     }
618c2c66affSColin Finck 
619c2c66affSColin Finck                     sprintf(indexString, "ICONINDEX=%d", pvread[1].u.iVal);
620c2c66affSColin Finck                     WriteFile(file, indexString, lstrlenA(indexString), &bytesWritten, NULL);
621c2c66affSColin Finck                     WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
622c2c66affSColin Finck 
623c2c66affSColin Finck                     IPropertyStorage_Release(pPropStgRead);
624c2c66affSColin Finck                     PropVariantClear(&pvread[0]);
625c2c66affSColin Finck                     PropVariantClear(&pvread[1]);
626c2c66affSColin Finck                 }
627c2c66affSColin Finck                 else
628c2c66affSColin Finck                 {
629c2c66affSColin Finck                     TRACE("Unable to read properties.\n");
630c2c66affSColin Finck                 }
631c2c66affSColin Finck             }
632c2c66affSColin Finck             else
633c2c66affSColin Finck             {
634c2c66affSColin Finck                TRACE("Unable to get the IPropertyStorage.\n");
635c2c66affSColin Finck             }
636c2c66affSColin Finck 
637c2c66affSColin Finck             CloseHandle(file);
638c2c66affSColin Finck             if (pszFileName == NULL || fRemember)
639c2c66affSColin Finck                 This->isDirty = FALSE;
640c2c66affSColin Finck             StartLinkProcessor(pszFileName);
641c2c66affSColin Finck         }
642c2c66affSColin Finck         else
643c2c66affSColin Finck             hr = E_FAIL;
644c2c66affSColin Finck         heap_free(url);
645c2c66affSColin Finck     }
646c2c66affSColin Finck     else
647c2c66affSColin Finck         hr = E_OUTOFMEMORY;
648c2c66affSColin Finck 
649c2c66affSColin Finck     return hr;
650c2c66affSColin Finck }
651c2c66affSColin Finck 
PersistFile_SaveCompleted(IPersistFile * pFile,LPCOLESTR pszFileName)652c2c66affSColin Finck static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
653c2c66affSColin Finck {
654c2c66affSColin Finck     FIXME("(%p, %p): stub\n", pFile, pszFileName);
655c2c66affSColin Finck     return E_NOTIMPL;
656c2c66affSColin Finck }
657c2c66affSColin Finck 
PersistFile_GetCurFile(IPersistFile * pFile,LPOLESTR * ppszFileName)658c2c66affSColin Finck static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
659c2c66affSColin Finck {
660c2c66affSColin Finck     HRESULT hr = S_OK;
661c2c66affSColin Finck     InternetShortcut *This = impl_from_IPersistFile(pFile);
662c2c66affSColin Finck     TRACE("(%p, %p)\n", pFile, ppszFileName);
663c2c66affSColin Finck     if (This->currentFile == NULL)
664c2c66affSColin Finck         *ppszFileName = NULL;
665c2c66affSColin Finck     else
666c2c66affSColin Finck     {
667c2c66affSColin Finck         *ppszFileName = co_strdupW(This->currentFile);
668c2c66affSColin Finck         if (*ppszFileName == NULL)
669c2c66affSColin Finck             hr = E_OUTOFMEMORY;
670c2c66affSColin Finck     }
671c2c66affSColin Finck     return hr;
672c2c66affSColin Finck }
673c2c66affSColin Finck 
PropertySetStorage_QueryInterface(IPropertySetStorage * iface,REFIID riid,PVOID * ppvObject)674c2c66affSColin Finck static HRESULT WINAPI PropertySetStorage_QueryInterface(IPropertySetStorage *iface, REFIID riid, PVOID *ppvObject)
675c2c66affSColin Finck {
676c2c66affSColin Finck     InternetShortcut *This = impl_from_IPropertySetStorage(iface);
677c2c66affSColin Finck     TRACE("(%p)\n", iface);
678c2c66affSColin Finck     return Unknown_QueryInterface(This, riid, ppvObject);
679c2c66affSColin Finck }
680c2c66affSColin Finck 
PropertySetStorage_AddRef(IPropertySetStorage * iface)681c2c66affSColin Finck static ULONG WINAPI PropertySetStorage_AddRef(IPropertySetStorage *iface)
682c2c66affSColin Finck {
683c2c66affSColin Finck     InternetShortcut *This = impl_from_IPropertySetStorage(iface);
684c2c66affSColin Finck     TRACE("(%p)\n", iface);
685c2c66affSColin Finck     return Unknown_AddRef(This);
686c2c66affSColin Finck }
687c2c66affSColin Finck 
PropertySetStorage_Release(IPropertySetStorage * iface)688c2c66affSColin Finck static ULONG WINAPI PropertySetStorage_Release(IPropertySetStorage *iface)
689c2c66affSColin Finck {
690c2c66affSColin Finck     InternetShortcut *This = impl_from_IPropertySetStorage(iface);
691c2c66affSColin Finck     TRACE("(%p)\n", iface);
692c2c66affSColin Finck     return Unknown_Release(This);
693c2c66affSColin Finck }
694c2c66affSColin Finck 
PropertySetStorage_Create(IPropertySetStorage * iface,REFFMTID rfmtid,const CLSID * pclsid,DWORD grfFlags,DWORD grfMode,IPropertyStorage ** ppprstg)695c2c66affSColin Finck static HRESULT WINAPI PropertySetStorage_Create(
696c2c66affSColin Finck         IPropertySetStorage* iface,
697c2c66affSColin Finck         REFFMTID rfmtid,
698c2c66affSColin Finck         const CLSID *pclsid,
699c2c66affSColin Finck         DWORD grfFlags,
700c2c66affSColin Finck         DWORD grfMode,
701c2c66affSColin Finck         IPropertyStorage **ppprstg)
702c2c66affSColin Finck {
703c2c66affSColin Finck     InternetShortcut *This = impl_from_IPropertySetStorage(iface);
704c2c66affSColin Finck     TRACE("(%s, %p, 0x%x, 0x%x, %p)\n", debugstr_guid(rfmtid), pclsid, grfFlags, grfMode, ppprstg);
705c2c66affSColin Finck 
706c2c66affSColin Finck     return IPropertySetStorage_Create(This->property_set_storage,
707c2c66affSColin Finck                                       rfmtid,
708c2c66affSColin Finck                                       pclsid,
709c2c66affSColin Finck                                       grfFlags,
710c2c66affSColin Finck                                       grfMode,
711c2c66affSColin Finck                                       ppprstg);
712c2c66affSColin Finck }
713c2c66affSColin Finck 
PropertySetStorage_Open(IPropertySetStorage * iface,REFFMTID rfmtid,DWORD grfMode,IPropertyStorage ** ppprstg)714c2c66affSColin Finck static HRESULT WINAPI PropertySetStorage_Open(
715c2c66affSColin Finck         IPropertySetStorage* iface,
716c2c66affSColin Finck         REFFMTID rfmtid,
717c2c66affSColin Finck         DWORD grfMode,
718c2c66affSColin Finck         IPropertyStorage **ppprstg)
719c2c66affSColin Finck {
720c2c66affSColin Finck     InternetShortcut *This = impl_from_IPropertySetStorage(iface);
721c2c66affSColin Finck     TRACE("(%s, 0x%x, %p)\n", debugstr_guid(rfmtid), grfMode, ppprstg);
722c2c66affSColin Finck 
723c2c66affSColin Finck     /* Note:  The |STGM_SHARE_EXCLUSIVE is to cope with a bug in the implementation.  Should be fixed in ole32. */
724c2c66affSColin Finck     return IPropertySetStorage_Open(This->property_set_storage,
725c2c66affSColin Finck                                     rfmtid,
726c2c66affSColin Finck                                     grfMode|STGM_SHARE_EXCLUSIVE,
727c2c66affSColin Finck                                     ppprstg);
728c2c66affSColin Finck }
729c2c66affSColin Finck 
PropertySetStorage_Delete(IPropertySetStorage * iface,REFFMTID rfmtid)730c2c66affSColin Finck static HRESULT WINAPI PropertySetStorage_Delete(IPropertySetStorage *iface, REFFMTID rfmtid)
731c2c66affSColin Finck {
732c2c66affSColin Finck     InternetShortcut *This = impl_from_IPropertySetStorage(iface);
733c2c66affSColin Finck     TRACE("(%s)\n", debugstr_guid(rfmtid));
734c2c66affSColin Finck 
735c2c66affSColin Finck 
736c2c66affSColin Finck     return IPropertySetStorage_Delete(This->property_set_storage,
737c2c66affSColin Finck                                       rfmtid);
738c2c66affSColin Finck }
739c2c66affSColin Finck 
PropertySetStorage_Enum(IPropertySetStorage * iface,IEnumSTATPROPSETSTG ** ppenum)740c2c66affSColin Finck static HRESULT WINAPI PropertySetStorage_Enum(IPropertySetStorage *iface, IEnumSTATPROPSETSTG **ppenum)
741c2c66affSColin Finck {
742c2c66affSColin Finck     FIXME("(%p): stub\n", ppenum);
743c2c66affSColin Finck     return E_NOTIMPL;
744c2c66affSColin Finck }
745c2c66affSColin Finck 
746c2c66affSColin Finck static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
747c2c66affSColin Finck     UniformResourceLocatorW_QueryInterface,
748c2c66affSColin Finck     UniformResourceLocatorW_AddRef,
749c2c66affSColin Finck     UniformResourceLocatorW_Release,
750c2c66affSColin Finck     UniformResourceLocatorW_SetUrl,
751c2c66affSColin Finck     UniformResourceLocatorW_GetUrl,
752c2c66affSColin Finck     UniformResourceLocatorW_InvokeCommand
753c2c66affSColin Finck };
754c2c66affSColin Finck 
755c2c66affSColin Finck static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
756c2c66affSColin Finck     UniformResourceLocatorA_QueryInterface,
757c2c66affSColin Finck     UniformResourceLocatorA_AddRef,
758c2c66affSColin Finck     UniformResourceLocatorA_Release,
759c2c66affSColin Finck     UniformResourceLocatorA_SetUrl,
760c2c66affSColin Finck     UniformResourceLocatorA_GetUrl,
761c2c66affSColin Finck     UniformResourceLocatorA_InvokeCommand
762c2c66affSColin Finck };
763c2c66affSColin Finck 
764c2c66affSColin Finck static const IPersistFileVtbl persistFileVtbl = {
765c2c66affSColin Finck     PersistFile_QueryInterface,
766c2c66affSColin Finck     PersistFile_AddRef,
767c2c66affSColin Finck     PersistFile_Release,
768c2c66affSColin Finck     PersistFile_GetClassID,
769c2c66affSColin Finck     PersistFile_IsDirty,
770c2c66affSColin Finck     PersistFile_Load,
771c2c66affSColin Finck     PersistFile_Save,
772c2c66affSColin Finck     PersistFile_SaveCompleted,
773c2c66affSColin Finck     PersistFile_GetCurFile
774c2c66affSColin Finck };
775c2c66affSColin Finck 
776c2c66affSColin Finck static const IPropertySetStorageVtbl propertySetStorageVtbl = {
777c2c66affSColin Finck     PropertySetStorage_QueryInterface,
778c2c66affSColin Finck     PropertySetStorage_AddRef,
779c2c66affSColin Finck     PropertySetStorage_Release,
780c2c66affSColin Finck     PropertySetStorage_Create,
781c2c66affSColin Finck     PropertySetStorage_Open,
782c2c66affSColin Finck     PropertySetStorage_Delete,
783c2c66affSColin Finck     PropertySetStorage_Enum
784c2c66affSColin Finck };
785c2c66affSColin Finck 
create_shortcut(void)786c2c66affSColin Finck static InternetShortcut *create_shortcut(void)
787c2c66affSColin Finck {
788c2c66affSColin Finck     InternetShortcut *newshortcut;
789c2c66affSColin Finck 
790c2c66affSColin Finck     newshortcut = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
791c2c66affSColin Finck     if (newshortcut)
792c2c66affSColin Finck     {
793c2c66affSColin Finck         HRESULT hr;
794c2c66affSColin Finck         IPropertyStorage *dummy;
795c2c66affSColin Finck 
796c2c66affSColin Finck         newshortcut->IUniformResourceLocatorA_iface.lpVtbl = &uniformResourceLocatorAVtbl;
797c2c66affSColin Finck         newshortcut->IUniformResourceLocatorW_iface.lpVtbl = &uniformResourceLocatorWVtbl;
798c2c66affSColin Finck         newshortcut->IPersistFile_iface.lpVtbl = &persistFileVtbl;
799c2c66affSColin Finck         newshortcut->IPropertySetStorage_iface.lpVtbl = &propertySetStorageVtbl;
800c2c66affSColin Finck         newshortcut->refCount = 1;
801c2c66affSColin Finck         hr = StgCreateStorageEx(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE,
802c2c66affSColin Finck                                 STGFMT_STORAGE, 0, NULL, NULL, &IID_IPropertySetStorage, (void **) &newshortcut->property_set_storage);
803c2c66affSColin Finck         if (FAILED(hr))
804c2c66affSColin Finck         {
805c2c66affSColin Finck             TRACE("Failed to create the storage object needed for the shortcut.\n");
806c2c66affSColin Finck             heap_free(newshortcut);
807c2c66affSColin Finck             return NULL;
808c2c66affSColin Finck         }
809c2c66affSColin Finck 
810c2c66affSColin Finck         hr = IPropertySetStorage_Create(newshortcut->property_set_storage, &FMTID_Intshcut, NULL, PROPSETFLAG_DEFAULT, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, &dummy);
811c2c66affSColin Finck         if (FAILED(hr))
812c2c66affSColin Finck         {
813c2c66affSColin Finck             TRACE("Failed to create the property object needed for the shortcut.\n");
814c2c66affSColin Finck             IPropertySetStorage_Release(newshortcut->property_set_storage);
815c2c66affSColin Finck             heap_free(newshortcut);
816c2c66affSColin Finck             return NULL;
817c2c66affSColin Finck         }
818c2c66affSColin Finck         IPropertyStorage_Release(dummy);
819c2c66affSColin Finck     }
820c2c66affSColin Finck 
821c2c66affSColin Finck     return newshortcut;
822c2c66affSColin Finck }
823c2c66affSColin Finck 
InternetShortcut_Create(IClassFactory * iface,IUnknown * outer,REFIID riid,void ** ppv)824c2c66affSColin Finck HRESULT WINAPI InternetShortcut_Create(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
825c2c66affSColin Finck {
826c2c66affSColin Finck     InternetShortcut *This;
827c2c66affSColin Finck     HRESULT hres;
828c2c66affSColin Finck 
829c2c66affSColin Finck     TRACE("(%p, %s, %p)\n", outer, debugstr_guid(riid), ppv);
830c2c66affSColin Finck 
831c2c66affSColin Finck     *ppv = NULL;
832c2c66affSColin Finck 
833c2c66affSColin Finck     if(outer)
834c2c66affSColin Finck         return CLASS_E_NOAGGREGATION;
835c2c66affSColin Finck 
836c2c66affSColin Finck     This = create_shortcut();
837c2c66affSColin Finck     if(!This)
838c2c66affSColin Finck         return E_OUTOFMEMORY;
839c2c66affSColin Finck 
840c2c66affSColin Finck     hres = Unknown_QueryInterface(This, riid, ppv);
841c2c66affSColin Finck     Unknown_Release(This);
842c2c66affSColin Finck     return hres;
843c2c66affSColin Finck }
844c2c66affSColin Finck 
845c2c66affSColin Finck 
846c2c66affSColin Finck /**********************************************************************
847c2c66affSColin Finck  * OpenURL  (ieframe.@)
848c2c66affSColin Finck  */
OpenURL(HWND hWnd,HINSTANCE hInst,LPCSTR lpcstrUrl,int nShowCmd)849c2c66affSColin Finck void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd)
850c2c66affSColin Finck {
851c2c66affSColin Finck     InternetShortcut *shortcut;
852c2c66affSColin Finck     WCHAR* urlfilepath = NULL;
853c2c66affSColin Finck     int len;
854c2c66affSColin Finck 
855c2c66affSColin Finck     shortcut = create_shortcut();
856c2c66affSColin Finck 
857c2c66affSColin Finck     if(!shortcut)
858c2c66affSColin Finck         return;
859c2c66affSColin Finck 
860c2c66affSColin Finck     len = MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, NULL, 0);
861c2c66affSColin Finck     urlfilepath = heap_alloc(len * sizeof(WCHAR));
862c2c66affSColin Finck     MultiByteToWideChar(CP_ACP, 0, lpcstrUrl, -1, urlfilepath, len);
863c2c66affSColin Finck 
864c2c66affSColin Finck     if(SUCCEEDED(IPersistFile_Load(&shortcut->IPersistFile_iface, urlfilepath, 0))) {
865c2c66affSColin Finck         URLINVOKECOMMANDINFOW ici;
866c2c66affSColin Finck 
867c2c66affSColin Finck         memset( &ici, 0, sizeof ici );
868c2c66affSColin Finck         ici.dwcbSize = sizeof ici;
869c2c66affSColin Finck         ici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
870c2c66affSColin Finck         ici.hwndParent = hWnd;
871c2c66affSColin Finck 
872c2c66affSColin Finck         if(FAILED(UniformResourceLocatorW_InvokeCommand(&shortcut->IUniformResourceLocatorW_iface, (PURLINVOKECOMMANDINFOW) &ici)))
873c2c66affSColin Finck             TRACE("failed to open URL: %s\n", debugstr_a(lpcstrUrl));
874c2c66affSColin Finck     }
875c2c66affSColin Finck 
876c2c66affSColin Finck     heap_free(urlfilepath);
877c2c66affSColin Finck     Unknown_Release(shortcut);
878c2c66affSColin Finck }
879