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 * fd.o desktop and menu integration
24 * Implement the IShellLinkA/W interfaces
25 * Handle the SetURL flags
27 * Implement any other interfaces? Does any software actually use them?
29 * The installer for the Zuma Deluxe Popcap game is good for testing.
32 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
42 IUniformResourceLocatorA uniformResourceLocatorA;
43 IUniformResourceLocatorW uniformResourceLocatorW;
44 IPersistFile persistFile;
53 /* utility functions */
55 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
57 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, uniformResourceLocatorA));
60 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
62 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, uniformResourceLocatorW));
65 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
67 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, persistFile));
70 /* interface functions */
72 static HRESULT WINAPI Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
74 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
76 if (IsEqualGUID(&IID_IUnknown, riid))
77 *ppvObject = &This->uniformResourceLocatorA;
78 else if (IsEqualGUID(&IID_IUniformResourceLocatorA, riid))
79 *ppvObject = &This->uniformResourceLocatorA;
80 else if (IsEqualGUID(&IID_IUniformResourceLocatorW, riid))
81 *ppvObject = &This->uniformResourceLocatorW;
82 else if (IsEqualGUID(&IID_IPersistFile, riid))
83 *ppvObject = &This->persistFile;
84 else if (IsEqualGUID(&IID_IShellLinkA, riid))
86 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
89 else if (IsEqualGUID(&IID_IShellLinkW, riid))
91 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
96 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
99 IUnknown_AddRef((IUnknown*)*ppvObject);
103 static ULONG WINAPI Unknown_AddRef(InternetShortcut *This)
105 TRACE("(%p)\n", This);
106 return InterlockedIncrement(&This->refCount);
109 static ULONG WINAPI Unknown_Release(InternetShortcut *This)
112 TRACE("(%p)\n", This);
113 count = InterlockedDecrement(&This->refCount);
116 CoTaskMemFree(This->url);
117 CoTaskMemFree(This->currentFile);
119 SHDOCVW_UnlockModule();
124 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
126 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
127 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
128 return Unknown_QueryInterface(This, riid, ppvObject);
131 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
133 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
134 TRACE("(%p)\n", url);
135 return Unknown_AddRef(This);
138 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
140 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
141 TRACE("(%p)\n", url);
142 return Unknown_Release(This);
145 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
147 WCHAR *newURL = NULL;
148 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
149 TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags);
151 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
154 newURL = co_strdupW(pcszURL);
156 return E_OUTOFMEMORY;
158 CoTaskMemFree(This->url);
160 This->isDirty = TRUE;
164 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
167 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
168 TRACE("(%p, %p)\n", url, ppszURL);
169 if (This->url == NULL)
173 *ppszURL = co_strdupW(This->url);
174 if (*ppszURL == NULL)
180 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
182 FIXME("(%p, %p): stub\n", url, pCommandInfo);
186 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
188 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
189 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
190 return Unknown_QueryInterface(This, riid, ppvObject);
193 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
195 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
196 TRACE("(%p)\n", url);
197 return Unknown_AddRef(This);
200 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
202 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
203 TRACE("(%p)\n", url);
204 return Unknown_Release(This);
207 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
209 WCHAR *newURL = NULL;
210 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
211 TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags);
213 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
216 newURL = co_strdupAtoW(pcszURL);
218 return E_OUTOFMEMORY;
220 CoTaskMemFree(This->url);
222 This->isDirty = TRUE;
226 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
229 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
230 TRACE("(%p, %p)\n", url, ppszURL);
231 if (This->url == NULL)
235 *ppszURL = co_strdupWtoA(This->url);
236 if (*ppszURL == NULL)
242 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
244 FIXME("(%p, %p): stub\n", url, pCommandInfo);
248 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
250 InternetShortcut *This = impl_from_IPersistFile(pFile);
251 TRACE("(%p, %s, %p)\n", pFile, debugstr_guid(riid), ppvObject);
252 return Unknown_QueryInterface(This, riid, ppvObject);
255 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
257 InternetShortcut *This = impl_from_IPersistFile(pFile);
258 TRACE("(%p)\n", pFile);
259 return Unknown_AddRef(This);
262 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
264 InternetShortcut *This = impl_from_IPersistFile(pFile);
265 TRACE("(%p)\n", pFile);
266 return Unknown_Release(This);
269 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
271 TRACE("(%p, %p)\n", pFile, pClassID);
272 *pClassID = CLSID_InternetShortcut;
276 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
278 InternetShortcut *This = impl_from_IPersistFile(pFile);
279 TRACE("(%p)\n", pFile);
280 return This->isDirty ? S_OK : S_FALSE;
283 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
285 FIXME("(%p, %p, 0x%x): stub\n", pFile, pszFileName, dwMode);
289 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
294 InternetShortcut *This = impl_from_IPersistFile(pFile);
296 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
298 if (pszFileName != NULL && fRemember)
300 LPOLESTR oldFile = This->currentFile;
301 This->currentFile = co_strdupW(pszFileName);
302 if (This->currentFile == NULL)
304 This->currentFile = oldFile;
305 return E_OUTOFMEMORY;
307 CoTaskMemFree(oldFile);
309 if (This->url == NULL)
312 /* Windows seems to always write:
313 * ASCII "[InternetShortcut]" headers
314 * ASCII names in "name=value" pairs
315 * An ASCII (probably UTF8?) value in "URL=..."
317 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
318 url = heap_alloc(len);
322 WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0);
323 file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
324 if (file != INVALID_HANDLE_VALUE)
327 char str_header[] = "[InternetShortcut]";
328 char str_URL[] = "URL=";
329 char str_eol[] = "\r\n";
331 WriteFile(file, str_header, lstrlenA(str_header), &bytesWritten, NULL);
332 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
333 WriteFile(file, str_URL, lstrlenA(str_URL), &bytesWritten, NULL);
334 WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL);
335 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
337 if (pszFileName == NULL || fRemember)
338 This->isDirty = FALSE;
350 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
352 FIXME("(%p, %p): stub\n", pFile, pszFileName);
356 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
359 InternetShortcut *This = impl_from_IPersistFile(pFile);
360 TRACE("(%p, %p)\n", pFile, ppszFileName);
361 if (This->currentFile == NULL)
362 *ppszFileName = NULL;
365 *ppszFileName = co_strdupW(This->currentFile);
366 if (*ppszFileName == NULL)
374 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
375 UniformResourceLocatorW_QueryInterface,
376 UniformResourceLocatorW_AddRef,
377 UniformResourceLocatorW_Release,
378 UniformResourceLocatorW_SetUrl,
379 UniformResourceLocatorW_GetUrl,
380 UniformResourceLocatorW_InvokeCommand
383 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
384 UniformResourceLocatorA_QueryInterface,
385 UniformResourceLocatorA_AddRef,
386 UniformResourceLocatorA_Release,
387 UniformResourceLocatorA_SetUrl,
388 UniformResourceLocatorA_GetUrl,
389 UniformResourceLocatorA_InvokeCommand
392 static const IPersistFileVtbl persistFileVtbl = {
393 PersistFile_QueryInterface,
396 PersistFile_GetClassID,
400 PersistFile_SaveCompleted,
401 PersistFile_GetCurFile
404 HRESULT InternetShortcut_Create(IUnknown *pOuter, REFIID riid, void **ppv)
406 InternetShortcut *This;
409 TRACE("(%p, %s, %p)\n", pOuter, debugstr_guid(riid), ppv);
414 return CLASS_E_NOAGGREGATION;
416 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
419 This->uniformResourceLocatorA.lpVtbl = &uniformResourceLocatorAVtbl;
420 This->uniformResourceLocatorW.lpVtbl = &uniformResourceLocatorWVtbl;
421 This->persistFile.lpVtbl = &persistFileVtbl;
423 hr = Unknown_QueryInterface(This, riid, ppv);
425 SHDOCVW_LockModule();
431 return E_OUTOFMEMORY;