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