1 /*
2 * Copyright 2008 Damjan Jovanovic
3 *
4 * ShellLink's barely documented cousin that handles URLs.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 /*
22 * TODO:
23 * fd.o desktop and menu integration
24 * Implement the IShellLinkA/W interfaces
25 * Handle the SetURL flags
26 * Loading .url files
27 * Implement any other interfaces? Does any software actually use them?
28 *
29 * The installer for the Zuma Deluxe Popcap game is good for testing.
30 */
31
32 #include "wine/debug.h"
33 #include "shdocvw.h"
34 #include "objidl.h"
35 #include "shobjidl.h"
36 #include "intshcut.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
39
40 typedef struct
41 {
42 IUniformResourceLocatorA uniformResourceLocatorA;
43 IUniformResourceLocatorW uniformResourceLocatorW;
44 IPersistFile persistFile;
45
46 LONG refCount;
47
48 WCHAR *url;
49 BOOLEAN isDirty;
50 LPOLESTR currentFile;
51 } InternetShortcut;
52
53 /* utility functions */
54
55 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
56 {
57 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, uniformResourceLocatorA));
58 }
59
60 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
61 {
62 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, uniformResourceLocatorW));
63 }
64
65 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
66 {
67 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, persistFile));
68 }
69
70 /* interface functions */
71
72 static HRESULT WINAPI Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
73 {
74 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
75 *ppvObject = NULL;
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))
85 {
86 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
87 return E_NOINTERFACE;
88 }
89 else if (IsEqualGUID(&IID_IShellLinkW, riid))
90 {
91 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
92 return E_NOINTERFACE;
93 }
94 else
95 {
96 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
97 return E_NOINTERFACE;
98 }
99 IUnknown_AddRef((IUnknown*)*ppvObject);
100 return S_OK;
101 }
102
103 static ULONG WINAPI Unknown_AddRef(InternetShortcut *This)
104 {
105 TRACE("(%p)\n", This);
106 return InterlockedIncrement(&This->refCount);
107 }
108
109 static ULONG WINAPI Unknown_Release(InternetShortcut *This)
110 {
111 ULONG count;
112 TRACE("(%p)\n", This);
113 count = InterlockedDecrement(&This->refCount);
114 if (count == 0)
115 {
116 CoTaskMemFree(This->url);
117 CoTaskMemFree(This->currentFile);
118 heap_free(This);
119 SHDOCVW_UnlockModule();
120 }
121 return count;
122 }
123
124 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
125 {
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);
129 }
130
131 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
132 {
133 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
134 TRACE("(%p)\n", url);
135 return Unknown_AddRef(This);
136 }
137
138 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
139 {
140 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
141 TRACE("(%p)\n", url);
142 return Unknown_Release(This);
143 }
144
145 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
146 {
147 WCHAR *newURL = NULL;
148 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
149 TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags);
150 if (dwInFlags != 0)
151 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
152 if (pcszURL != NULL)
153 {
154 newURL = co_strdupW(pcszURL);
155 if (newURL == NULL)
156 return E_OUTOFMEMORY;
157 }
158 CoTaskMemFree(This->url);
159 This->url = newURL;
160 This->isDirty = TRUE;
161 return S_OK;
162 }
163
164 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
165 {
166 HRESULT hr = S_OK;
167 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
168 TRACE("(%p, %p)\n", url, ppszURL);
169 if (This->url == NULL)
170 *ppszURL = NULL;
171 else
172 {
173 *ppszURL = co_strdupW(This->url);
174 if (*ppszURL == NULL)
175 hr = E_OUTOFMEMORY;
176 }
177 return hr;
178 }
179
180 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
181 {
182 FIXME("(%p, %p): stub\n", url, pCommandInfo);
183 return E_NOTIMPL;
184 }
185
186 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
187 {
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);
191 }
192
193 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
194 {
195 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
196 TRACE("(%p)\n", url);
197 return Unknown_AddRef(This);
198 }
199
200 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
201 {
202 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
203 TRACE("(%p)\n", url);
204 return Unknown_Release(This);
205 }
206
207 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
208 {
209 WCHAR *newURL = NULL;
210 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
211 TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags);
212 if (dwInFlags != 0)
213 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
214 if (pcszURL != NULL)
215 {
216 newURL = co_strdupAtoW(pcszURL);
217 if (newURL == NULL)
218 return E_OUTOFMEMORY;
219 }
220 CoTaskMemFree(This->url);
221 This->url = newURL;
222 This->isDirty = TRUE;
223 return S_OK;
224 }
225
226 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
227 {
228 HRESULT hr = S_OK;
229 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
230 TRACE("(%p, %p)\n", url, ppszURL);
231 if (This->url == NULL)
232 *ppszURL = NULL;
233 else
234 {
235 *ppszURL = co_strdupWtoA(This->url);
236 if (*ppszURL == NULL)
237 hr = E_OUTOFMEMORY;
238 }
239 return hr;
240 }
241
242 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
243 {
244 FIXME("(%p, %p): stub\n", url, pCommandInfo);
245 return E_NOTIMPL;
246 }
247
248 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
249 {
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);
253 }
254
255 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
256 {
257 InternetShortcut *This = impl_from_IPersistFile(pFile);
258 TRACE("(%p)\n", pFile);
259 return Unknown_AddRef(This);
260 }
261
262 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
263 {
264 InternetShortcut *This = impl_from_IPersistFile(pFile);
265 TRACE("(%p)\n", pFile);
266 return Unknown_Release(This);
267 }
268
269 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
270 {
271 TRACE("(%p, %p)\n", pFile, pClassID);
272 *pClassID = CLSID_InternetShortcut;
273 return S_OK;
274 }
275
276 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
277 {
278 InternetShortcut *This = impl_from_IPersistFile(pFile);
279 TRACE("(%p)\n", pFile);
280 return This->isDirty ? S_OK : S_FALSE;
281 }
282
283 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
284 {
285 FIXME("(%p, %p, 0x%x): stub\n", pFile, pszFileName, dwMode);
286 return E_NOTIMPL;
287 }
288
289 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
290 {
291 HRESULT hr = S_OK;
292 INT len;
293 CHAR *url;
294 InternetShortcut *This = impl_from_IPersistFile(pFile);
295
296 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
297
298 if (pszFileName != NULL && fRemember)
299 {
300 LPOLESTR oldFile = This->currentFile;
301 This->currentFile = co_strdupW(pszFileName);
302 if (This->currentFile == NULL)
303 {
304 This->currentFile = oldFile;
305 return E_OUTOFMEMORY;
306 }
307 CoTaskMemFree(oldFile);
308 }
309 if (This->url == NULL)
310 return E_FAIL;
311
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=..."
316 */
317 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
318 url = heap_alloc(len);
319 if (url != NULL)
320 {
321 HANDLE file;
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)
325 {
326 DWORD bytesWritten;
327 char str_header[] = "[InternetShortcut]";
328 char str_URL[] = "URL=";
329 char str_eol[] = "\r\n";
330
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);
336 CloseHandle(file);
337 if (pszFileName == NULL || fRemember)
338 This->isDirty = FALSE;
339 }
340 else
341 hr = E_FAIL;
342 heap_free(url);
343 }
344 else
345 hr = E_OUTOFMEMORY;
346
347 return hr;
348 }
349
350 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
351 {
352 FIXME("(%p, %p): stub\n", pFile, pszFileName);
353 return E_NOTIMPL;
354 }
355
356 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
357 {
358 HRESULT hr = S_OK;
359 InternetShortcut *This = impl_from_IPersistFile(pFile);
360 TRACE("(%p, %p)\n", pFile, ppszFileName);
361 if (This->currentFile == NULL)
362 *ppszFileName = NULL;
363 else
364 {
365 *ppszFileName = co_strdupW(This->currentFile);
366 if (*ppszFileName == NULL)
367 hr = E_OUTOFMEMORY;
368 }
369 return hr;
370 }
371
372
373
374 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
375 UniformResourceLocatorW_QueryInterface,
376 UniformResourceLocatorW_AddRef,
377 UniformResourceLocatorW_Release,
378 UniformResourceLocatorW_SetUrl,
379 UniformResourceLocatorW_GetUrl,
380 UniformResourceLocatorW_InvokeCommand
381 };
382
383 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
384 UniformResourceLocatorA_QueryInterface,
385 UniformResourceLocatorA_AddRef,
386 UniformResourceLocatorA_Release,
387 UniformResourceLocatorA_SetUrl,
388 UniformResourceLocatorA_GetUrl,
389 UniformResourceLocatorA_InvokeCommand
390 };
391
392 static const IPersistFileVtbl persistFileVtbl = {
393 PersistFile_QueryInterface,
394 PersistFile_AddRef,
395 PersistFile_Release,
396 PersistFile_GetClassID,
397 PersistFile_IsDirty,
398 PersistFile_Load,
399 PersistFile_Save,
400 PersistFile_SaveCompleted,
401 PersistFile_GetCurFile
402 };
403
404 HRESULT InternetShortcut_Create(IUnknown *pOuter, REFIID riid, void **ppv)
405 {
406 InternetShortcut *This;
407 HRESULT hr;
408
409 TRACE("(%p, %s, %p)\n", pOuter, debugstr_guid(riid), ppv);
410
411 *ppv = NULL;
412
413 if(pOuter)
414 return CLASS_E_NOAGGREGATION;
415
416 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
417 if (This)
418 {
419 This->uniformResourceLocatorA.lpVtbl = &uniformResourceLocatorAVtbl;
420 This->uniformResourceLocatorW.lpVtbl = &uniformResourceLocatorWVtbl;
421 This->persistFile.lpVtbl = &persistFileVtbl;
422 This->refCount = 0;
423 hr = Unknown_QueryInterface(This, riid, ppv);
424 if (SUCCEEDED(hr))
425 SHDOCVW_LockModule();
426 else
427 heap_free(This);
428 return hr;
429 }
430 else
431 return E_OUTOFMEMORY;
432 }
433
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.