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