The real, definitive, Visual C++ support branch. Accept no substitutes
[reactos.git] / dll / win32 / 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 }