oleaut32: Use a saner calling convention for the marshaller asm thunks.
[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  * AssocGetPerceivedType  [SHLWAPI.@]
107  *
108  * Detect the type of a file by inspecting its extension
109  *
110  * PARAMS
111  *  lpszExt     [I] File extension to evaluate.
112  *  lpType      [O] Pointer to perceived type
113  *  lpFlag      [O] Pointer to perceived type flag
114  *  lppszType   [O] Address to pointer for perceived type text
115  *
116  * RETURNS
117  *  Success: S_OK. lpType and lpFlag contain the perceived type and
118  *           its information. If lppszType is not NULL, it will point
119  *           to a string with perceived type text.
120  *  Failure: An HRESULT error code indicating the error.
121  *
122  * NOTES
123  *  lppszType is optional and it can be NULL.
124  *  if lpType or lpFlag are NULL, the function will crash.
125  *  if lpszExt is NULL, an error is returned.
126  *
127  * BUGS
128  *   Unimplemented.
129  */
130 HRESULT WINAPI AssocGetPerceivedType(LPCWSTR lpszExt, PERCEIVED *lpType,
131                                      INT *lpFlag, LPWSTR *lppszType)
132 {
133   FIXME("(%s, %p, %p, %p) not supported\n", debugstr_w(lpszExt), lpType, lpFlag, lppszType);
134
135   if (lpszExt == NULL)
136     return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
137
138   return E_NOTIMPL;
139 }
140
141 /*************************************************************************
142  * AssocQueryKeyW  [SHLWAPI.@]
143  *
144  * See AssocQueryKeyA.
145  */
146 HRESULT WINAPI AssocQueryKeyW(ASSOCF cfFlags, ASSOCKEY assockey, LPCWSTR pszAssoc,
147                               LPCWSTR pszExtra, HKEY *phkeyOut)
148 {
149   HRESULT hRet;
150   IQueryAssociations* lpAssoc;
151
152   TRACE("(0x%x,%d,%s,%s,%p)\n", cfFlags, assockey, debugstr_w(pszAssoc),
153         debugstr_w(pszExtra), phkeyOut);
154
155   hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
156   if (FAILED(hRet)) return hRet;
157
158   cfFlags &= SHLWAPI_DEF_ASSOCF;
159   hRet = IQueryAssociations_Init(lpAssoc, cfFlags, pszAssoc, NULL, NULL);
160
161   if (SUCCEEDED(hRet))
162     hRet = IQueryAssociations_GetKey(lpAssoc, cfFlags, assockey, pszExtra, phkeyOut);
163
164   IQueryAssociations_Release(lpAssoc);
165   return hRet;
166 }
167
168 /*************************************************************************
169  * AssocQueryKeyA  [SHLWAPI.@]
170  *
171  * Get a file association key from the registry.
172  *
173  * PARAMS
174  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
175  *  assockey [I] Type of key to get
176  *  pszAssoc [I] Key name to search below
177  *  pszExtra [I] Extra information about the key location
178  *  phkeyOut [O] Destination for the association key
179  *
180  * RETURNS
181  *  Success: S_OK. phkeyOut contains the key.
182  *  Failure: An HRESULT error code indicating the error.
183  */
184 HRESULT WINAPI AssocQueryKeyA(ASSOCF cfFlags, ASSOCKEY assockey, LPCSTR pszAssoc,
185                               LPCSTR pszExtra, HKEY *phkeyOut)
186 {
187   WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL;
188   WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL;
189   HRESULT hRet = E_OUTOFMEMORY;
190
191   TRACE("(0x%x,%d,%s,%s,%p)\n", cfFlags, assockey, debugstr_a(pszAssoc),
192         debugstr_a(pszExtra), phkeyOut);
193
194   if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) &&
195       SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
196   {
197     hRet = AssocQueryKeyW(cfFlags, assockey, lpszAssocW, lpszExtraW, phkeyOut);
198   }
199
200   if (lpszAssocW != szAssocW)
201     HeapFree(GetProcessHeap(), 0, lpszAssocW);
202
203   if (lpszExtraW != szExtraW)
204     HeapFree(GetProcessHeap(), 0, lpszExtraW);
205
206   return hRet;
207 }
208
209 /*************************************************************************
210  * AssocQueryStringW  [SHLWAPI.@]
211  *
212  * See AssocQueryStringA.
213  */
214 HRESULT WINAPI AssocQueryStringW(ASSOCF cfFlags, ASSOCSTR str, LPCWSTR pszAssoc,
215                                  LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut)
216 {
217   HRESULT hRet;
218   IQueryAssociations* lpAssoc;
219
220   TRACE("(0x%x,%d,%s,%s,%p,%p)\n", cfFlags, str, debugstr_w(pszAssoc),
221         debugstr_w(pszExtra), pszOut, pcchOut);
222
223   if (!pcchOut)
224     return E_UNEXPECTED;
225
226   hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
227   if (FAILED(hRet)) return hRet;
228
229   hRet = IQueryAssociations_Init(lpAssoc, cfFlags & SHLWAPI_DEF_ASSOCF,
230                                  pszAssoc, NULL, NULL);
231
232   if (SUCCEEDED(hRet))
233     hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra,
234                                         pszOut, pcchOut);
235
236   IQueryAssociations_Release(lpAssoc);
237   return hRet;
238 }
239
240 /*************************************************************************
241  * AssocQueryStringA  [SHLWAPI.@]
242  *
243  * Get a file association string from the registry.
244  *
245  * PARAMS
246  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
247  *  str      [I] Type of string to get (ASSOCSTR enum from "shlwapi.h")
248  *  pszAssoc [I] Key name to search below
249  *  pszExtra [I] Extra information about the string location
250  *  pszOut   [O] Destination for the association string
251  *  pcchOut  [O] Length of pszOut
252  *
253  * RETURNS
254  *  Success: S_OK. pszOut contains the string, pcchOut contains its length.
255  *  Failure: An HRESULT error code indicating the error.
256  */
257 HRESULT WINAPI AssocQueryStringA(ASSOCF cfFlags, ASSOCSTR str, LPCSTR pszAssoc,
258                                  LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut)
259 {
260   WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL;
261   WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL;
262   HRESULT hRet = E_OUTOFMEMORY;
263
264   TRACE("(0x%x,0x%d,%s,%s,%p,%p)\n", cfFlags, str, debugstr_a(pszAssoc),
265         debugstr_a(pszExtra), pszOut, pcchOut);
266
267   if (!pcchOut)
268     hRet = E_UNEXPECTED;
269   else if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) &&
270            SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
271   {
272     WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW;
273     DWORD dwLenOut = *pcchOut;
274
275     if (dwLenOut >= MAX_PATH)
276       lpszReturnW = HeapAlloc(GetProcessHeap(), 0,
277                                       (dwLenOut + 1) * sizeof(WCHAR));
278     else
279       dwLenOut = sizeof(szReturnW) / sizeof(szReturnW[0]);
280
281     if (!lpszReturnW)
282       hRet = E_OUTOFMEMORY;
283     else
284     {
285       hRet = AssocQueryStringW(cfFlags, str, lpszAssocW, lpszExtraW,
286                                lpszReturnW, &dwLenOut);
287
288       if (SUCCEEDED(hRet))
289         dwLenOut = WideCharToMultiByte(CP_ACP, 0, lpszReturnW, -1,
290                                        pszOut, *pcchOut, NULL, NULL);
291
292       *pcchOut = dwLenOut;
293       if (lpszReturnW != szReturnW)
294         HeapFree(GetProcessHeap(), 0, lpszReturnW);
295     }
296   }
297
298   if (lpszAssocW != szAssocW)
299     HeapFree(GetProcessHeap(), 0, lpszAssocW);
300   if (lpszExtraW != szExtraW)
301     HeapFree(GetProcessHeap(), 0, lpszExtraW);
302   return hRet;
303 }
304
305 /*************************************************************************
306  * AssocQueryStringByKeyW  [SHLWAPI.@]
307  *
308  * See AssocQueryStringByKeyA.
309  */
310 HRESULT WINAPI AssocQueryStringByKeyW(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc,
311                                       LPCWSTR pszExtra, LPWSTR pszOut,
312                                       DWORD *pcchOut)
313 {
314   HRESULT hRet;
315   IQueryAssociations* lpAssoc;
316
317   TRACE("(0x%x,0x%d,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc,
318         debugstr_w(pszExtra), pszOut, pcchOut);
319
320   hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
321   if (FAILED(hRet)) return hRet;
322
323   cfFlags &= SHLWAPI_DEF_ASSOCF;
324   hRet = IQueryAssociations_Init(lpAssoc, cfFlags, 0, hkAssoc, NULL);
325
326   if (SUCCEEDED(hRet))
327     hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra,
328                                         pszOut, pcchOut);
329
330   IQueryAssociations_Release(lpAssoc);
331   return hRet;
332 }
333
334 /*************************************************************************
335  * AssocQueryStringByKeyA  [SHLWAPI.@]
336  *
337  * Get a file association string from the registry, given a starting key.
338  *
339  * PARAMS
340  *  cfFlags  [I] ASSOCF_ flags from "shlwapi.h"
341  *  str      [I] Type of string to get
342  *  hkAssoc  [I] Key to search below
343  *  pszExtra [I] Extra information about the string location
344  *  pszOut   [O] Destination for the association string
345  *  pcchOut  [O] Length of pszOut
346  *
347  * RETURNS
348  *  Success: S_OK. pszOut contains the string, pcchOut contains its length.
349  *  Failure: An HRESULT error code indicating the error.
350  */
351 HRESULT WINAPI AssocQueryStringByKeyA(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc,
352                                       LPCSTR pszExtra, LPSTR pszOut,
353                                       DWORD *pcchOut)
354 {
355   WCHAR szExtraW[MAX_PATH], *lpszExtraW = szExtraW;
356   WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW;
357   HRESULT hRet = E_OUTOFMEMORY;
358
359   TRACE("(0x%x,0x%d,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc,
360         debugstr_a(pszExtra), pszOut, pcchOut);
361
362   if (!pcchOut)
363     hRet = E_INVALIDARG;
364   else if (SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
365   {
366     DWORD dwLenOut = *pcchOut;
367     if (dwLenOut >= MAX_PATH)
368       lpszReturnW = HeapAlloc(GetProcessHeap(), 0,
369                                       (dwLenOut + 1) * sizeof(WCHAR));
370
371     if (lpszReturnW)
372     {
373       hRet = AssocQueryStringByKeyW(cfFlags, str, hkAssoc, lpszExtraW,
374                                     lpszReturnW, &dwLenOut);
375
376       if (SUCCEEDED(hRet))
377         WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0);
378       *pcchOut = dwLenOut;
379
380       if (lpszReturnW != szReturnW)
381         HeapFree(GetProcessHeap(), 0, lpszReturnW);
382     }
383   }
384
385   if (lpszExtraW != szExtraW)
386     HeapFree(GetProcessHeap(), 0, lpszExtraW);
387   return hRet;
388 }
389
390
391 /**************************************************************************
392  *  AssocIsDangerous  (SHLWAPI.@)
393  *  
394  * Determine if a file association is dangerous (potentially malware).
395  *
396  * PARAMS
397  *  lpszAssoc [I] Name of file or file extension to check.
398  *
399  * RETURNS
400  *  TRUE, if lpszAssoc may potentially be malware (executable),
401  *  FALSE, Otherwise.
402  */
403 BOOL WINAPI AssocIsDangerous(LPCWSTR lpszAssoc)
404 {
405     FIXME("%s\n", debugstr_w(lpszAssoc));
406     return FALSE;
407 }