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