richedit: Correctly initialize the paraformat structure.
[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_WINE_PREATTACH:
45         return FALSE;  /* prefer native version */
46     case DLL_PROCESS_ATTACH:
47         DisableThreadLibraryCalls(hinstDLL);
48         break;
49     case DLL_PROCESS_DETACH:
50         break;
51     }
52     return TRUE;
53 }
54
55 HRESULT WINAPI DllCanUnloadNow( void )
56 {
57     FIXME("\n");
58     return S_OK;
59 }
60
61 HRESULT WINAPI HlinkCreateFromMoniker( IMoniker *pimkTrgt, LPCWSTR pwzLocation,
62         LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData,
63         IUnknown* piunkOuter, REFIID riid, void** ppvObj)
64 {
65     IHlink *hl = NULL;
66     HRESULT r = S_OK;
67
68     TRACE("%p %s %s %p %i %p %s %p\n", pimkTrgt, debugstr_w(pwzLocation),
69             debugstr_w(pwzFriendlyName), pihlsite, dwSiteData, piunkOuter,
70             debugstr_guid(riid), ppvObj);
71
72     r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl);
73     if (FAILED(r))
74         return r;
75
76     if (pwzLocation)
77         IHlink_SetStringReference(hl, HLINKSETF_LOCATION, NULL, pwzLocation);
78     if (pwzFriendlyName)
79         IHlink_SetFriendlyName(hl, pwzFriendlyName);
80     if (pihlsite)
81         IHlink_SetHlinkSite(hl, pihlsite, dwSiteData);
82     if (pimkTrgt)
83         IHlink_SetMonikerReference(hl, 0, pimkTrgt, pwzLocation);
84
85     *ppvObj = hl;
86
87     TRACE("Returning %i\n",r);
88
89     return r;
90 }
91
92 HRESULT WINAPI HlinkCreateFromString( LPCWSTR pwzTarget, LPCWSTR pwzLocation,
93         LPCWSTR pwzFriendlyName, IHlinkSite* pihlsite, DWORD dwSiteData,
94         IUnknown* piunkOuter, REFIID riid, void** ppvObj)
95 {
96     IHlink *hl = NULL;
97     HRESULT r = S_OK;
98
99     TRACE("%s %s %s %p %i %p %s %p\n", debugstr_w(pwzTarget),
100             debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), pihlsite,
101             dwSiteData, piunkOuter, debugstr_guid(riid), ppvObj);
102
103     r = CoCreateInstance(&CLSID_StdHlink, piunkOuter, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&hl);
104     if (FAILED(r))
105         return r;
106
107     if (pwzLocation)
108         IHlink_SetStringReference(hl, HLINKSETF_LOCATION, NULL, pwzLocation);
109
110     if (pwzTarget)
111     {
112         IMoniker *pTgtMk = NULL;
113         IBindCtx *pbc = NULL;
114         ULONG eaten;
115
116         CreateBindCtx(0, &pbc);
117         r = MkParseDisplayName(pbc, pwzTarget, &eaten, &pTgtMk);
118         IBindCtx_Release(pbc);
119
120         if (FAILED(r))
121         {
122             LPCWSTR p = strchrW(pwzTarget, ':');
123             if (p && (p - pwzTarget > 1))
124                 r = CreateURLMoniker(NULL, pwzTarget, &pTgtMk);
125             else
126                 r = CreateFileMoniker(pwzTarget,&pTgtMk);
127         }
128
129         if (FAILED(r))
130         {
131             ERR("couldn't create moniker for %s, failed with error 0x%08x\n",
132                 debugstr_w(pwzTarget), r);
133             return r;
134         }
135
136         IHlink_SetMonikerReference(hl, 0, pTgtMk, pwzLocation);
137         IMoniker_Release(pTgtMk);
138
139         IHlink_SetStringReference(hl, HLINKSETF_TARGET, pwzTarget, NULL);
140     }
141
142     if (pwzFriendlyName)
143         IHlink_SetFriendlyName(hl, pwzFriendlyName);
144     if (pihlsite)
145         IHlink_SetHlinkSite(hl, pihlsite, dwSiteData);
146
147     TRACE("Returning %i\n",r);
148     *ppvObj = hl;
149
150     return r;
151 }
152
153
154 HRESULT WINAPI HlinkCreateBrowseContext( IUnknown* piunkOuter, REFIID riid, void** ppvObj)
155 {
156     HRESULT r = S_OK;
157
158     TRACE("%p %s %p\n", piunkOuter, debugstr_guid(riid), ppvObj);
159
160     r = CoCreateInstance(&CLSID_StdHlinkBrowseContext, piunkOuter, CLSCTX_INPROC_SERVER, riid, ppvObj);
161
162     TRACE("returning %i\n",r);
163
164     return r;
165 }
166
167 HRESULT WINAPI HlinkNavigate(IHlink *phl, IHlinkFrame *phlFrame,
168         DWORD grfHLNF, LPBC pbc, IBindStatusCallback *pbsc,
169         IHlinkBrowseContext *phlbc)
170 {
171     HRESULT r = S_OK;
172
173     TRACE("%p %p %i %p %p %p\n", phl, phlFrame, grfHLNF, pbc, pbsc, phlbc);
174
175     if (phlFrame)
176         r = IHlinkFrame_Navigate(phlFrame, grfHLNF, pbc, pbsc, phl);
177     else if (phl)
178         r = IHlink_Navigate(phl, grfHLNF, pbc, pbsc, phlbc);
179
180     return r;
181 }
182
183 HRESULT WINAPI HlinkOnNavigate( IHlinkFrame *phlFrame,
184         IHlinkBrowseContext* phlbc, DWORD grfHLNF, IMoniker *pmkTarget,
185         LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, ULONG* puHLID)
186 {
187     HRESULT r = S_OK;
188
189     TRACE("%p %p %i %p %s %s %p\n",phlFrame, phlbc, grfHLNF, pmkTarget,
190             debugstr_w(pwzLocation), debugstr_w(pwzFriendlyName), puHLID);
191
192     r = IHlinkBrowseContext_OnNavigateHlink(phlbc, grfHLNF, pmkTarget,
193             pwzLocation, pwzFriendlyName, puHLID);
194
195     if (phlFrame)
196         r = IHlinkFrame_OnNavigate(phlFrame,grfHLNF,pmkTarget, pwzLocation,
197                 pwzFriendlyName, 0);
198
199     return r;
200 }
201
202 HRESULT WINAPI HlinkCreateFromData(IDataObject *piDataObj,
203         IHlinkSite *pihlsite, DWORD dwSiteData, IUnknown *piunkOuter,
204         REFIID riid, void **ppvObj)
205 {
206     FIXME("%p %p %d %p %p %p\n",
207           piDataObj, pihlsite, dwSiteData, piunkOuter, riid, ppvObj);
208     *ppvObj = NULL;
209     return E_NOTIMPL;
210 }
211
212 HRESULT WINAPI HlinkQueryCreateFromData(IDataObject* piDataObj)
213 {
214     FIXME("%p\n", piDataObj);
215     return E_NOTIMPL;
216 }
217
218 HRESULT WINAPI HlinkNavigateToStringReference( LPCWSTR pwzTarget,
219         LPCWSTR pwzLocation, IHlinkSite *pihlsite, DWORD dwSiteData,
220         IHlinkFrame *pihlframe, DWORD grfHLNF, LPBC pibc,
221         IBindStatusCallback *pibsc, IHlinkBrowseContext *pihlbc)
222 {
223     HRESULT r;
224     IHlink *hlink = NULL;
225
226     FIXME("%s %s %p %08x %p %08x %p %p %p\n",
227           debugstr_w(pwzTarget), debugstr_w(pwzLocation), pihlsite,
228           dwSiteData, pihlframe, grfHLNF, pibc, pibsc, pihlbc);
229
230     r = HlinkCreateFromString( pwzTarget, pwzLocation, NULL, pihlsite,
231                                dwSiteData, NULL, &IID_IHlink, (LPVOID*) &hlink );
232     if (SUCCEEDED(r))
233         r = HlinkNavigate(hlink, pihlframe, grfHLNF, pibc, pibsc, pihlbc);
234
235     return r;
236 }
237
238 HRESULT WINAPI HlinkIsShortcut(LPCWSTR pwzFileName)
239 {
240     int len;
241
242     static const WCHAR url_ext[] = {'.','u','r','l',0};
243
244     TRACE("(%s)\n", debugstr_w(pwzFileName));
245
246     if(!pwzFileName)
247         return E_INVALIDARG;
248
249     len = strlenW(pwzFileName)-4;
250     if(len < 0)
251         return S_FALSE;
252
253     return strcmpiW(pwzFileName+len, url_ext) ? S_FALSE : S_OK;
254 }
255
256 HRESULT WINAPI HlinkGetSpecialReference(ULONG uReference, LPWSTR *ppwzReference)
257 {
258     DWORD res, type, size = 100;
259     LPCWSTR value_name;
260     WCHAR *buf;
261     HKEY hkey;
262
263     static const WCHAR start_pageW[] = {'S','t','a','r','t',' ','P','a','g','e',0};
264     static const WCHAR search_pageW[] = {'S','e','a','r','c','h',' ','P','a','g','e',0};
265
266     static const WCHAR ie_main_keyW[] =
267         {'S','o','f','t','w','a','r','e',
268          '\\','M','i','c','r','o','s','o','f','t','\\',
269          'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',
270          '\\','M','a','i','n',0};
271
272     TRACE("(%u %p)\n", uReference, ppwzReference);
273
274     *ppwzReference = NULL;
275
276     switch(uReference) {
277     case HLSR_HOME:
278         value_name = start_pageW;
279         break;
280     case HLSR_SEARCHPAGE:
281         value_name = search_pageW;
282         break;
283     case HLSR_HISTORYFOLDER:
284         return E_NOTIMPL;
285     default:
286         return E_INVALIDARG;
287     }
288
289     res = RegOpenKeyW(HKEY_CURRENT_USER, ie_main_keyW, &hkey);
290     if(res != ERROR_SUCCESS) {
291         WARN("Could not open key: %u\n", res);
292         return HRESULT_FROM_WIN32(res);
293     }
294
295     buf = CoTaskMemAlloc(size);
296     res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size);
297     buf = CoTaskMemRealloc(buf, size);
298     if(res == ERROR_MORE_DATA)
299         res = RegQueryValueExW(hkey, value_name, NULL, &type, (PBYTE)buf, &size);
300     RegCloseKey(hkey);
301     if(res != ERROR_SUCCESS) {
302         WARN("Could not query value %s: %u\n", debugstr_w(value_name), res);
303         CoTaskMemFree(buf);
304         return HRESULT_FROM_WIN32(res);
305     }
306
307     *ppwzReference = buf;
308     return S_OK;
309 }
310
311 HRESULT WINAPI HlinkTranslateURL(LPCWSTR pwzURL, DWORD grfFlags, LPWSTR *ppwzTranslatedURL)
312 {
313     FIXME("(%s %08x %p)\n", debugstr_w(pwzURL), grfFlags, ppwzTranslatedURL);
314     return E_NOTIMPL;
315 }
316
317 HRESULT WINAPI HlinkUpdateStackItem(IHlinkFrame *pihlframe, IHlinkBrowseContext *pihlbc,
318         ULONG uHLID, IMoniker *pimkTrgt, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName)
319 {
320     FIXME("(%p %p %u %p %s %s)\n", pihlframe, pihlbc, uHLID, pimkTrgt, debugstr_w(pwzLocation),
321           debugstr_w(pwzFriendlyName));
322     return E_NOTIMPL;
323 }
324
325 static HRESULT WINAPI HLinkCF_fnQueryInterface ( LPCLASSFACTORY iface,
326         REFIID riid, LPVOID *ppvObj)
327 {
328     CFImpl *This = (CFImpl *)iface;
329
330     TRACE("(%p)->(%s)\n",This,debugstr_guid(riid));
331
332     *ppvObj = NULL;
333
334     if (IsEqualIID(riid, &IID_IUnknown) ||
335         IsEqualIID(riid, &IID_IClassFactory))
336     {
337         *ppvObj = This;
338         return S_OK;
339     }
340
341     TRACE("-- E_NOINTERFACE\n");
342     return E_NOINTERFACE;
343 }
344
345 static ULONG WINAPI HLinkCF_fnAddRef (LPCLASSFACTORY iface)
346 {
347     return 2;
348 }
349
350 static ULONG WINAPI HLinkCF_fnRelease(LPCLASSFACTORY iface)
351 {
352     return 1;
353 }
354
355 static HRESULT WINAPI HLinkCF_fnCreateInstance( LPCLASSFACTORY iface,
356         LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject)
357 {
358     CFImpl *This = (CFImpl *)iface;
359
360     TRACE("%p->(%p,%s,%p)\n", This, pUnkOuter, debugstr_guid(riid), ppvObject);
361
362     *ppvObject = NULL;
363
364     return This->lpfnCI(pUnkOuter, riid, ppvObject);
365 }
366
367 static HRESULT WINAPI HLinkCF_fnLockServer(LPCLASSFACTORY iface, BOOL fLock)
368 {
369     FIXME("%p %d\n", iface, fLock);
370     return E_NOTIMPL;
371 }
372
373 static const IClassFactoryVtbl hlcfvt =
374 {
375     HLinkCF_fnQueryInterface,
376     HLinkCF_fnAddRef,
377     HLinkCF_fnRelease,
378     HLinkCF_fnCreateInstance,
379     HLinkCF_fnLockServer
380 };
381
382 static CFImpl HLink_cf = { &hlcfvt, &HLink_Constructor };
383 static CFImpl HLinkBrowseContext_cf = { &hlcfvt, &HLinkBrowseContext_Constructor };
384
385 /***********************************************************************
386  *             DllGetClassObject (HLINK.@)
387  */
388 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
389 {
390     IClassFactory   *pcf = NULL;
391
392     TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
393
394     if (!ppv)
395         return E_INVALIDARG;
396     *ppv = NULL;
397
398     if (IsEqualIID(rclsid, &CLSID_StdHlink))
399         pcf = (IClassFactory*) &HLink_cf;
400     else if (IsEqualIID(rclsid, &CLSID_StdHlinkBrowseContext))
401         pcf = (IClassFactory*) &HLinkBrowseContext_cf;
402     else
403         return CLASS_E_CLASSNOTAVAILABLE;
404
405     return IClassFactory_QueryInterface(pcf, iid, ppv);
406 }
407
408 static HRESULT register_clsid(LPCGUID guid)
409 {
410     static const WCHAR clsid[] =
411         {'C','L','S','I','D','\\',0};
412     static const WCHAR ips[] =
413         {'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
414     static const WCHAR hlink[] =
415         {'h','l','i','n','k','.','d','l','l',0};
416     static const WCHAR threading_model[] =
417         {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0};
418     static const WCHAR apartment[] =
419         {'A','p','a','r','t','m','e','n','t',0};
420     WCHAR path[80];
421     HKEY key = NULL;
422     LONG r;
423
424     lstrcpyW(path, clsid);
425     StringFromGUID2(guid, &path[6], 80);
426     lstrcatW(path, ips);
427     r = RegCreateKeyW(HKEY_CLASSES_ROOT, path, &key);
428     if (r != ERROR_SUCCESS)
429         return E_FAIL;
430
431     RegSetValueExW(key, NULL, 0, REG_SZ, (const BYTE *)hlink, sizeof hlink);
432     RegSetValueExW(key, threading_model, 0, REG_SZ, (const BYTE *)apartment, sizeof apartment);
433     RegCloseKey(key);
434
435     return S_OK;
436 }
437
438 HRESULT WINAPI DllRegisterServer(void)
439 {
440     HRESULT r;
441
442     r = register_clsid(&CLSID_StdHlink);
443     if (SUCCEEDED(r))
444         r = register_clsid(&CLSID_StdHlinkBrowseContext);
445
446     return S_OK;
447 }