1 /* 2 * Implementation of hyperlinking (hlink.dll) 3 * 4 * Copyright 2005 Aric Stewart for CodeWeavers 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 #include "hlink_private.h" 22 23 #include "winreg.h" 24 #include "hlguids.h" 25 26 #include "wine/debug.h" 27 28 WINE_DEFAULT_DEBUG_CHANNEL(hlink); 29 30 typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown*, REFIID, LPVOID*); 31 32 typedef struct 33 { 34 const IClassFactoryVtbl *lpVtbl; 35 LPFNCREATEINSTANCE lpfnCI; 36 } CFImpl; 37 38 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 39 { 40 TRACE("%p %d %p\n", hinstDLL, fdwReason, lpvReserved); 41 42 switch (fdwReason) 43 { 44 case DLL_PROCESS_ATTACH: 45 DisableThreadLibraryCalls(hinstDLL); 46 break; 47 case DLL_PROCESS_DETACH: 48 break; 49 } 50 return TRUE; 51 } 52 53 /*********************************************************************** 54 * DllCanUnloadNow (HLINK.@) 55 */ 56 HRESULT WINAPI DllCanUnloadNow( void ) 57 { 58 return S_OK; 59 } 60 61 /*********************************************************************** 62 * HlinkCreateFromMoniker (HLINK.@) 63 */ 64 HRESULT WINAPI HlinkCreateFromMoniker( IMoniker *pimkTrgt, LPCWSTR pwzLocation, 65 LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData, 66 IUnknown* piunkOuter, REFIID riid, void** ppvObj) 67 { 68 IHlink *hl = NULL; 69 HRESULT r = S_OK; 70 71 TRACE("%p %s %s %p %i %p %s %p\n", pimkTrgt, debugstr_w(pwzLocation), 72 debugstr_w(pwzFriendlyName), pihlsite, dwSiteData, piunkOuter, 73 debugstr_guid(riid), ppvObj); 74 75 r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl); 76 if (FAILED(r)) 77 return r; 78 79 IHlink_SetMonikerReference(hl, HLINKSETF_LOCATION | HLINKSETF_TARGET, pimkTrgt, pwzLocation); 80 81 if (pwzFriendlyName) 82 IHlink_SetFriendlyName(hl, pwzFriendlyName); 83 if (pihlsite) 84 IHlink_SetHlinkSite(hl, pihlsite, dwSiteData); 85 86 *ppvObj = hl; 87 88 TRACE("Returning %i\n",r); 89 90 return r; 91 } 92 93 /*********************************************************************** 94 * HlinkCreateFromString (HLINK.@) 95 */ 96 HRESULT WINAPI HlinkCreateFromString( LPCWSTR pwzTarget, LPCWSTR pwzLocation, 97 LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData, 98 IUnknown* piunkOuter, REFIID riid, void** ppvObj) 99 { 100 IHlink *hl = NULL; 101 HRESULT r = S_OK; 102 WCHAR *hash, *tgt; 103 const WCHAR *loc; 104 105 TRACE("%s %s %s %p %i %p %s %p\n", debugstr_w(pwzTarget), 106 debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), pihlsite, 107 dwSiteData, piunkOuter, debugstr_guid(riid), ppvObj); 108 109 r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl); 110 if (FAILED(r)) 111 return r; 112 113 if (pwzTarget) 114 { 115 hash = strchrW(pwzTarget, '#'); 116 if (hash) 117 { 118 if (hash == pwzTarget) 119 tgt = NULL; 120 else 121 { 122 int tgt_len = hash - pwzTarget; 123 tgt = heap_alloc((tgt_len + 1) * sizeof(WCHAR)); 124 if (!tgt) 125 return E_OUTOFMEMORY; 126 memcpy(tgt, pwzTarget, tgt_len * sizeof(WCHAR)); 127 tgt[tgt_len] = 0; 128 } 129 if (!pwzLocation) 130 loc = hash + 1; 131 else 132 loc = pwzLocation; 133 } 134 else 135 { 136 tgt = hlink_strdupW(pwzTarget); 137 if (!tgt) 138 return E_OUTOFMEMORY; 139 loc = pwzLocation; 140 } 141 } 142 else 143 { 144 tgt = NULL; 145 loc = pwzLocation; 146 } 147 148 IHlink_SetStringReference(hl, HLINKSETF_TARGET | HLINKSETF_LOCATION, tgt, loc); 149 150 heap_free(tgt); 151 152 if (pwzFriendlyName) 153 IHlink_SetFriendlyName(hl, pwzFriendlyName); 154 155 if (pihlsite) 156 IHlink_SetHlinkSite(hl, pihlsite, dwSiteData); 157 158 TRACE("Returning %i\n",r); 159 *ppvObj = hl; 160 161 return r; 162 } 163 164 165 /*********************************************************************** 166 * HlinkCreateBrowseContext (HLINK.@) 167 */ 168 HRESULT WINAPI HlinkCreateBrowseContext( IUnknown* piunkOuter, REFIID riid, void** ppvObj) 169 { 170 HRESULT r = S_OK; 171 172 TRACE("%p %s %p\n", piunkOuter, debugstr_guid(riid), ppvObj); 173 174 r = CoCreateInstance(&CLSID_StdHlinkBrowseContext, piunkOuter, CLSCTX_INPROC_SERVER, riid, ppvObj); 175 176 TRACE("returning %i\n",r); 177 178 return r; 179 } 180 181 /*********************************************************************** 182 * HlinkNavigate (HLINK.@) 183 */ 184 HRESULT WINAPI HlinkNavigate(IHlink *phl, IHlinkFrame *phlFrame, 185 DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pbsc, 186 IHlinkBrowseContext *phlbc) 187 { 188 HRESULT r = S_OK; 189 190 TRACE("%p %p %i %p %p %p\n", phl, phlFrame, grfHLNF, pbc, pbsc, phlbc); 191 192 if (phlFrame) 193 r = IHlinkFrame_Navigate(phlFrame, grfHLNF, pbc, pbsc, phl); 194 else if (phl) 195 r = IHlink_Navigate(phl, grfHLNF, pbc, pbsc, phlbc); 196 197 return r; 198 } 199 200 /*********************************************************************** 201 * HlinkOnNavigate (HLINK.@) 202 */ 203 HRESULT WINAPI HlinkOnNavigate( IHlinkFrame *phlFrame, 204 IHlinkBrowseContext* phlbc, DWORD grfHLNF, IMoniker *pmkTarget, 205 LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, ULONG* puHLID) 206 { 207 HRESULT r = S_OK; 208 209 TRACE("%p %p %i %p %s %s %p\n",phlFrame, phlbc, grfHLNF, pmkTarget, 210 debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID); 211 212 r = IHlinkBrowseContext_OnNavigateHlink(phlbc, grfHLNF, pmkTarget, 213 pwzLocation, pwzFriendlyName, puHLID); 214 215 if (phlFrame) 216 r = IHlinkFrame_OnNavigate(phlFrame,grfHLNF,pmkTarget, pwzLocation, 217 pwzFriendlyName, 0); 218 219 return r; 220 } 221 222 /*********************************************************************** 223 * HlinkCreateFromData (HLINK.@) 224 */ 225 HRESULT WINAPI HlinkCreateFromData(IDataObject *piDataObj, 226 IHlinkSite *pihlsite, DWORD dwSiteData, IUnknown *piunkOuter, 227 REFIID riid, void **ppvObj) 228 { 229 FIXME("%p %p %d %p %p %p\n", 230 piDataObj, pihlsite, dwSiteData, piunkOuter, riid, ppvObj); 231 *ppvObj = NULL; 232 return E_NOTIMPL; 233 } 234 235 /*********************************************************************** 236 * HlinkQueryCreateFromData (HLINK.@) 237 */ 238 HRESULT WINAPI HlinkQueryCreateFromData(IDataObject* piDataObj) 239 { 240 FIXME("%p\n", piDataObj); 241 return E_NOTIMPL; 242 } 243 244 /*********************************************************************** 245 * HlinkNavigateToStringReference (HLINK.@) 246 */ 247 HRESULT WINAPI HlinkNavigateToStringReference( LPCWSTR pwzTarget, 248 LPCWSTR pwzLocation, IHlinkSite *pihlsite, DWORD dwSiteData, 249 IHlinkFrame *pihlframe, DWORD grfHLNF, LPBC pibc, 250 IBindStatusCallback *pibsc, IHlinkBrowseContext *pihlbc) 251 { 252 HRESULT r; 253 IHlink *hlink = NULL; 254 255 FIXME("%s %s %p %08x %p %08x %p %p %p\n", 256 debugstr_w(pwzTarget), debugstr_w(pwzLocation), pihlsite, 257 dwSiteData, pihlframe, grfHLNF, pibc, pibsc, pihlbc); 258 259 r = HlinkCreateFromString( pwzTarget, pwzLocation, NULL, pihlsite, 260 dwSiteData, NULL, &IID_IHlink, (LPVOID*) &hlink ); 261 if (SUCCEEDED(r)) 262 r = HlinkNavigate(hlink, pihlframe, grfHLNF, pibc, pibsc, pihlbc); 263 264 return r; 265 } 266 267 /*********************************************************************** 268 * HlinkIsShortcut (HLINK.@) 269 */ 270 HRESULT WINAPI HlinkIsShortcut(LPCWSTR pwzFileName) 271 { 272 int len; 273 274 static const WCHAR url_ext[] = {'.','u','r','l',0}; 275 276 TRACE("(%s)\n", debugstr_w(pwzFileName)); 277 278 if(!pwzFileName) 279 return E_INVALIDARG; 280 281 len = strlenW(pwzFileName)-4; 282 if(len < 0) 283 return S_FALSE; 284 285 return strcmpiW(pwzFileName+len, url_ext) ? S_FALSE : S_OK; 286 } 287 288 /*********************************************************************** 289 * HlinkGetSpecialReference (HLINK.@) 290 */ 291 HRESULT WINAPI HlinkGetSpecialReference(ULONG uReference, LPWSTR *ppwzReference) 292 { 293 DWORD res, type, size = 100; 294 LPCWSTR value_name; 295 WCHAR *buf; 296 HKEY hkey; 297 298 static const WCHAR start_pageW[] = {'S','t','a','r','t',' ','P','a','g','e',0}; 299 static const WCHAR search_pageW[] = {'S','e','a','r','c','h',' ','P','a','g','e',0}; 300 301 static const WCHAR ie_main_keyW[] = 302 {'S','o','f','t','w','a','r','e', 303 '\\','M','i','c','r','o','s','o','f','t','\\', 304 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r', 305 '\\','M','a','i','n',0}; 306 307 TRACE("(%u %p)\n", uReference, ppwzReference); 308 309 *ppwzReference = NULL; 310 311 switch(uReference) { 312 case HLSR_HOME: 313 value_name = start_pageW; 314 break; 315 case HLSR_SEARCHPAGE: 316 value_name = search_pageW; 317 break; 318 case HLSR_HISTORYFOLDER: 319 return E_NOTIMPL; 320 default: 321 return E_INVALIDARG; 322 } 323 324 res = RegOpenKeyW(HKEY_CURRENT_USER, ie_main_keyW, &hkey); 325 if(res != ERROR_SUCCESS) { 326 WARN("Could not open key: %u\n", res); 327 return HRESULT_FROM_WIN32(res); 328 } 329 330 buf = CoTaskMemAlloc(size); 331 res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size); 332 buf = CoTaskMemRealloc(buf, size); 333 if(res == ERROR_MORE_DATA) 334 res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size); 335 RegCloseKey(hkey); 336 if(res != ERROR_SUCCESS) { 337 WARN("Could not query value %s: %u\n", debugstr_w(value_name), res); 338 CoTaskMemFree(buf); 339 return HRESULT_FROM_WIN32(res); 340 } 341 342 *ppwzReference = buf; 343 return S_OK; 344 } 345 346 /*********************************************************************** 347 * HlinkTranslateURL (HLINK.@) 348 */ 349 HRESULT WINAPI HlinkTranslateURL(LPCWSTR pwzURL, DWORD grfFlags, LPWSTR *ppwzTranslatedURL) 350 { 351 FIXME("(%s %08x %p)\n", debugstr_w(pwzURL), grfFlags, ppwzTranslatedURL); 352 return E_NOTIMPL; 353 } 354 355 /*********************************************************************** 356 * HlinkUpdateStackItem (HLINK.@) 357 */ 358 HRESULT WINAPI HlinkUpdateStackItem(IHlinkFrame *pihlframe, IHlinkBrowseContext *pihlbc, 359 ULONG uHLID, IMoniker *pimkTrgt, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName) 360 { 361 FIXME("(%p %p %u %p %s %s)\n", pihlframe, pihlbc, uHLID, pimkTrgt, debugstr_w(pwzLocation), 362 debugstr_w(pwzFriendlyName)); 363 return E_NOTIMPL; 364 } 365 366 /*********************************************************************** 367 * HlinkParseDisplayName (HLINK.@) 368 */ 369 HRESULT WINAPI HlinkParseDisplayName(LPBC pibc, LPCWSTR pwzDisplayName, BOOL fNoForceAbs, 370 ULONG *pcchEaten, IMoniker **ppimk) 371 { 372 HRESULT hres; 373 374 TRACE("(%p %s %x %p %p)\n", pibc, debugstr_w(pwzDisplayName), fNoForceAbs, pcchEaten, ppimk); 375 376 if(fNoForceAbs) 377 FIXME("Unsupported fNoForceAbs\n"); 378 379 hres = MkParseDisplayNameEx(pibc, pwzDisplayName, pcchEaten, ppimk); 380 if(SUCCEEDED(hres)) 381 return hres; 382 383 hres = MkParseDisplayName(pibc, pwzDisplayName, pcchEaten, ppimk); 384 if(SUCCEEDED(hres)) 385 return hres; 386 387 hres = CreateFileMoniker(pwzDisplayName, ppimk); 388 if(SUCCEEDED(hres)) 389 *pcchEaten = strlenW(pwzDisplayName); 390 391 return hres; 392 } 393 394 /*********************************************************************** 395 * HlinkResolveMonikerForData (HLINK.@) 396 */ 397 HRESULT WINAPI HlinkResolveMonikerForData(LPMONIKER pimkReference, DWORD reserved, LPBC pibc, 398 ULONG cFmtetc, FORMATETC *rgFmtetc, IBindStatusCallback *pibsc, LPMONIKER pimkBase) 399 { 400 LPOLESTR name = NULL; 401 IBindCtx *bctx; 402 DWORD mksys = 0; 403 void *obj = NULL; 404 HRESULT hres; 405 406 TRACE("(%p %x %p %d %p %p %p)\n", pimkReference, reserved, pibc, cFmtetc, rgFmtetc, pibsc, pimkBase); 407 408 if(cFmtetc || rgFmtetc || pimkBase) 409 FIXME("Unsupported args\n"); 410 411 hres = RegisterBindStatusCallback(pibc, pibsc, NULL /* FIXME */, 0); 412 if(FAILED(hres)) 413 return hres; 414 415 hres = IMoniker_IsSystemMoniker(pimkReference, &mksys); 416 if(SUCCEEDED(hres) && mksys != MKSYS_URLMONIKER) 417 WARN("sysmk = %x\n", mksys); 418 419 /* FIXME: What is it for? */ 420 CreateBindCtx(0, &bctx); 421 hres = IMoniker_GetDisplayName(pimkReference, bctx, NULL, &name); 422 IBindCtx_Release(bctx); 423 if(SUCCEEDED(hres)) { 424 TRACE("got display name %s\n", debugstr_w(name)); 425 CoTaskMemFree(name); 426 } 427 428 return IMoniker_BindToStorage(pimkReference, pibc, NULL, &IID_IUnknown, &obj); 429 } 430 431 static HRESULT WINAPI HLinkCF_fnQueryInterface ( LPCLASSFACTORY iface, 432 REFIID riid, LPVOID *ppvObj) 433 { 434 CFImpl *This = (CFImpl *)iface; 435 436 TRACE("(%p)->(%s)\n",This,debugstr_guid(riid)); 437 438 *ppvObj = NULL; 439 440 if (IsEqualIID(riid, &IID_IUnknown) || 441 IsEqualIID(riid, &IID_IClassFactory)) 442 { 443 *ppvObj = This; 444 return S_OK; 445 } 446 447 TRACE("-- E_NOINTERFACE\n"); 448 return E_NOINTERFACE; 449 } 450 451 static ULONG WINAPI HLinkCF_fnAddRef (LPCLASSFACTORY iface) 452 { 453 return 2; 454 } 455 456 static ULONG WINAPI HLinkCF_fnRelease(LPCLASSFACTORY iface) 457 { 458 return 1; 459 } 460 461 static HRESULT WINAPI HLinkCF_fnCreateInstance( LPCLASSFACTORY iface, 462 LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject) 463 { 464 CFImpl *This = (CFImpl *)iface; 465 466 TRACE("%p->(%p,%s,%p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObject); 467 468 *ppvObject = NULL; 469 470 return This->lpfnCI(pUnkOuter, riid, ppvObject); 471 } 472 473 static HRESULT WINAPI HLinkCF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock) 474 { 475 FIXME("%p %d\n", iface, fLock); 476 return E_NOTIMPL; 477 } 478 479 static const IClassFactoryVtbl hlcfvt = 480 { 481 HLinkCF_fnQueryInterface, 482 HLinkCF_fnAddRef, 483 HLinkCF_fnRelease, 484 HLinkCF_fnCreateInstance, 485 HLinkCF_fnLockServer 486 }; 487 488 static CFImpl HLink_cf = { &hlcfvt, HLink_Constructor }; 489 static CFImpl HLinkBrowseContext_cf = { &hlcfvt, HLinkBrowseContext_Constructor }; 490 491 /*********************************************************************** 492 * DllGetClassObject (HLINK.@) 493 */ 494 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) 495 { 496 IClassFactory *pcf = NULL; 497 498 TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv); 499 500 if (!ppv) 501 return E_INVALIDARG; 502 *ppv = NULL; 503 504 if (IsEqualIID(rclsid, &CLSID_StdHlink)) 505 pcf = (IClassFactory*) &HLink_cf; 506 else if (IsEqualIID(rclsid, &CLSID_StdHlinkBrowseContext)) 507 pcf = (IClassFactory*) &HLinkBrowseContext_cf; 508 else 509 return CLASS_E_CLASSNOTAVAILABLE; 510 511 return IClassFactory_QueryInterface(pcf, iid, ppv); 512 } 513 514 static HRESULT register_clsid(LPCGUID guid) 515 { 516 static const WCHAR clsid[] = 517 {'C','L','S','I','D','\\',0}; 518 static const WCHAR ips[] = 519 {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0}; 520 static const WCHAR hlink[] = 521 {'h','l','i','n','k','.','d','l','l',0}; 522 static const WCHAR threading_model[] = 523 {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; 524 static const WCHAR apartment[] = 525 {'A','p','a','r','t','m','e','n','t',0}; 526 WCHAR path[80]; 527 HKEY key = NULL; 528 LONG r; 529 530 lstrcpyW(path, clsid); 531 StringFromGUID2(guid, &path[6], 80); 532 lstrcatW(path, ips); 533 r = RegCreateKeyW(HKEY_CLASSES_ROOT, path, &key); 534 if (r != ERROR_SUCCESS) 535 return E_FAIL; 536 537 RegSetValueExW(key, NULL, 0, REG_SZ, (const BYTE *)hlink, sizeof hlink); 538 RegSetValueExW(key, threading_model, 0, REG_SZ, (const BYTE *)apartment, sizeof apartment); 539 RegCloseKey(key); 540 541 return S_OK; 542 } 543 544 /*********************************************************************** 545 * DllRegisterServer (HLINK.@) 546 */ 547 HRESULT WINAPI DllRegisterServer(void) 548 { 549 HRESULT r; 550 551 r = register_clsid(&CLSID_StdHlink); 552 if (SUCCEEDED(r)) 553 r = register_clsid(&CLSID_StdHlinkBrowseContext); 554 555 return S_OK; 556 } 557