xref: /reactos/dll/win32/hlink/hlink_main.c (revision 62919904)
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 "rpcproxy.h"
25 #include "hlguids.h"
26 
27 #include "wine/debug.h"
28 
29 WINE_DEFAULT_DEBUG_CHANNEL(hlink);
30 
31 static HINSTANCE instance;
32 
33 typedef HRESULT (*LPFNCREATEINSTANCE)(IUnknown*, REFIID, LPVOID*);
34 
35 typedef struct
36 {
37     IClassFactory      IClassFactory_iface;
38     LPFNCREATEINSTANCE lpfnCI;
39 } CFImpl;
40 
41 static inline CFImpl *impl_from_IClassFactory(IClassFactory *iface)
42 {
43     return CONTAINING_RECORD(iface, CFImpl, IClassFactory_iface);
44 }
45 
46 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
47 {
48     TRACE("%p %d %p\n", hinstDLL, fdwReason, lpvReserved);
49 
50     switch (fdwReason)
51     {
52     case DLL_PROCESS_ATTACH:
53         instance = hinstDLL;
54         DisableThreadLibraryCalls(hinstDLL);
55         break;
56     }
57     return TRUE;
58 }
59 
60 /***********************************************************************
61  *             DllCanUnloadNow (HLINK.@)
62  */
63 HRESULT WINAPI DllCanUnloadNow( void )
64 {
65     return S_FALSE;
66 }
67 
68 /***********************************************************************
69  *             HlinkCreateFromMoniker (HLINK.@)
70  */
71 HRESULT WINAPI HlinkCreateFromMoniker( IMoniker *pimkTrgt, LPCWSTR pwzLocation,
72         LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData,
73         IUnknown* piunkOuter, REFIID riid, void** ppvObj)
74 {
75     IHlink *hl = NULL;
76     HRESULT r;
77 
78     TRACE("%p %s %s %p %i %p %s %p\n", pimkTrgt, debugstr_w(pwzLocation),
79             debugstr_w(pwzFriendlyName), pihlsite, dwSiteData, piunkOuter,
80             debugstr_guid(riid), ppvObj);
81 
82     r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl);
83     if (FAILED(r))
84         return r;
85 
86     IHlink_SetMonikerReference(hl, HLINKSETF_LOCATION | HLINKSETF_TARGET, pimkTrgt, pwzLocation);
87 
88     if (pwzFriendlyName)
89         IHlink_SetFriendlyName(hl, pwzFriendlyName);
90     if (pihlsite)
91         IHlink_SetHlinkSite(hl, pihlsite, dwSiteData);
92 
93     *ppvObj = hl;
94 
95     TRACE("Returning %i\n",r);
96 
97     return r;
98 }
99 
100 /***********************************************************************
101  *             HlinkCreateFromString (HLINK.@)
102  */
103 HRESULT WINAPI HlinkCreateFromString( LPCWSTR pwzTarget, LPCWSTR pwzLocation,
104         LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData,
105         IUnknown* piunkOuter, REFIID riid, void** ppvObj)
106 {
107     IHlink *hl = NULL;
108     HRESULT r;
109     WCHAR *hash, *tgt;
110     const WCHAR *loc;
111 
112     TRACE("%s %s %s %p %i %p %s %p\n", debugstr_w(pwzTarget),
113             debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), pihlsite,
114             dwSiteData, piunkOuter, debugstr_guid(riid), ppvObj);
115 
116     r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl);
117     if (FAILED(r))
118         return r;
119 
120     if (pwzTarget)
121     {
122         hash = strchrW(pwzTarget, '#');
123         if (hash)
124         {
125             if (hash == pwzTarget)
126                 tgt = NULL;
127             else
128             {
129                 int tgt_len = hash - pwzTarget;
130                 tgt = heap_alloc((tgt_len + 1) * sizeof(WCHAR));
131                 if (!tgt)
132                     return E_OUTOFMEMORY;
133                 memcpy(tgt, pwzTarget, tgt_len * sizeof(WCHAR));
134                 tgt[tgt_len] = 0;
135             }
136             if (!pwzLocation)
137                 loc = hash + 1;
138             else
139                 loc = pwzLocation;
140         }
141         else
142         {
143             tgt = hlink_strdupW(pwzTarget);
144             if (!tgt)
145                 return E_OUTOFMEMORY;
146             loc = pwzLocation;
147         }
148     }
149     else
150     {
151         tgt = NULL;
152         loc = pwzLocation;
153     }
154 
155     IHlink_SetStringReference(hl, HLINKSETF_TARGET | HLINKSETF_LOCATION, tgt, loc);
156 
157     heap_free(tgt);
158 
159     if (pwzFriendlyName)
160         IHlink_SetFriendlyName(hl, pwzFriendlyName);
161 
162     if (pihlsite)
163         IHlink_SetHlinkSite(hl, pihlsite, dwSiteData);
164 
165     TRACE("Returning %i\n",r);
166     *ppvObj = hl;
167 
168     return r;
169 }
170 
171 
172 /***********************************************************************
173  *             HlinkCreateBrowseContext (HLINK.@)
174  */
175 HRESULT WINAPI HlinkCreateBrowseContext( IUnknown* piunkOuter, REFIID riid, void** ppvObj)
176 {
177     TRACE("%p %s %p\n", piunkOuter, debugstr_guid(riid), ppvObj);
178     return CoCreateInstance(&CLSID_StdHlinkBrowseContext, piunkOuter, CLSCTX_INPROC_SERVER, riid, ppvObj);
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;
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, %s, %p\n", piDataObj, pihlsite, dwSiteData,
230            piunkOuter, debugstr_guid(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     TRACE("%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         IHlink_Release(hlink);
264     }
265 
266     return r;
267 }
268 
269 /***********************************************************************
270  *             HlinkIsShortcut (HLINK.@)
271  */
272 HRESULT WINAPI HlinkIsShortcut(LPCWSTR pwzFileName)
273 {
274     int len;
275 
276     static const WCHAR url_ext[] = {'.','u','r','l',0};
277 
278     TRACE("(%s)\n", debugstr_w(pwzFileName));
279 
280     if(!pwzFileName)
281         return E_INVALIDARG;
282 
283     len = strlenW(pwzFileName)-4;
284     if(len < 0)
285         return S_FALSE;
286 
287     return strcmpiW(pwzFileName+len, url_ext) ? S_FALSE : S_OK;
288 }
289 
290 /***********************************************************************
291  *             HlinkGetSpecialReference (HLINK.@)
292  */
293 HRESULT WINAPI HlinkGetSpecialReference(ULONG uReference, LPWSTR *ppwzReference)
294 {
295     DWORD res, type, size = 100;
296     LPCWSTR value_name;
297     WCHAR *buf;
298     HKEY hkey;
299 
300     static const WCHAR start_pageW[] = {'S','t','a','r','t',' ','P','a','g','e',0};
301     static const WCHAR search_pageW[] = {'S','e','a','r','c','h',' ','P','a','g','e',0};
302 
303     static const WCHAR ie_main_keyW[] =
304         {'S','o','f','t','w','a','r','e',
305          '\\','M','i','c','r','o','s','o','f','t','\\',
306          'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',
307          '\\','M','a','i','n',0};
308 
309     TRACE("(%u %p)\n", uReference, ppwzReference);
310 
311     *ppwzReference = NULL;
312 
313     switch(uReference) {
314     case HLSR_HOME:
315         value_name = start_pageW;
316         break;
317     case HLSR_SEARCHPAGE:
318         value_name = search_pageW;
319         break;
320     case HLSR_HISTORYFOLDER:
321         return E_NOTIMPL;
322     default:
323         return E_INVALIDARG;
324     }
325 
326     res = RegOpenKeyW(HKEY_CURRENT_USER, ie_main_keyW, &hkey);
327     if(res != ERROR_SUCCESS) {
328         WARN("Could not open key: %u\n", res);
329         return HRESULT_FROM_WIN32(res);
330     }
331 
332     buf = CoTaskMemAlloc(size);
333     res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size);
334     buf = CoTaskMemRealloc(buf, size);
335     if(res == ERROR_MORE_DATA)
336         res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size);
337     RegCloseKey(hkey);
338     if(res != ERROR_SUCCESS) {
339         WARN("Could not query value %s: %u\n", debugstr_w(value_name), res);
340         CoTaskMemFree(buf);
341         return HRESULT_FROM_WIN32(res);
342     }
343 
344     *ppwzReference = buf;
345     return S_OK;
346 }
347 
348 /***********************************************************************
349  *             HlinkTranslateURL (HLINK.@)
350  */
351 HRESULT WINAPI HlinkTranslateURL(LPCWSTR pwzURL, DWORD grfFlags, LPWSTR *ppwzTranslatedURL)
352 {
353     FIXME("(%s %08x %p)\n", debugstr_w(pwzURL), grfFlags, ppwzTranslatedURL);
354     return E_NOTIMPL;
355 }
356 
357 /***********************************************************************
358  *             HlinkUpdateStackItem (HLINK.@)
359  */
360 HRESULT WINAPI HlinkUpdateStackItem(IHlinkFrame *frame, IHlinkBrowseContext *bc,
361         ULONG hlid, IMoniker *target, LPCWSTR location, LPCWSTR friendly_name)
362 {
363     HRESULT hr;
364 
365     TRACE("(%p %p 0x%x %p %s %s)\n", frame, bc, hlid, target, debugstr_w(location), debugstr_w(friendly_name));
366 
367     if (!frame && !bc) return E_INVALIDARG;
368 
369     if (frame)
370         hr = IHlinkFrame_UpdateHlink(frame, hlid, target, location, friendly_name);
371     else
372         hr = IHlinkBrowseContext_UpdateHlink(bc, hlid, target, location, friendly_name);
373 
374     return hr;
375 }
376 
377 /***********************************************************************
378  *             HlinkParseDisplayName (HLINK.@)
379  */
380 HRESULT WINAPI HlinkParseDisplayName(LPBC pibc, LPCWSTR pwzDisplayName, BOOL fNoForceAbs,
381         ULONG *pcchEaten, IMoniker **ppimk)
382 {
383     static const WCHAR file_colonW[] = {'f','i','l','e',':'};
384     ULONG eaten = 0;
385     HRESULT hres;
386 
387     TRACE("(%p %s %x %p %p)\n", pibc, debugstr_w(pwzDisplayName), fNoForceAbs, pcchEaten, ppimk);
388 
389     if(fNoForceAbs)
390         FIXME("Unsupported fNoForceAbs\n");
391 
392     if(!strncmpiW(pwzDisplayName, file_colonW, ARRAY_SIZE(file_colonW))) {
393         pwzDisplayName += ARRAY_SIZE(file_colonW);
394         eaten += ARRAY_SIZE(file_colonW);
395 
396         while(*pwzDisplayName == '/') {
397             pwzDisplayName++;
398             eaten++;
399         }
400     }else {
401         hres = MkParseDisplayNameEx(pibc, pwzDisplayName, pcchEaten, ppimk);
402         if(SUCCEEDED(hres))
403             return hres;
404 
405         hres = MkParseDisplayName(pibc, pwzDisplayName, pcchEaten, ppimk);
406         if(SUCCEEDED(hres))
407             return hres;
408     }
409 
410     hres = CreateFileMoniker(pwzDisplayName, ppimk);
411     if(SUCCEEDED(hres))
412         *pcchEaten = eaten + strlenW(pwzDisplayName);
413 
414     return hres;
415 }
416 
417 /***********************************************************************
418  *             HlinkResolveMonikerForData (HLINK.@)
419  */
420 HRESULT WINAPI HlinkResolveMonikerForData(LPMONIKER pimkReference, DWORD reserved, LPBC pibc,
421         ULONG cFmtetc, FORMATETC *rgFmtetc, IBindStatusCallback *pibsc, LPMONIKER pimkBase)
422 {
423     LPOLESTR name = NULL;
424     IBindCtx *bctx;
425     DWORD mksys = 0;
426     void *obj = NULL;
427     HRESULT hres;
428 
429     TRACE("(%p %x %p %d %p %p %p)\n", pimkReference, reserved, pibc, cFmtetc, rgFmtetc, pibsc, pimkBase);
430 
431     if(cFmtetc || rgFmtetc || pimkBase)
432         FIXME("Unsupported args\n");
433 
434     hres = RegisterBindStatusCallback(pibc, pibsc, NULL /* FIXME */, 0);
435     if(FAILED(hres))
436         return hres;
437 
438     hres = IMoniker_IsSystemMoniker(pimkReference, &mksys);
439     if(SUCCEEDED(hres) && mksys != MKSYS_URLMONIKER)
440         WARN("sysmk = %x\n", mksys);
441 
442     /* FIXME: What is it for? */
443     CreateBindCtx(0, &bctx);
444     hres = IMoniker_GetDisplayName(pimkReference, bctx, NULL, &name);
445     IBindCtx_Release(bctx);
446     if(SUCCEEDED(hres)) {
447         TRACE("got display name %s\n", debugstr_w(name));
448         CoTaskMemFree(name);
449     }
450 
451     return IMoniker_BindToStorage(pimkReference, pibc, NULL, &IID_IUnknown, &obj);
452 }
453 
454 /***********************************************************************
455  *             HlinkClone (HLINK.@)
456  */
457 HRESULT WINAPI HlinkClone(IHlink *hlink, REFIID riid, IHlinkSite *hls,
458         DWORD site_data, void **obj)
459 {
460     IMoniker *mk, *clone_mk = NULL;
461     WCHAR *loc, *name = NULL;
462     HRESULT hres;
463 
464     if(!hlink || !riid || !obj)
465         return E_INVALIDARG;
466 
467     *obj = NULL;
468 
469     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &mk, &loc);
470     if(FAILED(hres))
471         return hres;
472 
473     if(mk) {
474         IStream *strm;
475         LARGE_INTEGER lgint;
476 
477         hres = CreateStreamOnHGlobal(NULL, TRUE, &strm);
478         if(FAILED(hres)) {
479             IMoniker_Release(mk);
480             goto cleanup;
481         }
482 
483         hres = OleSaveToStream((IPersistStream*)mk, strm);
484         if(FAILED(hres)) {
485             IStream_Release(strm);
486             IMoniker_Release(mk);
487             goto cleanup;
488         }
489         IMoniker_Release(mk);
490 
491         lgint.QuadPart = 0;
492         hres = IStream_Seek(strm, lgint, STREAM_SEEK_SET, NULL);
493         if(FAILED(hres)) {
494             IStream_Release(strm);
495             goto cleanup;
496         }
497 
498         hres = OleLoadFromStream(strm, &IID_IMoniker, (void**)&clone_mk);
499         IStream_Release(strm);
500         if(FAILED(hres))
501             goto cleanup;
502     }
503 
504     hres = IHlink_GetFriendlyName(hlink, HLFNAMEF_DEFAULT, &name);
505     if(FAILED(hres))
506         goto cleanup;
507 
508     hres = HlinkCreateFromMoniker(clone_mk, loc, name, hls, site_data, NULL,
509             &IID_IHlink, obj);
510 
511 cleanup:
512     if(clone_mk)
513         IMoniker_Release(clone_mk);
514     CoTaskMemFree(loc);
515     CoTaskMemFree(name);
516     return hres;
517 }
518 
519 static HRESULT WINAPI HLinkCF_fnQueryInterface ( LPCLASSFACTORY iface,
520         REFIID riid, LPVOID *ppvObj)
521 {
522     CFImpl *This = impl_from_IClassFactory(iface);
523 
524     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObj);
525 
526     *ppvObj = NULL;
527 
528     if (IsEqualIID(riid, &IID_IUnknown) ||
529         IsEqualIID(riid, &IID_IClassFactory))
530     {
531         *ppvObj = &This->IClassFactory_iface;
532         return S_OK;
533     }
534 
535     TRACE("-- E_NOINTERFACE\n");
536     return E_NOINTERFACE;
537 }
538 
539 static ULONG WINAPI HLinkCF_fnAddRef (LPCLASSFACTORY iface)
540 {
541     return 2;
542 }
543 
544 static ULONG WINAPI HLinkCF_fnRelease(LPCLASSFACTORY iface)
545 {
546     return 1;
547 }
548 
549 static HRESULT WINAPI HLinkCF_fnCreateInstance( LPCLASSFACTORY iface,
550         LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
551 {
552     CFImpl *This = impl_from_IClassFactory(iface);
553 
554     TRACE("%p->(%p,%s,%p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObject);
555 
556     *ppvObject = NULL;
557 
558     return This->lpfnCI(pUnkOuter, riid, ppvObject);
559 }
560 
561 static HRESULT WINAPI HLinkCF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
562 {
563     FIXME("%p %d\n", iface, fLock);
564     return E_NOTIMPL;
565 }
566 
567 static const IClassFactoryVtbl hlcfvt =
568 {
569     HLinkCF_fnQueryInterface,
570     HLinkCF_fnAddRef,
571     HLinkCF_fnRelease,
572     HLinkCF_fnCreateInstance,
573     HLinkCF_fnLockServer
574 };
575 
576 static CFImpl HLink_cf = { { &hlcfvt }, HLink_Constructor };
577 static CFImpl HLinkBrowseContext_cf = { { &hlcfvt }, HLinkBrowseContext_Constructor };
578 
579 /***********************************************************************
580  *             DllGetClassObject (HLINK.@)
581  */
582 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
583 {
584     IClassFactory   *pcf = NULL;
585 
586     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
587 
588     if (!ppv)
589         return E_INVALIDARG;
590     *ppv = NULL;
591 
592     if (IsEqualIID(rclsid, &CLSID_StdHlink))
593         pcf = &HLink_cf.IClassFactory_iface;
594     else if (IsEqualIID(rclsid, &CLSID_StdHlinkBrowseContext))
595         pcf = &HLinkBrowseContext_cf.IClassFactory_iface;
596     else
597         return CLASS_E_CLASSNOTAVAILABLE;
598 
599     return IClassFactory_QueryInterface(pcf, iid, ppv);
600 }
601 
602 /***********************************************************************
603  *		DllRegisterServer (HLINK.@)
604  */
605 HRESULT WINAPI DllRegisterServer(void)
606 {
607     return __wine_register_resources( instance );
608 }
609 
610 /***********************************************************************
611  *		DllUnregisterServer (HLINK.@)
612  */
613 HRESULT WINAPI DllUnregisterServer(void)
614 {
615     return __wine_unregister_resources( instance );
616 }
617