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