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 } 621