[SHLWAPI] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / 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 struct AssocPerceivedInfo
107 {
108 PCWSTR Type;
109 PERCEIVED Perceived;
110 INT FlagHardcoded;
111 INT FlagSoftcoded;
112 PCWSTR Extensions;
113 };
114
115 static const WCHAR unspecified_exts[] = {
116 '.','l','n','k',0,
117 '.','s','e','a','r','c','h','-','m','s',0,
118 0
119 };
120
121 static const WCHAR image_exts[] = {
122 '.','b','m','p',0,
123 '.','d','i','b',0,
124 '.','e','m','f',0,
125 '.','g','i','f',0,
126 '.','i','c','o',0,
127 '.','j','f','i','f',0,
128 '.','j','p','e',0,
129 '.','j','p','e','g',0,
130 '.','j','p','g',0,
131 '.','p','n','g',0,
132 '.','r','l','e',0,
133 '.','t','i','f',0,
134 '.','t','i','f','f',0,
135 '.','w','m','f',0,
136 0
137 };
138
139 static const WCHAR audio_exts[] = {
140 '.','a','i','f',0,
141 '.','a','i','f','c',0,
142 '.','a','i','f','f',0,
143 '.','a','u',0,
144 '.','m','3','u',0,
145 '.','m','i','d',0,
146 '.','m','i','d','i',0,
147 #if _WIN32_WINNT > 0x602
148 '.','m','p','2',0,
149 #endif
150 '.','m','p','3',0,
151 '.','r','m','i',0,
152 '.','s','n','d',0,
153 '.','w','a','v',0,
154 '.','w','a','x',0,
155 '.','w','m','a',0,
156 0
157 };
158
159 static const WCHAR video_exts[] = {
160 '.','a','s','f',0,
161 '.','a','s','x',0,
162 '.','a','v','i',0,
163 '.','d','v','r','-','m','s',0,
164 '.','I','V','F',0,
165 '.','m','1','v',0,
166 #if _WIN32_WINNT <= 0x602
167 '.','m','p','2',0,
168 #endif
169 '.','m','p','2','v',0,
170 '.','m','p','a',0,
171 '.','m','p','e',0,
172 '.','m','p','e','g',0,
173 '.','m','p','g',0,
174 '.','m','p','v','2',0,
175 '.','w','m',0,
176 '.','w','m','v',0,
177 '.','w','m','x',0,
178 '.','w','v','x',0,
179 0
180 };
181
182 static const WCHAR compressed_exts[] = {
183 '.','z','i','p',0,
184 0
185 };
186
187 static const WCHAR document_exts[] = {
188 #if _WIN32_WINNT >= 0x600
189 '.','h','t','m',0,
190 '.','h','t','m','l',0,
191 #endif
192 '.','m','h','t',0,
193 0
194 };
195
196 static const WCHAR system_exts[] = {
197 '.','c','p','l',0,
198 0
199 };
200
201 static const WCHAR application_exts[] = {
202 '.','b','a','s',0,
203 '.','b','a','t',0,
204 '.','c','m','d',0,
205 '.','c','o','m',0,
206 '.','e','x','e',0,
207 '.','h','t','a',0,
208 '.','m','s','i',0,
209 '.','p','i','f',0,
210 '.','r','e','g',0,
211 '.','s','c','r',0,
212 '.','v','b',0,
213 0
214 };
215
216 const WCHAR type_text[] = {'t','e','x','t',0};
217 const WCHAR type_image[] = {'i','m','a','g','e',0};
218 const WCHAR type_audio[] = {'a','u','d','i','o',0};
219 const WCHAR type_video[] = {'v','i','d','e','o',0};
220 const WCHAR type_compressed[] = {'c','o','m','p','r','e','s','s','e','d',0};
221 const WCHAR type_document[] = {'d','o','c','u','m','e','n','t',0};
222 const WCHAR type_system[] = {'s','y','s','t','e','m',0};
223 const WCHAR type_application[] = {'a','p','p','l','i','c','a','t','i','o','n',0};
224
225 #define HARDCODED_NATIVE_WMSDK (PERCEIVEDFLAG_HARDCODED | PERCEIVEDFLAG_NATIVESUPPORT | PERCEIVEDFLAG_WMSDK)
226 #define HARDCODED_NATIVE_GDIPLUS (PERCEIVEDFLAG_HARDCODED | PERCEIVEDFLAG_NATIVESUPPORT | PERCEIVEDFLAG_GDIPLUS)
227 #define HARDCODED_NATIVE_ZIPFLDR (PERCEIVEDFLAG_HARDCODED | PERCEIVEDFLAG_NATIVESUPPORT | PERCEIVEDFLAG_ZIPFOLDER)
228 #define SOFTCODED_NATIVESUPPORT (PERCEIVEDFLAG_SOFTCODED | PERCEIVEDFLAG_NATIVESUPPORT)
229
230 static const struct AssocPerceivedInfo known_types[] = {
231 { NULL, PERCEIVED_TYPE_UNSPECIFIED, PERCEIVEDFLAG_HARDCODED, PERCEIVEDFLAG_SOFTCODED, unspecified_exts },
232 { type_text, PERCEIVED_TYPE_TEXT, PERCEIVEDFLAG_HARDCODED, SOFTCODED_NATIVESUPPORT, NULL },
233 { type_image, PERCEIVED_TYPE_IMAGE, HARDCODED_NATIVE_GDIPLUS, PERCEIVEDFLAG_SOFTCODED, image_exts },
234 { type_audio, PERCEIVED_TYPE_AUDIO, HARDCODED_NATIVE_WMSDK, PERCEIVEDFLAG_SOFTCODED, audio_exts },
235 { type_video, PERCEIVED_TYPE_VIDEO, HARDCODED_NATIVE_WMSDK, PERCEIVEDFLAG_SOFTCODED, video_exts },
236 { type_compressed, PERCEIVED_TYPE_COMPRESSED, HARDCODED_NATIVE_ZIPFLDR, PERCEIVEDFLAG_SOFTCODED, compressed_exts },
237 { type_document, PERCEIVED_TYPE_DOCUMENT, PERCEIVEDFLAG_HARDCODED, PERCEIVEDFLAG_SOFTCODED, document_exts },
238 { type_system, PERCEIVED_TYPE_SYSTEM, PERCEIVEDFLAG_HARDCODED, PERCEIVEDFLAG_SOFTCODED, system_exts },
239 { type_application, PERCEIVED_TYPE_APPLICATION, PERCEIVEDFLAG_HARDCODED, PERCEIVEDFLAG_SOFTCODED, application_exts },
240 };
241
242 static const struct AssocPerceivedInfo* AssocFindByBuiltinExtension(LPCWSTR pszExt)
243 {
244 UINT n;
245 for (n = 0; n < sizeof(known_types) / sizeof(known_types[0]); ++n)
246 {
247 PCWSTR Ext = known_types[n].Extensions;
248 while (Ext && *Ext)
249 {
250 if (!StrCmpIW(Ext, pszExt))
251 return &known_types[n];
252 Ext += (strlenW(Ext) + 1);
253 }
254 }
255 return NULL;
256 }
257
258 static const struct AssocPerceivedInfo* AssocFindByType(LPCWSTR pszType)
259 {
260 UINT n;
261 for (n = 0; n < sizeof(known_types) / sizeof(known_types[0]); ++n)
262 {
263 if (known_types[n].Type)
264 {
265 if (!StrCmpIW(known_types[n].Type, pszType))
266 return &known_types[n];
267 }
268 }
269 return NULL;
270 }
271
272
273 /*************************************************************************
274 * AssocGetPerceivedType [SHLWAPI.@]
275 *
276 * Detect the type of a file by inspecting its extension
277 *
278 * PARAMS
279 * lpszExt [I] File extension to evaluate.
280 * lpType [O] Pointer to perceived type
281 * lpFlag [O] Pointer to perceived type flag
282 * lppszType [O] Address to pointer for perceived type text
283 *
284 * RETURNS
285 * Success: S_OK. lpType and lpFlag contain the perceived type and
286 * its information. If lppszType is not NULL, it will point
287 * to a string with perceived type text.
288 * Failure: An HRESULT error code indicating the error.
289 *
290 * NOTES
291 * lppszType is optional and it can be NULL.
292 * if lpType or lpFlag are NULL, the function will crash.
293 * if lpszExt is NULL, an error is returned.
294 */
295 HRESULT WINAPI AssocGetPerceivedType(LPCWSTR lpszExt, PERCEIVED *lpType,
296 INT *lpFlag, LPWSTR *lppszType)
297 {
298 static const WCHAR PerceivedTypeKey[] = {'P','e','r','c','e','i','v','e','d','T','y','p','e',0};
299 static const WCHAR SystemFileAssociationsKey[] = {'S','y','s','t','e','m','F','i','l','e',
300 'A','s','s','o','c','i','a','t','i','o','n','s','\\','%','s',0};
301 const struct AssocPerceivedInfo *Info;
302
303 TRACE("(%s,%p,%p,%p)\n", debugstr_w(lpszExt), lpType, lpFlag, lppszType);
304
305 Info = AssocFindByBuiltinExtension(lpszExt);
306 if (Info)
307 {
308 *lpType = Info->Perceived;
309 *lpFlag = Info->FlagHardcoded;
310 }
311 else
312 {
313 WCHAR Buffer[100] = { 0 };
314 DWORD Size = sizeof(Buffer);
315 if (RegGetValueW(HKEY_CLASSES_ROOT, lpszExt, PerceivedTypeKey,
316 RRF_RT_REG_SZ, NULL, Buffer, &Size) == ERROR_SUCCESS)
317 {
318 Info = AssocFindByType(Buffer);
319 }
320 if (!Info)
321 {
322 WCHAR KeyName[MAX_PATH] = { 0 };
323 snprintfW(KeyName, MAX_PATH, SystemFileAssociationsKey, lpszExt);
324 Size = sizeof(Buffer);
325 if (RegGetValueW(HKEY_CLASSES_ROOT, KeyName, PerceivedTypeKey,
326 RRF_RT_REG_SZ, NULL, Buffer, &Size) == ERROR_SUCCESS)
327 {
328 Info = AssocFindByType(Buffer);
329 }
330 }
331 if (Info)
332 {
333 *lpType = Info->Perceived;
334 *lpFlag = Info->FlagSoftcoded;
335 }
336 }
337
338 if (Info)
339 {
340 if (lppszType && Info->Type)
341 {
342 return SHStrDupW(Info->Type, lppszType);
343 }
344 return Info->Type ? S_OK : E_FAIL;
345 }
346 else
347 {
348 *lpType = PERCEIVED_TYPE_UNSPECIFIED;
349 *lpFlag = 0;
350 }
351 return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
352 }
353
354 /*************************************************************************
355 * AssocQueryKeyW [SHLWAPI.@]
356 *
357 * See AssocQueryKeyA.
358 */
359 HRESULT WINAPI AssocQueryKeyW(ASSOCF cfFlags, ASSOCKEY assockey, LPCWSTR pszAssoc,
360 LPCWSTR pszExtra, HKEY *phkeyOut)
361 {
362 HRESULT hRet;
363 IQueryAssociations* lpAssoc;
364
365 TRACE("(0x%x,%d,%s,%s,%p)\n", cfFlags, assockey, debugstr_w(pszAssoc),
366 debugstr_w(pszExtra), phkeyOut);
367
368 hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
369 if (FAILED(hRet)) return hRet;
370
371 cfFlags &= SHLWAPI_DEF_ASSOCF;
372 hRet = IQueryAssociations_Init(lpAssoc, cfFlags, pszAssoc, NULL, NULL);
373
374 if (SUCCEEDED(hRet))
375 hRet = IQueryAssociations_GetKey(lpAssoc, cfFlags, assockey, pszExtra, phkeyOut);
376
377 IQueryAssociations_Release(lpAssoc);
378 return hRet;
379 }
380
381 /*************************************************************************
382 * AssocQueryKeyA [SHLWAPI.@]
383 *
384 * Get a file association key from the registry.
385 *
386 * PARAMS
387 * cfFlags [I] ASSOCF_ flags from "shlwapi.h"
388 * assockey [I] Type of key to get
389 * pszAssoc [I] Key name to search below
390 * pszExtra [I] Extra information about the key location
391 * phkeyOut [O] Destination for the association key
392 *
393 * RETURNS
394 * Success: S_OK. phkeyOut contains the key.
395 * Failure: An HRESULT error code indicating the error.
396 */
397 HRESULT WINAPI AssocQueryKeyA(ASSOCF cfFlags, ASSOCKEY assockey, LPCSTR pszAssoc,
398 LPCSTR pszExtra, HKEY *phkeyOut)
399 {
400 WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL;
401 WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL;
402 HRESULT hRet = E_OUTOFMEMORY;
403
404 TRACE("(0x%x,%d,%s,%s,%p)\n", cfFlags, assockey, debugstr_a(pszAssoc),
405 debugstr_a(pszExtra), phkeyOut);
406
407 if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) &&
408 SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
409 {
410 hRet = AssocQueryKeyW(cfFlags, assockey, lpszAssocW, lpszExtraW, phkeyOut);
411 }
412
413 if (lpszAssocW != szAssocW)
414 HeapFree(GetProcessHeap(), 0, lpszAssocW);
415
416 if (lpszExtraW != szExtraW)
417 HeapFree(GetProcessHeap(), 0, lpszExtraW);
418
419 return hRet;
420 }
421
422 /*************************************************************************
423 * AssocQueryStringW [SHLWAPI.@]
424 *
425 * See AssocQueryStringA.
426 */
427 HRESULT WINAPI AssocQueryStringW(ASSOCF cfFlags, ASSOCSTR str, LPCWSTR pszAssoc,
428 LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut)
429 {
430 HRESULT hRet;
431 IQueryAssociations* lpAssoc;
432
433 TRACE("(0x%x,%d,%s,%s,%p,%p)\n", cfFlags, str, debugstr_w(pszAssoc),
434 debugstr_w(pszExtra), pszOut, pcchOut);
435
436 if (!pcchOut)
437 return E_UNEXPECTED;
438
439 hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
440 if (FAILED(hRet)) return hRet;
441
442 hRet = IQueryAssociations_Init(lpAssoc, cfFlags & SHLWAPI_DEF_ASSOCF,
443 pszAssoc, NULL, NULL);
444
445 if (SUCCEEDED(hRet))
446 hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra,
447 pszOut, pcchOut);
448
449 IQueryAssociations_Release(lpAssoc);
450 return hRet;
451 }
452
453 /*************************************************************************
454 * AssocQueryStringA [SHLWAPI.@]
455 *
456 * Get a file association string from the registry.
457 *
458 * PARAMS
459 * cfFlags [I] ASSOCF_ flags from "shlwapi.h"
460 * str [I] Type of string to get (ASSOCSTR enum from "shlwapi.h")
461 * pszAssoc [I] Key name to search below
462 * pszExtra [I] Extra information about the string location
463 * pszOut [O] Destination for the association string
464 * pcchOut [O] Length of pszOut
465 *
466 * RETURNS
467 * Success: S_OK. pszOut contains the string, pcchOut contains its length.
468 * Failure: An HRESULT error code indicating the error.
469 */
470 HRESULT WINAPI AssocQueryStringA(ASSOCF cfFlags, ASSOCSTR str, LPCSTR pszAssoc,
471 LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut)
472 {
473 WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL;
474 WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL;
475 HRESULT hRet = E_OUTOFMEMORY;
476
477 TRACE("(0x%x,0x%d,%s,%s,%p,%p)\n", cfFlags, str, debugstr_a(pszAssoc),
478 debugstr_a(pszExtra), pszOut, pcchOut);
479
480 if (!pcchOut)
481 hRet = E_UNEXPECTED;
482 else if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) &&
483 SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
484 {
485 WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW;
486 DWORD dwLenOut = *pcchOut;
487
488 if (dwLenOut >= MAX_PATH)
489 lpszReturnW = HeapAlloc(GetProcessHeap(), 0,
490 (dwLenOut + 1) * sizeof(WCHAR));
491 else
492 dwLenOut = sizeof(szReturnW) / sizeof(szReturnW[0]);
493
494 if (!lpszReturnW)
495 hRet = E_OUTOFMEMORY;
496 else
497 {
498 hRet = AssocQueryStringW(cfFlags, str, lpszAssocW, lpszExtraW,
499 lpszReturnW, &dwLenOut);
500
501 if (SUCCEEDED(hRet))
502 dwLenOut = WideCharToMultiByte(CP_ACP, 0, lpszReturnW, -1,
503 pszOut, *pcchOut, NULL, NULL);
504
505 *pcchOut = dwLenOut;
506 if (lpszReturnW != szReturnW)
507 HeapFree(GetProcessHeap(), 0, lpszReturnW);
508 }
509 }
510
511 if (lpszAssocW != szAssocW)
512 HeapFree(GetProcessHeap(), 0, lpszAssocW);
513 if (lpszExtraW != szExtraW)
514 HeapFree(GetProcessHeap(), 0, lpszExtraW);
515 return hRet;
516 }
517
518 /*************************************************************************
519 * AssocQueryStringByKeyW [SHLWAPI.@]
520 *
521 * See AssocQueryStringByKeyA.
522 */
523 HRESULT WINAPI AssocQueryStringByKeyW(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc,
524 LPCWSTR pszExtra, LPWSTR pszOut,
525 DWORD *pcchOut)
526 {
527 HRESULT hRet;
528 IQueryAssociations* lpAssoc;
529
530 TRACE("(0x%x,0x%d,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc,
531 debugstr_w(pszExtra), pszOut, pcchOut);
532
533 hRet = AssocCreate( CLSID_QueryAssociations, &IID_IQueryAssociations, (void **)&lpAssoc );
534 if (FAILED(hRet)) return hRet;
535
536 cfFlags &= SHLWAPI_DEF_ASSOCF;
537 hRet = IQueryAssociations_Init(lpAssoc, cfFlags, 0, hkAssoc, NULL);
538
539 if (SUCCEEDED(hRet))
540 hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra,
541 pszOut, pcchOut);
542
543 IQueryAssociations_Release(lpAssoc);
544 return hRet;
545 }
546
547 /*************************************************************************
548 * AssocQueryStringByKeyA [SHLWAPI.@]
549 *
550 * Get a file association string from the registry, given a starting key.
551 *
552 * PARAMS
553 * cfFlags [I] ASSOCF_ flags from "shlwapi.h"
554 * str [I] Type of string to get
555 * hkAssoc [I] Key to search below
556 * pszExtra [I] Extra information about the string location
557 * pszOut [O] Destination for the association string
558 * pcchOut [O] Length of pszOut
559 *
560 * RETURNS
561 * Success: S_OK. pszOut contains the string, pcchOut contains its length.
562 * Failure: An HRESULT error code indicating the error.
563 */
564 HRESULT WINAPI AssocQueryStringByKeyA(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc,
565 LPCSTR pszExtra, LPSTR pszOut,
566 DWORD *pcchOut)
567 {
568 WCHAR szExtraW[MAX_PATH], *lpszExtraW = szExtraW;
569 WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW;
570 HRESULT hRet = E_OUTOFMEMORY;
571
572 TRACE("(0x%x,0x%d,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc,
573 debugstr_a(pszExtra), pszOut, pcchOut);
574
575 if (!pcchOut)
576 hRet = E_INVALIDARG;
577 else if (SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW))
578 {
579 DWORD dwLenOut = *pcchOut;
580 if (dwLenOut >= MAX_PATH)
581 lpszReturnW = HeapAlloc(GetProcessHeap(), 0,
582 (dwLenOut + 1) * sizeof(WCHAR));
583
584 if (lpszReturnW)
585 {
586 hRet = AssocQueryStringByKeyW(cfFlags, str, hkAssoc, lpszExtraW,
587 lpszReturnW, &dwLenOut);
588
589 if (SUCCEEDED(hRet))
590 WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0);
591 *pcchOut = dwLenOut;
592
593 if (lpszReturnW != szReturnW)
594 HeapFree(GetProcessHeap(), 0, lpszReturnW);
595 }
596 }
597
598 if (lpszExtraW != szExtraW)
599 HeapFree(GetProcessHeap(), 0, lpszExtraW);
600 return hRet;
601 }
602
603
604 /**************************************************************************
605 * AssocIsDangerous (SHLWAPI.@)
606 *
607 * Determine if a file association is dangerous (potentially malware).
608 *
609 * PARAMS
610 * lpszAssoc [I] Name of file or file extension to check.
611 *
612 * RETURNS
613 * TRUE, if lpszAssoc may potentially be malware (executable),
614 * FALSE, Otherwise.
615 */
616 BOOL WINAPI AssocIsDangerous(LPCWSTR lpszAssoc)
617 {
618 FIXME("%s\n", debugstr_w(lpszAssoc));
619 return FALSE;
620 }