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