hlink: Implement HlinkClone.
[wine] / dlls / shlwapi / assoc.c
1 /*
2  * IQueryAssociations helper functions
3  *
4  * Copyright 2002 Jon Griffiths
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 #include <stdarg.h>
21 #include <assert.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "winreg.h"
27 #include "objbase.h"
28 #include "shlguid.h"
29 #include "shlobj.h"
30 #include "shlwapi.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(shell);
35
36 /* Default IQueryAssociations::Init() flags */
37 #define SHLWAPI_DEF_ASSOCF (ASSOCF_INIT_BYEXENAME|ASSOCF_INIT_DEFAULTTOSTAR| \
38                             ASSOCF_INIT_DEFAULTTOFOLDER)
39
40 /*************************************************************************
41  * SHLWAPI_ParamAToW
42  *
43  * Internal helper function: Convert ASCII parameter to Unicode.
44  */
45 static BOOL SHLWAPI_ParamAToW(LPCSTR lpszParam, LPWSTR lpszBuff, DWORD dwLen,
46                               LPWSTR* lpszOut)
47 {
48   if (lpszParam)
49   {
50     DWORD dwStrLen = MultiByteToWideChar(CP_ACP, 0, lpszParam, -1, NULL, 0);
51
52     if (dwStrLen < dwLen)
53     {
54       *lpszOut = lpszBuff; /* Use Buffer, it is big enough */
55     }
56     else
57     {
58       /* Create a new buffer big enough for the string */
59       *lpszOut = HeapAlloc(GetProcessHeap(), 0,
60                                    dwStrLen * sizeof(WCHAR));
61       if (!*lpszOut)
62         return FALSE;
63     }
64     MultiByteToWideChar(CP_ACP, 0, lpszParam, -1, *lpszOut, dwStrLen);
65   }
66   else
67     *lpszOut = NULL;
68   return TRUE;
69 }
70
71 /*************************************************************************
72  * AssocCreate  [SHLWAPI.@]
73  *
74  * Create a new IQueryAssociations object.
75  *
76  * PARAMS
77  *  clsid       [I] CLSID of object
78  *  refiid      [I] REFIID of interface
79  *  lpInterface [O] Destination for the created IQueryAssociations object
80  *
81  * RETURNS
82  *  Success: S_OK. lpInterface contains the new object.
83  *  Failure: An HRESULT error code indicating the error.
84  *
85  * NOTES
86  *  clsid  must be equal to CLSID_QueryAssociations and
87  *  refiid must be equal to IID_IQueryAssociations, IID_IUnknown or this function will fail
88  */
89 HRESULT WINAPI AssocCreate(CLSID clsid, REFIID refiid, void **lpInterface)
90 {
91   TRACE("(%s,%s,%p)\n", debugstr_guid(&clsid), debugstr_guid(refiid),
92         lpInterface);
93
94   if (!lpInterface)
95     return E_INVALIDARG;
96
97   *(DWORD*)lpInterface = 0;
98
99   if (!IsEqualGUID(&clsid,  &CLSID_QueryAssociations))
100     return CLASS_E_CLASSNOTAVAILABLE;
101
102   return SHCoCreateInstance( NULL, &clsid, NULL, refiid, lpInterface );
103 }
104
105 /*************************************************************************
106  * AssocQueryKeyW  [SHLWAPI.@]
107  *
108  * See AssocQueryKeyA.
109  */
110 HRESULT WINAPI AssocQueryKeyW(ASSOCF cfFlags, ASSOCKEY assockey, LPCWSTR pszAssoc,
111                               LPCWSTR pszExtra, HKEY *phkeyOut)
112 {
113   HRESULT hRet;
114   IQueryAssociations* lpAssoc;
115
116   TRACE("(0x%x,%d,%s,%s,%p)\n", cfFlags, assockey, debugstr_w(pszAssoc),
117         debugstr_w(pszExtra), phkeyOut);
118
119   hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
120   if (FAILED(hRet)) return hRet;
121
122   cfFlags &= SHLWAPI_DEF_ASSOCF;
123   hRet = IQueryAssociations_Init(lpAssoc, cfFlags, pszAssoc, NULL, NULL);
124
125   if (SUCCEEDED(hRet))
126     hRet = IQueryAssociations_GetKey(lpAssoc, cfFlags, assockey, pszExtra, phkeyOut);
127
128   IQueryAssociations_Release(lpAssoc);
129   return hRet;
130 }
131
132 /*************************************************************************
133  * AssocQueryKeyA  [SHLWAPI.@]
134  *
135  * Get a file association key from the registry.
136  *
137  * PARAMS
138  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
139  *  assockey [I] Type of key to get
140  *  pszAssoc [I] Key name to search below
141  *  pszExtra [I] Extra information about the key location
142  *  phkeyOut [O] Destination for the association key
143  *
144  * RETURNS
145  *  Success: S_OK. phkeyOut contains the key.
146  *  Failure: An HRESULT error code indicating the error.
147  */
148 HRESULT WINAPI AssocQueryKeyA(ASSOCF cfFlags, ASSOCKEY assockey, LPCSTR pszAssoc,
149                               LPCSTR pszExtra, HKEY *phkeyOut)
150 {
151   WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL;
152   WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL;
153   HRESULT hRet = E_OUTOFMEMORY;
154
155   TRACE("(0x%x,%d,%s,%s,%p)\n", cfFlags, assockey, debugstr_a(pszAssoc),
156         debugstr_a(pszExtra), phkeyOut);
157
158   if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) &&
159       SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
160   {
161     hRet = AssocQueryKeyW(cfFlags, assockey, lpszAssocW, lpszExtraW, phkeyOut);
162   }
163
164   if (lpszAssocW != szAssocW)
165     HeapFree(GetProcessHeap(), 0, lpszAssocW);
166
167   if (lpszExtraW != szExtraW)
168     HeapFree(GetProcessHeap(), 0, lpszExtraW);
169
170   return hRet;
171 }
172
173 /*************************************************************************
174  * AssocQueryStringW  [SHLWAPI.@]
175  *
176  * See AssocQueryStringA.
177  */
178 HRESULT WINAPI AssocQueryStringW(ASSOCF cfFlags, ASSOCSTR str, LPCWSTR pszAssoc,
179                                  LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut)
180 {
181   HRESULT hRet;
182   IQueryAssociations* lpAssoc;
183
184   TRACE("(0x%x,%d,%s,%s,%p,%p)\n", cfFlags, str, debugstr_w(pszAssoc),
185         debugstr_w(pszExtra), pszOut, pcchOut);
186
187   if (!pcchOut)
188     return E_UNEXPECTED;
189
190   hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
191   if (FAILED(hRet)) return hRet;
192
193   hRet = IQueryAssociations_Init(lpAssoc, cfFlags & SHLWAPI_DEF_ASSOCF,
194                                  pszAssoc, NULL, NULL);
195
196   if (SUCCEEDED(hRet))
197     hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra,
198                                         pszOut, pcchOut);
199
200   IQueryAssociations_Release(lpAssoc);
201   return hRet;
202 }
203
204 /*************************************************************************
205  * AssocQueryStringA  [SHLWAPI.@]
206  *
207  * Get a file association string from the registry.
208  *
209  * PARAMS
210  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
211  *  str      [I] Type of string to get (ASSOCSTR enum from "shlwapi.h")
212  *  pszAssoc [I] Key name to search below
213  *  pszExtra [I] Extra information about the string location
214  *  pszOut   [O] Destination for the association string
215  *  pcchOut  [O] Length of pszOut
216  *
217  * RETURNS
218  *  Success: S_OK. pszOut contains the string, pcchOut contains its length.
219  *  Failure: An HRESULT error code indicating the error.
220  */
221 HRESULT WINAPI AssocQueryStringA(ASSOCF cfFlags, ASSOCSTR str, LPCSTR pszAssoc,
222                                  LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut)
223 {
224   WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL;
225   WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL;
226   HRESULT hRet = E_OUTOFMEMORY;
227
228   TRACE("(0x%x,0x%d,%s,%s,%p,%p)\n", cfFlags, str, debugstr_a(pszAssoc),
229         debugstr_a(pszExtra), pszOut, pcchOut);
230
231   if (!pcchOut)
232     hRet = E_UNEXPECTED;
233   else if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) &&
234            SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
235   {
236     WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW;
237     DWORD dwLenOut = *pcchOut;
238
239     if (dwLenOut >= MAX_PATH)
240       lpszReturnW = HeapAlloc(GetProcessHeap(), 0,
241                                       (dwLenOut + 1) * sizeof(WCHAR));
242     else
243       dwLenOut = sizeof(szReturnW) / sizeof(szReturnW[0]);
244
245     if (!lpszReturnW)
246       hRet = E_OUTOFMEMORY;
247     else
248     {
249       hRet = AssocQueryStringW(cfFlags, str, lpszAssocW, lpszExtraW,
250                                lpszReturnW, &dwLenOut);
251
252       if (SUCCEEDED(hRet))
253         dwLenOut = WideCharToMultiByte(CP_ACP, 0, lpszReturnW, -1,
254                                        pszOut, *pcchOut, NULL, NULL);
255
256       *pcchOut = dwLenOut;
257       if (lpszReturnW != szReturnW)
258         HeapFree(GetProcessHeap(), 0, lpszReturnW);
259     }
260   }
261
262   if (lpszAssocW != szAssocW)
263     HeapFree(GetProcessHeap(), 0, lpszAssocW);
264   if (lpszExtraW != szExtraW)
265     HeapFree(GetProcessHeap(), 0, lpszExtraW);
266   return hRet;
267 }
268
269 /*************************************************************************
270  * AssocQueryStringByKeyW  [SHLWAPI.@]
271  *
272  * See AssocQueryStringByKeyA.
273  */
274 HRESULT WINAPI AssocQueryStringByKeyW(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc,
275                                       LPCWSTR pszExtra, LPWSTR pszOut,
276                                       DWORD *pcchOut)
277 {
278   HRESULT hRet;
279   IQueryAssociations* lpAssoc;
280
281   TRACE("(0x%x,0x%d,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc,
282         debugstr_w(pszExtra), pszOut, pcchOut);
283
284   hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
285   if (FAILED(hRet)) return hRet;
286
287   cfFlags &= SHLWAPI_DEF_ASSOCF;
288   hRet = IQueryAssociations_Init(lpAssoc, cfFlags, 0, hkAssoc, NULL);
289
290   if (SUCCEEDED(hRet))
291     hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra,
292                                         pszOut, pcchOut);
293
294   IQueryAssociations_Release(lpAssoc);
295   return hRet;
296 }
297
298 /*************************************************************************
299  * AssocQueryStringByKeyA  [SHLWAPI.@]
300  *
301  * Get a file association string from the registry, given a starting key.
302  *
303  * PARAMS
304  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
305  *  str      [I] Type of string to get
306  *  hkAssoc  [I] Key to search below
307  *  pszExtra [I] Extra information about the string location
308  *  pszOut   [O] Destination for the association string
309  *  pcchOut  [O] Length of pszOut
310  *
311  * RETURNS
312  *  Success: S_OK. pszOut contains the string, pcchOut contains its length.
313  *  Failure: An HRESULT error code indicating the error.
314  */
315 HRESULT WINAPI AssocQueryStringByKeyA(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc,
316                                       LPCSTR pszExtra, LPSTR pszOut,
317                                       DWORD *pcchOut)
318 {
319   WCHAR szExtraW[MAX_PATH], *lpszExtraW = szExtraW;
320   WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW;
321   HRESULT hRet = E_OUTOFMEMORY;
322
323   TRACE("(0x%x,0x%d,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc,
324         debugstr_a(pszExtra), pszOut, pcchOut);
325
326   if (!pcchOut)
327     hRet = E_INVALIDARG;
328   else if (SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
329   {
330     DWORD dwLenOut = *pcchOut;
331     if (dwLenOut >= MAX_PATH)
332       lpszReturnW = HeapAlloc(GetProcessHeap(), 0,
333                                       (dwLenOut + 1) * sizeof(WCHAR));
334
335     if (lpszReturnW)
336     {
337       hRet = AssocQueryStringByKeyW(cfFlags, str, hkAssoc, lpszExtraW,
338                                     lpszReturnW, &dwLenOut);
339
340       if (SUCCEEDED(hRet))
341         WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0);
342       *pcchOut = dwLenOut;
343
344       if (lpszReturnW != szReturnW)
345         HeapFree(GetProcessHeap(), 0, lpszReturnW);
346     }
347   }
348
349   if (lpszExtraW != szExtraW)
350     HeapFree(GetProcessHeap(), 0, lpszExtraW);
351   return hRet;
352 }
353
354
355 /**************************************************************************
356  *  AssocIsDangerous  (SHLWAPI.@)
357  *  
358  * Determine if a file association is dangerous (potentially malware).
359  *
360  * PARAMS
361  *  lpszAssoc [I] Name of file or file extension to check.
362  *
363  * RETURNS
364  *  TRUE, if lpszAssoc may potentially be malware (executable),
365  *  FALSE, Otherwise.
366  */
367 BOOL WINAPI AssocIsDangerous(LPCWSTR lpszAssoc)
368 {
369     FIXME("%s\n", debugstr_w(lpszAssoc));
370     return FALSE;
371 }