gdi32: Add a string table resource for the translation.
[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     FIXME("%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
273     return r;
274 }
275
276 /***********************************************************************
277  *             HlinkIsShortcut (HLINK.@)
278  */
279 HRESULT WINAPI HlinkIsShortcut(LPCWSTR pwzFileName)
280 {
281     int len;
282
283     static const WCHAR url_ext[] = {'.','u','r','l',0};
284
285     TRACE("(%s)\n", debugstr_w(pwzFileName));
286
287     if(!pwzFileName)
288         return E_INVALIDARG;
289
290     len = strlenW(pwzFileName)-4;
291     if(len < 0)
292         return S_FALSE;
293
294     return strcmpiW(pwzFileName+len, url_ext) ? S_FALSE : S_OK;
295 }
296
297 /***********************************************************************
298  *             HlinkGetSpecialReference (HLINK.@)
299  */
300 HRESULT WINAPI HlinkGetSpecialReference(ULONG uReference, LPWSTR *ppwzReference)
301 {
302     DWORD res, type, size = 100;
303     LPCWSTR value_name;
304     WCHAR *buf;
305     HKEY hkey;
306
307     static const WCHAR start_pageW[] = {'S','t','a','r','t',' ','P','a','g','e',0};
308     static const WCHAR search_pageW[] = {'S','e','a','r','c','h',' ','P','a','g','e',0};
309
310     static const WCHAR ie_main_keyW[] =
311         {'S','o','f','t','w','a','r','e',
312          '\\','M','i','c','r','o','s','o','f','t','\\',
313          'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',
314          '\\','M','a','i','n',0};
315
316     TRACE("(%u %p)\n", uReference, ppwzReference);
317
318     *ppwzReference = NULL;
319
320     switch(uReference) {
321     case HLSR_HOME:
322         value_name = start_pageW;
323         break;
324     case HLSR_SEARCHPAGE:
325         value_name = search_pageW;
326         break;
327     case HLSR_HISTORYFOLDER:
328         return E_NOTIMPL;
329     default:
330         return E_INVALIDARG;
331     }
332
333     res = RegOpenKeyW(HKEY_CURRENT_USER, ie_main_keyW, &hkey);
334     if(res != ERROR_SUCCESS) {
335         WARN("Could not open key: %u\n", res);
336         return HRESULT_FROM_WIN32(res);
337     }
338
339     buf = CoTaskMemAlloc(size);
340     res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size);
341     buf = CoTaskMemRealloc(buf, size);
342     if(res == ERROR_MORE_DATA)
343         res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size);
344     RegCloseKey(hkey);
345     if(res != ERROR_SUCCESS) {
346         WARN("Could not query value %s: %u\n", debugstr_w(value_name), res);
347         CoTaskMemFree(buf);
348         return HRESULT_FROM_WIN32(res);
349     }
350
351     *ppwzReference = buf;
352     return S_OK;
353 }
354
355 /***********************************************************************
356  *             HlinkTranslateURL (HLINK.@)
357  */
358 HRESULT WINAPI HlinkTranslateURL(LPCWSTR pwzURL, DWORD grfFlags, LPWSTR *ppwzTranslatedURL)
359 {
360     FIXME("(%s %08x %p)\n", debugstr_w(pwzURL), grfFlags, ppwzTranslatedURL);
361     return E_NOTIMPL;
362 }
363
364 /***********************************************************************
365  *             HlinkUpdateStackItem (HLINK.@)
366  */
367 HRESULT WINAPI HlinkUpdateStackItem(IHlinkFrame *pihlframe, IHlinkBrowseContext *pihlbc,
368         ULONG uHLID, IMoniker *pimkTrgt, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName)
369 {
370     FIXME("(%p %p %u %p %s %s)\n", pihlframe, pihlbc, uHLID, pimkTrgt, debugstr_w(pwzLocation),
371           debugstr_w(pwzFriendlyName));
372     return E_NOTIMPL;
373 }
374
375 /***********************************************************************
376  *             HlinkParseDisplayName (HLINK.@)
377  */
378 HRESULT WINAPI HlinkParseDisplayName(LPBC pibc, LPCWSTR pwzDisplayName, BOOL fNoForceAbs,
379         ULONG *pcchEaten, IMoniker **ppimk)
380 {
381     HRESULT hres;
382
383     TRACE("(%p %s %x %p %p)\n", pibc, debugstr_w(pwzDisplayName), fNoForceAbs, pcchEaten, ppimk);
384
385     if(fNoForceAbs)
386         FIXME("Unsupported fNoForceAbs\n");
387
388     hres = MkParseDisplayNameEx(pibc, pwzDisplayName, pcchEaten, ppimk);
389     if(SUCCEEDED(hres))
390         return hres;
391
392     hres = MkParseDisplayName(pibc, pwzDisplayName, pcchEaten, ppimk);
393     if(SUCCEEDED(hres))
394         return hres;
395
396     hres = CreateFileMoniker(pwzDisplayName, ppimk);
397     if(SUCCEEDED(hres))
398         *pcchEaten = strlenW(pwzDisplayName);
399
400     return hres;
401 }
402
403 /***********************************************************************
404  *             HlinkResolveMonikerForData (HLINK.@)
405  */
406 HRESULT WINAPI HlinkResolveMonikerForData(LPMONIKER pimkReference, DWORD reserved, LPBC pibc,
407         ULONG cFmtetc, FORMATETC *rgFmtetc, IBindStatusCallback *pibsc, LPMONIKER pimkBase)
408 {
409     LPOLESTR name = NULL;
410     IBindCtx *bctx;
411     DWORD mksys = 0;
412     void *obj = NULL;
413     HRESULT hres;
414
415     TRACE("(%p %x %p %d %p %p %p)\n", pimkReference, reserved, pibc, cFmtetc, rgFmtetc, pibsc, pimkBase);
416
417     if(cFmtetc || rgFmtetc || pimkBase)
418         FIXME("Unsupported args\n");
419
420     hres = RegisterBindStatusCallback(pibc, pibsc, NULL /* FIXME */, 0);
421     if(FAILED(hres))
422         return hres;
423
424     hres = IMoniker_IsSystemMoniker(pimkReference, &mksys);
425     if(SUCCEEDED(hres) && mksys != MKSYS_URLMONIKER)
426         WARN("sysmk = %x\n", mksys);
427
428     /* FIXME: What is it for? */
429     CreateBindCtx(0, &bctx);
430     hres = IMoniker_GetDisplayName(pimkReference, bctx, NULL, &name);
431     IBindCtx_Release(bctx);
432     if(SUCCEEDED(hres)) {
433         TRACE("got display name %s\n", debugstr_w(name));
434         CoTaskMemFree(name);
435     }
436
437     return IMoniker_BindToStorage(pimkReference, pibc, NULL, &IID_IUnknown, &obj);
438 }
439
440 /***********************************************************************
441  *             HlinkClone (HLINK.@)
442  */
443 HRESULT WINAPI HlinkClone(IHlink *hlink, REFIID riid, IHlinkSite *hls,
444         DWORD site_data, void **obj)
445 {
446     IMoniker *mk, *clone_mk = NULL;
447     WCHAR *loc, *name = NULL;
448     HRESULT hres;
449
450     if(!hlink || !riid || !obj)
451         return E_INVALIDARG;
452
453     *obj = NULL;
454
455     hres = IHlink_GetMonikerReference(hlink, HLINKGETREF_DEFAULT, &mk, &loc);
456     if(FAILED(hres))
457         return hres;
458
459     if(mk) {
460         IStream *strm;
461         LARGE_INTEGER lgint;
462
463         hres = CreateStreamOnHGlobal(NULL, TRUE, &strm);
464         if(FAILED(hres)) {
465             IMoniker_Release(mk);
466             goto cleanup;
467         }
468
469         hres = OleSaveToStream((IPersistStream*)mk, strm);
470         if(FAILED(hres)) {
471             IStream_Release(strm);
472             IMoniker_Release(mk);
473             goto cleanup;
474         }
475         IMoniker_Release(mk);
476
477         lgint.QuadPart = 0;
478         hres = IStream_Seek(strm, lgint, STREAM_SEEK_SET, NULL);
479         if(FAILED(hres)) {
480             IStream_Release(strm);
481             goto cleanup;
482         }
483
484         hres = OleLoadFromStream(strm, &IID_IMoniker, (void**)&clone_mk);
485         IStream_Release(strm);
486         if(FAILED(hres))
487             goto cleanup;
488     }
489
490     hres = IHlink_GetFriendlyName(hlink, HLFNAMEF_DEFAULT, &name);
491     if(FAILED(hres))
492         goto cleanup;
493
494     hres = HlinkCreateFromMoniker(clone_mk, loc, name, hls, site_data, NULL,
495             &IID_IHlink, obj);
496
497 cleanup:
498     if(clone_mk)
499         IMoniker_Release(clone_mk);
500     CoTaskMemFree(loc);
501     CoTaskMemFree(name);
502     return hres;
503 }
504
505 static HRESULT WINAPI HLinkCF_fnQueryInterface ( LPCLASSFACTORY iface,
506         REFIID riid, LPVOID *ppvObj)
507 {
508     CFImpl *This = impl_from_IClassFactory(iface);
509
510     TRACE("(%p)->(%s)\n",This,debugstr_guid(riid));
511
512     *ppvObj = NULL;
513
514     if (IsEqualIID(riid, &IID_IUnknown) ||
515         IsEqualIID(riid, &IID_IClassFactory))
516     {
517         *ppvObj = This;
518         return S_OK;
519     }
520
521     TRACE("-- E_NOINTERFACE\n");
522     return E_NOINTERFACE;
523 }
524
525 static ULONG WINAPI HLinkCF_fnAddRef (LPCLASSFACTORY iface)
526 {
527     return 2;
528 }
529
530 static ULONG WINAPI HLinkCF_fnRelease(LPCLASSFACTORY iface)
531 {
532     return 1;
533 }
534
535 static HRESULT WINAPI HLinkCF_fnCreateInstance( LPCLASSFACTORY iface,
536         LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
537 {
538     CFImpl *This = impl_from_IClassFactory(iface);
539
540     TRACE("%p->(%p,%s,%p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObject);
541
542     *ppvObject = NULL;
543
544     return This->lpfnCI(pUnkOuter, riid, ppvObject);
545 }
546
547 static HRESULT WINAPI HLinkCF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
548 {
549     FIXME("%p %d\n", iface, fLock);
550     return E_NOTIMPL;
551 }
552
553 static const IClassFactoryVtbl hlcfvt =
554 {
555     HLinkCF_fnQueryInterface,
556     HLinkCF_fnAddRef,
557     HLinkCF_fnRelease,
558     HLinkCF_fnCreateInstance,
559     HLinkCF_fnLockServer
560 };
561
562 static CFImpl HLink_cf = { { &hlcfvt }, HLink_Constructor };
563 static CFImpl HLinkBrowseContext_cf = { { &hlcfvt }, HLinkBrowseContext_Constructor };
564
565 /***********************************************************************
566  *             DllGetClassObject (HLINK.@)
567  */
568 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
569 {
570     IClassFactory   *pcf = NULL;
571
572     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
573
574     if (!ppv)
575         return E_INVALIDARG;
576     *ppv = NULL;
577
578     if (IsEqualIID(rclsid, &CLSID_StdHlink))
579         pcf = &HLink_cf.IClassFactory_iface;
580     else if (IsEqualIID(rclsid, &CLSID_StdHlinkBrowseContext))
581         pcf = &HLinkBrowseContext_cf.IClassFactory_iface;
582     else
583         return CLASS_E_CLASSNOTAVAILABLE;
584
585     return IClassFactory_QueryInterface(pcf, iid, ppv);
586 }
587
588 /***********************************************************************
589  *              DllRegisterServer (HLINK.@)
590  */
591 HRESULT WINAPI DllRegisterServer(void)
592 {
593     return __wine_register_resources( instance );
594 }
595
596 /***********************************************************************
597  *              DllUnregisterServer (HLINK.@)
598  */
599 HRESULT WINAPI DllUnregisterServer(void)
600 {
601     return __wine_unregister_resources( instance );
602 }