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 * Implement the IShellLinkA/W interfaces
24 * Handle the SetURL flags
25 * Implement any other interfaces? Does any software actually use them?
26 *
27 * The installer for the Zuma Deluxe Popcap game is good for testing.
28 */
29
30 #include "wine/debug.h"
31 #include "shdocvw.h"
32 #include "objidl.h"
33 #include "shobjidl.h"
34 #include "intshcut.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
37
38 typedef struct
39 {
40 IUniformResourceLocatorA uniformResourceLocatorA;
41 IUniformResourceLocatorW uniformResourceLocatorW;
42 IPersistFile persistFile;
43
44 LONG refCount;
45
46 WCHAR *url;
47 BOOLEAN isDirty;
48 LPOLESTR currentFile;
49 } InternetShortcut;
50
51 /* utility functions */
52
53 static inline InternetShortcut* impl_from_IUniformResourceLocatorA(IUniformResourceLocatorA *iface)
54 {
55 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, uniformResourceLocatorA));
56 }
57
58 static inline InternetShortcut* impl_from_IUniformResourceLocatorW(IUniformResourceLocatorW *iface)
59 {
60 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, uniformResourceLocatorW));
61 }
62
63 static inline InternetShortcut* impl_from_IPersistFile(IPersistFile *iface)
64 {
65 return (InternetShortcut*)((char*)iface - FIELD_OFFSET(InternetShortcut, persistFile));
66 }
67
68 static BOOL StartLinkProcessor(LPCOLESTR szLink)
69 {
70 static const WCHAR szFormat[] = {
71 'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e',
72 ' ','-','w',' ','-','u',' ','"','%','s','"',0 };
73 LONG len;
74 LPWSTR buffer;
75 STARTUPINFOW si;
76 PROCESS_INFORMATION pi;
77 BOOL ret;
78
79 len = sizeof(szFormat) + lstrlenW( szLink ) * sizeof(WCHAR);
80 buffer = heap_alloc( len );
81 if( !buffer )
82 return FALSE;
83
84 wsprintfW( buffer, szFormat, szLink );
85
86 TRACE("starting %s\n",debugstr_w(buffer));
87
88 memset(&si, 0, sizeof(si));
89 si.cb = sizeof(si);
90
91 ret = CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
92
93 HeapFree( GetProcessHeap(), 0, buffer );
94
95 if (ret)
96 {
97 CloseHandle( pi.hProcess );
98 CloseHandle( pi.hThread );
99 }
100
101 return ret;
102 }
103
104 /* interface functions */
105
106 static HRESULT Unknown_QueryInterface(InternetShortcut *This, REFIID riid, PVOID *ppvObject)
107 {
108 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
109 *ppvObject = NULL;
110 if (IsEqualGUID(&IID_IUnknown, riid))
111 *ppvObject = &This->uniformResourceLocatorA;
112 else if (IsEqualGUID(&IID_IUniformResourceLocatorA, riid))
113 *ppvObject = &This->uniformResourceLocatorA;
114 else if (IsEqualGUID(&IID_IUniformResourceLocatorW, riid))
115 *ppvObject = &This->uniformResourceLocatorW;
116 else if (IsEqualGUID(&IID_IPersistFile, riid))
117 *ppvObject = &This->persistFile;
118 else if (IsEqualGUID(&IID_IShellLinkA, riid))
119 {
120 FIXME("The IShellLinkA interface is not yet supported by InternetShortcut\n");
121 return E_NOINTERFACE;
122 }
123 else if (IsEqualGUID(&IID_IShellLinkW, riid))
124 {
125 FIXME("The IShellLinkW interface is not yet supported by InternetShortcut\n");
126 return E_NOINTERFACE;
127 }
128 else
129 {
130 FIXME("Interface with GUID %s not yet implemented by InternetShortcut\n", debugstr_guid(riid));
131 return E_NOINTERFACE;
132 }
133 IUnknown_AddRef((IUnknown*)*ppvObject);
134 return S_OK;
135 }
136
137 static ULONG Unknown_AddRef(InternetShortcut *This)
138 {
139 TRACE("(%p)\n", This);
140 return InterlockedIncrement(&This->refCount);
141 }
142
143 static ULONG Unknown_Release(InternetShortcut *This)
144 {
145 ULONG count;
146 TRACE("(%p)\n", This);
147 count = InterlockedDecrement(&This->refCount);
148 if (count == 0)
149 {
150 CoTaskMemFree(This->url);
151 CoTaskMemFree(This->currentFile);
152 heap_free(This);
153 SHDOCVW_UnlockModule();
154 }
155 return count;
156 }
157
158 static HRESULT WINAPI UniformResourceLocatorW_QueryInterface(IUniformResourceLocatorW *url, REFIID riid, PVOID *ppvObject)
159 {
160 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
161 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
162 return Unknown_QueryInterface(This, riid, ppvObject);
163 }
164
165 static ULONG WINAPI UniformResourceLocatorW_AddRef(IUniformResourceLocatorW *url)
166 {
167 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
168 TRACE("(%p)\n", url);
169 return Unknown_AddRef(This);
170 }
171
172 static ULONG WINAPI UniformResourceLocatorW_Release(IUniformResourceLocatorW *url)
173 {
174 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
175 TRACE("(%p)\n", url);
176 return Unknown_Release(This);
177 }
178
179 static HRESULT WINAPI UniformResourceLocatorW_SetUrl(IUniformResourceLocatorW *url, LPCWSTR pcszURL, DWORD dwInFlags)
180 {
181 WCHAR *newURL = NULL;
182 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
183 TRACE("(%p, %s, 0x%x)\n", url, debugstr_w(pcszURL), dwInFlags);
184 if (dwInFlags != 0)
185 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
186 if (pcszURL != NULL)
187 {
188 newURL = co_strdupW(pcszURL);
189 if (newURL == NULL)
190 return E_OUTOFMEMORY;
191 }
192 CoTaskMemFree(This->url);
193 This->url = newURL;
194 This->isDirty = TRUE;
195 return S_OK;
196 }
197
198 static HRESULT WINAPI UniformResourceLocatorW_GetUrl(IUniformResourceLocatorW *url, LPWSTR *ppszURL)
199 {
200 HRESULT hr = S_OK;
201 InternetShortcut *This = impl_from_IUniformResourceLocatorW(url);
202 TRACE("(%p, %p)\n", url, ppszURL);
203 if (This->url == NULL)
204 *ppszURL = NULL;
205 else
206 {
207 *ppszURL = co_strdupW(This->url);
208 if (*ppszURL == NULL)
209 hr = E_OUTOFMEMORY;
210 }
211 return hr;
212 }
213
214 static HRESULT WINAPI UniformResourceLocatorW_InvokeCommand(IUniformResourceLocatorW *url, PURLINVOKECOMMANDINFOW pCommandInfo)
215 {
216 FIXME("(%p, %p): stub\n", url, pCommandInfo);
217 return E_NOTIMPL;
218 }
219
220 static HRESULT WINAPI UniformResourceLocatorA_QueryInterface(IUniformResourceLocatorA *url, REFIID riid, PVOID *ppvObject)
221 {
222 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
223 TRACE("(%p, %s, %p)\n", url, debugstr_guid(riid), ppvObject);
224 return Unknown_QueryInterface(This, riid, ppvObject);
225 }
226
227 static ULONG WINAPI UniformResourceLocatorA_AddRef(IUniformResourceLocatorA *url)
228 {
229 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
230 TRACE("(%p)\n", url);
231 return Unknown_AddRef(This);
232 }
233
234 static ULONG WINAPI UniformResourceLocatorA_Release(IUniformResourceLocatorA *url)
235 {
236 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
237 TRACE("(%p)\n", url);
238 return Unknown_Release(This);
239 }
240
241 static HRESULT WINAPI UniformResourceLocatorA_SetUrl(IUniformResourceLocatorA *url, LPCSTR pcszURL, DWORD dwInFlags)
242 {
243 WCHAR *newURL = NULL;
244 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
245 TRACE("(%p, %s, 0x%x)\n", url, debugstr_a(pcszURL), dwInFlags);
246 if (dwInFlags != 0)
247 FIXME("ignoring unsupported flags 0x%x\n", dwInFlags);
248 if (pcszURL != NULL)
249 {
250 newURL = co_strdupAtoW(pcszURL);
251 if (newURL == NULL)
252 return E_OUTOFMEMORY;
253 }
254 CoTaskMemFree(This->url);
255 This->url = newURL;
256 This->isDirty = TRUE;
257 return S_OK;
258 }
259
260 static HRESULT WINAPI UniformResourceLocatorA_GetUrl(IUniformResourceLocatorA *url, LPSTR *ppszURL)
261 {
262 HRESULT hr = S_OK;
263 InternetShortcut *This = impl_from_IUniformResourceLocatorA(url);
264 TRACE("(%p, %p)\n", url, ppszURL);
265 if (This->url == NULL)
266 *ppszURL = NULL;
267 else
268 {
269 *ppszURL = co_strdupWtoA(This->url);
270 if (*ppszURL == NULL)
271 hr = E_OUTOFMEMORY;
272 }
273 return hr;
274 }
275
276 static HRESULT WINAPI UniformResourceLocatorA_InvokeCommand(IUniformResourceLocatorA *url, PURLINVOKECOMMANDINFOA pCommandInfo)
277 {
278 FIXME("(%p, %p): stub\n", url, pCommandInfo);
279 return E_NOTIMPL;
280 }
281
282 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *pFile, REFIID riid, PVOID *ppvObject)
283 {
284 InternetShortcut *This = impl_from_IPersistFile(pFile);
285 TRACE("(%p, %s, %p)\n", pFile, debugstr_guid(riid), ppvObject);
286 return Unknown_QueryInterface(This, riid, ppvObject);
287 }
288
289 static ULONG WINAPI PersistFile_AddRef(IPersistFile *pFile)
290 {
291 InternetShortcut *This = impl_from_IPersistFile(pFile);
292 TRACE("(%p)\n", pFile);
293 return Unknown_AddRef(This);
294 }
295
296 static ULONG WINAPI PersistFile_Release(IPersistFile *pFile)
297 {
298 InternetShortcut *This = impl_from_IPersistFile(pFile);
299 TRACE("(%p)\n", pFile);
300 return Unknown_Release(This);
301 }
302
303 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *pFile, CLSID *pClassID)
304 {
305 TRACE("(%p, %p)\n", pFile, pClassID);
306 *pClassID = CLSID_InternetShortcut;
307 return S_OK;
308 }
309
310 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *pFile)
311 {
312 InternetShortcut *This = impl_from_IPersistFile(pFile);
313 TRACE("(%p)\n", pFile);
314 return This->isDirty ? S_OK : S_FALSE;
315 }
316
317 static HRESULT WINAPI PersistFile_Load(IPersistFile *pFile, LPCOLESTR pszFileName, DWORD dwMode)
318 {
319 WCHAR str_header[] = {'I','n','t','e','r','n','e','t','S','h','o','r','t','c','u','t',0};
320 WCHAR str_URL[] = {'U','R','L',0};
321 WCHAR *filename = NULL;
322 HRESULT hr;
323 InternetShortcut *This = impl_from_IPersistFile(pFile);
324 TRACE("(%p, %s, 0x%x)\n", pFile, debugstr_w(pszFileName), dwMode);
325 if (dwMode != 0)
326 FIXME("ignoring unimplemented mode 0x%x\n", dwMode);
327 filename = co_strdupW(pszFileName);
328 if (filename != NULL)
329 {
330 DWORD len = 128;
331 DWORD r;
332 WCHAR *url = CoTaskMemAlloc(len*sizeof(WCHAR));
333 if (url != NULL)
334 {
335 r = GetPrivateProfileStringW(str_header, str_URL, NULL, url, len, pszFileName);
336 while (r == len-1)
337 {
338 CoTaskMemFree(url);
339 len *= 2;
340 url = CoTaskMemAlloc(len);
341 if (url == NULL)
342 break;
343 r = GetPrivateProfileStringW(str_header, str_URL, NULL, url, len, pszFileName);
344 }
345 if (r == 0)
346 hr = E_FAIL;
347 else if (url != NULL)
348 {
349 CoTaskMemFree(This->currentFile);
350 This->currentFile = filename;
351 CoTaskMemFree(This->url);
352 This->url = url;
353 This->isDirty = FALSE;
354 return S_OK;
355 }
356 else
357 hr = E_OUTOFMEMORY;
358 CoTaskMemFree(url);
359 }
360 else
361 hr = E_OUTOFMEMORY;
362 CoTaskMemFree(filename);
363 }
364 else
365 hr = E_OUTOFMEMORY;
366 return hr;
367 }
368
369 static HRESULT WINAPI PersistFile_Save(IPersistFile *pFile, LPCOLESTR pszFileName, BOOL fRemember)
370 {
371 HRESULT hr = S_OK;
372 INT len;
373 CHAR *url;
374 InternetShortcut *This = impl_from_IPersistFile(pFile);
375
376 TRACE("(%p, %s, %d)\n", pFile, debugstr_w(pszFileName), fRemember);
377
378 if (pszFileName != NULL && fRemember)
379 {
380 LPOLESTR oldFile = This->currentFile;
381 This->currentFile = co_strdupW(pszFileName);
382 if (This->currentFile == NULL)
383 {
384 This->currentFile = oldFile;
385 return E_OUTOFMEMORY;
386 }
387 CoTaskMemFree(oldFile);
388 }
389 if (This->url == NULL)
390 return E_FAIL;
391
392 /* Windows seems to always write:
393 * ASCII "[InternetShortcut]" headers
394 * ASCII names in "name=value" pairs
395 * An ASCII (probably UTF8?) value in "URL=..."
396 */
397 len = WideCharToMultiByte(CP_UTF8, 0, This->url, -1, NULL, 0, 0, 0);
398 url = heap_alloc(len);
399 if (url != NULL)
400 {
401 HANDLE file;
402 WideCharToMultiByte(CP_UTF8, 0, This->url, -1, url, len, 0, 0);
403 file = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
404 if (file != INVALID_HANDLE_VALUE)
405 {
406 DWORD bytesWritten;
407 char str_header[] = "[InternetShortcut]";
408 char str_URL[] = "URL=";
409 char str_eol[] = "\r\n";
410
411 WriteFile(file, str_header, lstrlenA(str_header), &bytesWritten, NULL);
412 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
413 WriteFile(file, str_URL, lstrlenA(str_URL), &bytesWritten, NULL);
414 WriteFile(file, url, lstrlenA(url), &bytesWritten, NULL);
415 WriteFile(file, str_eol, lstrlenA(str_eol), &bytesWritten, NULL);
416 CloseHandle(file);
417 if (pszFileName == NULL || fRemember)
418 This->isDirty = FALSE;
419 StartLinkProcessor(pszFileName);
420 }
421 else
422 hr = E_FAIL;
423 heap_free(url);
424 }
425 else
426 hr = E_OUTOFMEMORY;
427
428 return hr;
429 }
430
431 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *pFile, LPCOLESTR pszFileName)
432 {
433 FIXME("(%p, %p): stub\n", pFile, pszFileName);
434 return E_NOTIMPL;
435 }
436
437 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *pFile, LPOLESTR *ppszFileName)
438 {
439 HRESULT hr = S_OK;
440 InternetShortcut *This = impl_from_IPersistFile(pFile);
441 TRACE("(%p, %p)\n", pFile, ppszFileName);
442 if (This->currentFile == NULL)
443 *ppszFileName = NULL;
444 else
445 {
446 *ppszFileName = co_strdupW(This->currentFile);
447 if (*ppszFileName == NULL)
448 hr = E_OUTOFMEMORY;
449 }
450 return hr;
451 }
452
453
454
455 static const IUniformResourceLocatorWVtbl uniformResourceLocatorWVtbl = {
456 UniformResourceLocatorW_QueryInterface,
457 UniformResourceLocatorW_AddRef,
458 UniformResourceLocatorW_Release,
459 UniformResourceLocatorW_SetUrl,
460 UniformResourceLocatorW_GetUrl,
461 UniformResourceLocatorW_InvokeCommand
462 };
463
464 static const IUniformResourceLocatorAVtbl uniformResourceLocatorAVtbl = {
465 UniformResourceLocatorA_QueryInterface,
466 UniformResourceLocatorA_AddRef,
467 UniformResourceLocatorA_Release,
468 UniformResourceLocatorA_SetUrl,
469 UniformResourceLocatorA_GetUrl,
470 UniformResourceLocatorA_InvokeCommand
471 };
472
473 static const IPersistFileVtbl persistFileVtbl = {
474 PersistFile_QueryInterface,
475 PersistFile_AddRef,
476 PersistFile_Release,
477 PersistFile_GetClassID,
478 PersistFile_IsDirty,
479 PersistFile_Load,
480 PersistFile_Save,
481 PersistFile_SaveCompleted,
482 PersistFile_GetCurFile
483 };
484
485 HRESULT InternetShortcut_Create(IUnknown *pOuter, REFIID riid, void **ppv)
486 {
487 InternetShortcut *This;
488 HRESULT hr;
489
490 TRACE("(%p, %s, %p)\n", pOuter, debugstr_guid(riid), ppv);
491
492 *ppv = NULL;
493
494 if(pOuter)
495 return CLASS_E_NOAGGREGATION;
496
497 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(InternetShortcut));
498 if (This)
499 {
500 This->uniformResourceLocatorA.lpVtbl = &uniformResourceLocatorAVtbl;
501 This->uniformResourceLocatorW.lpVtbl = &uniformResourceLocatorWVtbl;
502 This->persistFile.lpVtbl = &persistFileVtbl;
503 This->refCount = 0;
504 hr = Unknown_QueryInterface(This, riid, ppv);
505 if (SUCCEEDED(hr))
506 SHDOCVW_LockModule();
507 else
508 heap_free(This);
509 return hr;
510 }
511 else
512 return E_OUTOFMEMORY;
513 }
514
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.