d3d9/tests: Add r500 fp_special results.
[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     }
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 %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     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     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 }