1 /* 2 * Open With Context Menu extension 3 * 4 * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org> 5 * Copyright 2009 Andrew Hill 6 * Copyright 2012 Rafal Harabien 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #include "precomp.h" 24 25 WINE_DEFAULT_DEBUG_CHANNEL(shell); 26 27 // 28 // [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system] 29 // "NoInternetOpenWith"=dword:00000001 30 // 31 32 EXTERN_C BOOL PathIsExeW(LPCWSTR lpszPath); 33 34 class COpenWithList 35 { 36 public: 37 struct SApp 38 { 39 WCHAR wszFilename[MAX_PATH]; 40 WCHAR wszCmd[MAX_PATH]; 41 //WCHAR wszManufacturer[256]; 42 WCHAR wszName[256]; 43 BOOL bHidden; 44 BOOL bRecommended; 45 BOOL bMRUList; 46 HICON hIcon; 47 }; 48 49 COpenWithList(); 50 ~COpenWithList(); 51 52 BOOL Load(); 53 SApp *Add(LPCWSTR pwszPath); 54 static BOOL SaveApp(SApp *pApp); 55 SApp *Find(LPCWSTR pwszFilename); 56 static LPCWSTR GetName(SApp *pApp); 57 static HICON GetIcon(SApp *pApp); 58 static BOOL Execute(SApp *pApp, LPCWSTR pwszFilePath); 59 static BOOL IsHidden(SApp *pApp); 60 inline BOOL IsNoOpen(VOID) { return m_bNoOpen; } 61 BOOL LoadRecommended(LPCWSTR pwszFilePath); 62 BOOL SetDefaultHandler(SApp *pApp, LPCWSTR pwszFilename); 63 64 inline SApp *GetList() { return m_pApp; } 65 inline UINT GetCount() { return m_cApp; } 66 inline UINT GetRecommendedCount() { return m_cRecommended; } 67 68 private: 69 typedef struct _LANGANDCODEPAGE 70 { 71 WORD lang; 72 WORD code; 73 } LANGANDCODEPAGE, *LPLANGANDCODEPAGE; 74 75 SApp *m_pApp; 76 UINT m_cApp, m_cRecommended; 77 BOOL m_bNoOpen; 78 79 SApp *AddInternal(LPCWSTR pwszFilename); 80 static BOOL LoadInfo(SApp *pApp); 81 static BOOL GetPathFromCmd(LPWSTR pwszAppPath, LPCWSTR pwszCmd); 82 BOOL LoadProgIdList(HKEY hKey, LPCWSTR pwszExt); 83 static HANDLE OpenMRUList(HKEY hKey); 84 BOOL LoadMRUList(HKEY hKey); 85 BOOL LoadAppList(HKEY hKey); 86 VOID LoadFromProgIdKey(HKEY hKey, LPCWSTR pwszExt); 87 VOID LoadRecommendedFromHKCR(LPCWSTR pwszExt); 88 VOID LoadRecommendedFromHKCU(LPCWSTR pwszExt); 89 static BOOL AddAppToMRUList(SApp *pApp, LPCWSTR pwszFilename); 90 91 inline VOID SetRecommended(SApp *pApp) 92 { 93 if (!pApp->bRecommended) 94 ++m_cRecommended; 95 pApp->bRecommended = TRUE; 96 } 97 }; 98 99 COpenWithList::COpenWithList(): 100 m_pApp(NULL), m_cApp(0), m_cRecommended(0), m_bNoOpen(FALSE) {} 101 102 COpenWithList::~COpenWithList() 103 { 104 for (UINT i = 0; i < m_cApp; ++i) 105 if (m_pApp[i].hIcon) 106 DestroyIcon(m_pApp[i].hIcon); 107 108 HeapFree(GetProcessHeap(), 0, m_pApp); 109 } 110 111 BOOL COpenWithList::Load() 112 { 113 HKEY hKey, hKeyApp; 114 WCHAR wszName[256], wszBuf[100]; 115 DWORD i = 0, cchName, dwSize; 116 SApp *pApp; 117 118 if (RegOpenKeyEx(HKEY_CLASSES_ROOT, L"Applications", 0, KEY_READ, &hKey) != ERROR_SUCCESS) 119 { 120 ERR("RegOpenKeyEx HKCR\\Applications failed!\n"); 121 return FALSE; 122 } 123 124 while (TRUE) 125 { 126 cchName = _countof(wszName); 127 if (RegEnumKeyEx(hKey, i++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) 128 break; 129 130 pApp = AddInternal(wszName); 131 132 if (pApp) 133 { 134 if (RegOpenKeyW(hKey, wszName, &hKeyApp) == ERROR_SUCCESS) 135 { 136 if ((RegQueryValueExW(hKeyApp, L"NoOpenWith", NULL, NULL, NULL, NULL) != ERROR_SUCCESS) && 137 (RegQueryValueExW(hKeyApp, L"NoStartPage", NULL, NULL, NULL, NULL) != ERROR_SUCCESS)) 138 { 139 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s\\shell\\open\\command", wszName); 140 dwSize = sizeof(pApp->wszCmd); 141 if (RegGetValueW(hKey, wszBuf, L"", RRF_RT_REG_SZ, NULL, pApp->wszCmd, &dwSize) != ERROR_SUCCESS) 142 { 143 ERR("Failed to add app %ls\n", wszName); 144 pApp->bHidden = TRUE; 145 } 146 else 147 { 148 TRACE("App added %ls\n", pApp->wszCmd); 149 } 150 } 151 else 152 { 153 pApp->bHidden = TRUE; 154 } 155 RegCloseKey(hKeyApp); 156 } 157 else 158 { 159 pApp->bHidden = TRUE; 160 } 161 } 162 else 163 { 164 ERR("AddInternal failed\n"); 165 } 166 } 167 168 RegCloseKey(hKey); 169 return TRUE; 170 } 171 172 COpenWithList::SApp *COpenWithList::Add(LPCWSTR pwszPath) 173 { 174 SApp *pApp = AddInternal(PathFindFileNameW(pwszPath)); 175 176 if (pApp) 177 { 178 StringCbPrintfW(pApp->wszCmd, sizeof(pApp->wszCmd), L"\"%s\" \"%%1\"", pwszPath); 179 SaveApp(pApp); 180 } 181 182 return pApp; 183 } 184 185 BOOL COpenWithList::SaveApp(SApp *pApp) 186 { 187 WCHAR wszBuf[256]; 188 HKEY hKey; 189 190 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s\\shell\\open\\command", pApp->wszFilename); 191 if (RegCreateKeyEx(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) 192 { 193 ERR("RegOpenKeyEx failed\n"); 194 return FALSE; 195 } 196 197 if (RegSetValueEx(hKey, L"", 0, REG_SZ, (PBYTE)pApp->wszCmd, (wcslen(pApp->wszCmd)+1)*sizeof(WCHAR)) != ERROR_SUCCESS) 198 ERR("Cannot add app to registry\n"); 199 200 RegCloseKey(hKey); 201 return TRUE; 202 } 203 204 COpenWithList::SApp *COpenWithList::Find(LPCWSTR pwszFilename) 205 { 206 for (UINT i = 0; i < m_cApp; ++i) 207 if (wcsicmp(m_pApp[i].wszFilename, pwszFilename) == 0) 208 return &m_pApp[i]; 209 return NULL; 210 } 211 212 LPCWSTR COpenWithList::GetName(SApp *pApp) 213 { 214 if (!pApp->wszName[0]) 215 { 216 if (!LoadInfo(pApp)) 217 { 218 WARN("Failed to load %ls info\n", pApp->wszFilename); 219 StringCbCopyW(pApp->wszName, sizeof(pApp->wszName), pApp->wszFilename); 220 221 WCHAR wszPath[MAX_PATH]; 222 if (!GetPathFromCmd(wszPath, pApp->wszCmd)) 223 { 224 return NULL; 225 } 226 } 227 } 228 229 TRACE("%ls name: %ls\n", pApp->wszFilename, pApp->wszName); 230 return pApp->wszName; 231 } 232 233 HICON COpenWithList::GetIcon(SApp *pApp) 234 { 235 if (!pApp->hIcon) 236 { 237 WCHAR wszPath[MAX_PATH]; 238 239 GetPathFromCmd(wszPath, pApp->wszCmd); 240 if (!ExtractIconExW(wszPath, 0, NULL, &pApp->hIcon, 1)) 241 { 242 SHFILEINFO fi; 243 /* FIXME: Ideally we should include SHGFI_USEFILEATTRIBUTES because we already 244 ** know the file has no icons but SHGetFileInfo is broken in that case (CORE-19122). 245 ** Without SHGFI_USEFILEATTRIBUTES we needlessly hit the disk again but it will 246 ** return the correct default .exe icon. 247 */ 248 SHGetFileInfoW(wszPath, 0, &fi, sizeof(fi), SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SHELLICONSIZE); 249 pApp->hIcon = fi.hIcon; 250 } 251 } 252 253 TRACE("%ls icon: %p\n", pApp->wszFilename, pApp->hIcon); 254 255 return pApp->hIcon; 256 } 257 258 BOOL COpenWithList::Execute(COpenWithList::SApp *pApp, LPCWSTR pwszFilePath) 259 { 260 WCHAR wszBuf[256]; 261 HKEY hKey; 262 263 /* Add app to registry if it wasnt there before */ 264 SaveApp(pApp); 265 if (!pApp->bMRUList) 266 AddAppToMRUList(pApp, pwszFilePath); 267 268 /* Get a handle to the reg key */ 269 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s", pApp->wszFilename); 270 if (RegCreateKeyEx(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) 271 { 272 ERR("RegOpenKeyEx failed\n"); 273 return FALSE; 274 } 275 276 /* Let ShellExecuteExW do the work */ 277 SHELLEXECUTEINFOW sei = {sizeof(SHELLEXECUTEINFOW), SEE_MASK_CLASSKEY}; 278 sei.nShow = SW_SHOWNORMAL; 279 sei.hkeyClass = hKey; 280 sei.lpFile = pwszFilePath; 281 282 ShellExecuteExW(&sei); 283 284 return TRUE; 285 } 286 287 BOOL COpenWithList::IsHidden(SApp *pApp) 288 { 289 WCHAR wszBuf[100]; 290 DWORD dwSize = 0; 291 292 if (pApp->bHidden) 293 return pApp->bHidden; 294 295 if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s", pApp->wszFilename))) 296 { 297 ERR("insufficient buffer\n"); 298 return FALSE; 299 } 300 301 if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, L"NoOpenWith", RRF_RT_REG_SZ, NULL, NULL, &dwSize) != ERROR_SUCCESS) 302 return FALSE; 303 304 pApp->bHidden = TRUE; 305 return TRUE; 306 } 307 308 COpenWithList::SApp *COpenWithList::AddInternal(LPCWSTR pwszFilename) 309 { 310 /* Check for duplicate */ 311 SApp *pApp = Find(pwszFilename); 312 if (pApp) 313 return pApp; 314 315 /* Create new item */ 316 if (!m_pApp) 317 m_pApp = static_cast<SApp *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(m_pApp[0]))); 318 else 319 m_pApp = static_cast<SApp *>(HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, m_pApp, (m_cApp + 1)*sizeof(m_pApp[0]))); 320 if (!m_pApp) 321 { 322 ERR("Allocation failed\n"); 323 return NULL; 324 } 325 326 pApp = &m_pApp[m_cApp++]; 327 wcscpy(pApp->wszFilename, pwszFilename); 328 return pApp; 329 } 330 331 BOOL COpenWithList::LoadInfo(COpenWithList::SApp *pApp) 332 { 333 UINT cbSize, cchLen; 334 LPVOID pBuf; 335 WORD wLang = 0, wCode = 0; 336 LPLANGANDCODEPAGE lpLangCode; 337 WCHAR wszBuf[100]; 338 WCHAR *pResult; 339 WCHAR wszPath[MAX_PATH]; 340 BOOL success = FALSE; 341 342 GetPathFromCmd(wszPath, pApp->wszCmd); 343 TRACE("LoadInfo %ls\n", wszPath); 344 345 /* query version info size */ 346 cbSize = GetFileVersionInfoSizeW(wszPath, NULL); 347 if (!cbSize) 348 { 349 ERR("GetFileVersionInfoSizeW %ls failed: %lu\n", wszPath, GetLastError()); 350 return FALSE; 351 } 352 353 /* allocate buffer */ 354 pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbSize + 200); 355 if (!pBuf) 356 { 357 ERR("HeapAlloc failed\n"); 358 return FALSE; 359 } 360 361 /* query version info */ 362 if (!GetFileVersionInfoW(wszPath, 0, cbSize, pBuf)) 363 { 364 ERR("GetFileVersionInfoW %ls failed: %lu\n", wszPath, GetLastError()); 365 HeapFree(GetProcessHeap(), 0, pBuf); 366 return FALSE; 367 } 368 369 /* query lang code */ 370 if (VerQueryValueW(pBuf, L"VarFileInfo\\Translation", (LPVOID*)&lpLangCode, &cbSize)) 371 { 372 /* FIXME: find language from current locale / if not available, 373 * default to english 374 * for now default to first available language 375 */ 376 wLang = lpLangCode->lang; 377 wCode = lpLangCode->code; 378 } 379 380 /* Query name */ 381 swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\FileDescription", wLang, wCode); 382 success = VerQueryValueW(pBuf, wszBuf, (LPVOID *)&pResult, &cchLen) && (cchLen > 1); 383 if (success) 384 StringCchCopyNW(pApp->wszName, _countof(pApp->wszName), pResult, cchLen); 385 else 386 ERR("Cannot get app name\n"); 387 388 /* Query manufacturer */ 389 /*swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\CompanyName", wLang, wCode); 390 391 if (VerQueryValueW(pBuf, wszBuf, (LPVOID *)&pResult, &cchLen)) 392 StringCchCopyNW(pApp->wszManufacturer, _countof(pApp->wszManufacturer), pResult, cchLen);*/ 393 HeapFree(GetProcessHeap(), 0, pBuf); 394 return success; 395 } 396 397 BOOL COpenWithList::GetPathFromCmd(LPWSTR pwszAppPath, LPCWSTR pwszCmd) 398 { 399 WCHAR wszBuf[MAX_PATH], *pwszDest = wszBuf; 400 401 /* Remove arguments */ 402 if (pwszCmd[0] == '"') 403 { 404 for(LPCWSTR pwszSrc = pwszCmd + 1; *pwszSrc && *pwszSrc != '"'; ++pwszSrc) 405 *(pwszDest++) = *pwszSrc; 406 } 407 else 408 { 409 for(LPCWSTR pwszSrc = pwszCmd; *pwszSrc && *pwszSrc != ' '; ++pwszSrc) 410 *(pwszDest++) = *pwszSrc; 411 } 412 413 *pwszDest = 0; 414 415 /* Expand evn vers and optionally search for path */ 416 ExpandEnvironmentStrings(wszBuf, pwszAppPath, MAX_PATH); 417 if (!PathFileExists(pwszAppPath)) 418 return SearchPath(NULL, pwszAppPath, NULL, MAX_PATH, pwszAppPath, NULL); 419 return TRUE; 420 } 421 422 BOOL COpenWithList::LoadRecommended(LPCWSTR pwszFilePath) 423 { 424 LPCWSTR pwszExt; 425 426 pwszExt = PathFindExtensionW(pwszFilePath); 427 if (!pwszExt[0]) 428 return FALSE; 429 430 /* load programs directly associated from HKCU */ 431 LoadRecommendedFromHKCU(pwszExt); 432 433 /* load programs associated from HKCR\Extension */ 434 LoadRecommendedFromHKCR(pwszExt); 435 436 return TRUE; 437 } 438 439 BOOL COpenWithList::LoadProgIdList(HKEY hKey, LPCWSTR pwszExt) 440 { 441 HKEY hSubkey, hSubkey2; 442 WCHAR wszProgId[256]; 443 DWORD i = 0, cchProgId; 444 445 if (RegOpenKeyExW(hKey, L"OpenWithProgIDs", 0, KEY_READ, &hSubkey) != ERROR_SUCCESS) 446 return FALSE; 447 448 while (TRUE) 449 { 450 /* Enumerate values - value name is ProgId */ 451 cchProgId = _countof(wszProgId); 452 if (RegEnumValue(hSubkey, i++, wszProgId, &cchProgId, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) 453 break; 454 455 /* If ProgId exists load it */ 456 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszProgId, 0, KEY_READ, &hSubkey2) == ERROR_SUCCESS) 457 { 458 LoadFromProgIdKey(hSubkey2, pwszExt); 459 RegCloseKey(hSubkey2); 460 } 461 } 462 463 RegCloseKey(hSubkey); 464 return TRUE; 465 } 466 467 HANDLE COpenWithList::OpenMRUList(HKEY hKey) 468 { 469 MRUINFOW Info; 470 471 /* Initialize mru list info */ 472 Info.cbSize = sizeof(Info); 473 Info.uMax = 32; 474 Info.fFlags = MRU_STRING; 475 Info.hKey = hKey; 476 Info.lpszSubKey = L"OpenWithList"; 477 Info.lpfnCompare = NULL; 478 479 return CreateMRUListW(&Info); 480 } 481 482 BOOL COpenWithList::LoadMRUList(HKEY hKey) 483 { 484 HANDLE hList; 485 int nItem, nCount, nResult; 486 WCHAR wszAppFilename[MAX_PATH]; 487 488 /* Open MRU list */ 489 hList = OpenMRUList(hKey); 490 if (!hList) 491 { 492 TRACE("OpenMRUList failed\n"); 493 return FALSE; 494 } 495 496 /* Get list count */ 497 nCount = EnumMRUListW(hList, -1, NULL, 0); 498 499 for(nItem = 0; nItem < nCount; nItem++) 500 { 501 nResult = EnumMRUListW(hList, nItem, wszAppFilename, _countof(wszAppFilename)); 502 if (nResult <= 0) 503 continue; 504 505 /* Insert item */ 506 SApp *pApp = Find(wszAppFilename); 507 508 TRACE("Recommended app %ls: %p\n", wszAppFilename, pApp); 509 if (pApp) 510 { 511 pApp->bMRUList = TRUE; 512 SetRecommended(pApp); 513 } 514 } 515 516 /* Free the MRU list */ 517 FreeMRUList(hList); 518 return TRUE; 519 } 520 521 BOOL COpenWithList::LoadAppList(HKEY hKey) 522 { 523 WCHAR wszAppFilename[MAX_PATH]; 524 HKEY hSubkey; 525 DWORD i = 0, cchAppFilename; 526 527 if (RegOpenKeyExW(hKey, L"OpenWithList", 0, KEY_READ, &hSubkey) != ERROR_SUCCESS) 528 return FALSE; 529 530 while (TRUE) 531 { 532 /* Enum registry keys - each of them is app name */ 533 cchAppFilename = _countof(wszAppFilename); 534 if (RegEnumKeyExW(hSubkey, i++, wszAppFilename, &cchAppFilename, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) 535 break; 536 537 /* Set application as recommended */ 538 SApp *pApp = Find(wszAppFilename); 539 540 TRACE("Recommended app %ls: %p\n", wszAppFilename, pApp); 541 if (pApp) 542 SetRecommended(pApp); 543 } 544 545 RegCloseKey(hSubkey); 546 return TRUE; 547 } 548 549 VOID COpenWithList::LoadFromProgIdKey(HKEY hKey, LPCWSTR pwszExt) 550 { 551 WCHAR wszCmd[MAX_PATH], wszPath[MAX_PATH]; 552 DWORD dwSize = 0; 553 554 /* Check if NoOpen value exists */ 555 if (RegGetValueW(hKey, NULL, L"NoOpen", RRF_RT_REG_SZ, NULL, NULL, &dwSize) == ERROR_SUCCESS) 556 { 557 /* Display warning dialog */ 558 m_bNoOpen = TRUE; 559 } 560 561 /* Check if there is a directly available execute key */ 562 dwSize = sizeof(wszCmd); 563 if (RegGetValueW(hKey, L"shell\\open\\command", NULL, RRF_RT_REG_SZ, NULL, (PVOID)wszCmd, &dwSize) == ERROR_SUCCESS) 564 { 565 /* Erase extra arguments */ 566 GetPathFromCmd(wszPath, wszCmd); 567 568 /* Add application */ 569 SApp *pApp = AddInternal(PathFindFileNameW(wszPath)); 570 TRACE("Add app %ls: %p\n", wszPath, pApp); 571 572 if (pApp) 573 { 574 StringCbCopyW(pApp->wszCmd, sizeof(pApp->wszCmd), wszCmd); 575 SetRecommended(pApp); 576 } 577 } 578 } 579 580 VOID COpenWithList::LoadRecommendedFromHKCR(LPCWSTR pwszExt) 581 { 582 HKEY hKey, hSubkey; 583 WCHAR wszBuf[MAX_PATH], wszBuf2[MAX_PATH]; 584 DWORD dwSize; 585 586 /* Check if extension exists */ 587 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 588 { 589 /* Load items from SystemFileAssociations\Ext key */ 590 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"SystemFileAssociations\\%s", pwszExt); 591 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 592 return; 593 } 594 595 /* Load programs referenced from HKCR\ProgId */ 596 dwSize = sizeof(wszBuf); 597 if (RegGetValueW(hKey, NULL, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS && 598 RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hSubkey) == ERROR_SUCCESS) 599 { 600 LoadFromProgIdKey(hSubkey, pwszExt); 601 RegCloseKey(hSubkey); 602 } 603 else 604 LoadFromProgIdKey(hKey, pwszExt); 605 606 /* Load items from HKCR\Ext\OpenWithList */ 607 LoadAppList(hKey); 608 609 /* Load items from HKCR\Ext\OpenWithProgIDs */ 610 if (RegOpenKeyExW(hKey, L"OpenWithProgIDs", 0, KEY_READ, &hSubkey) == ERROR_SUCCESS) 611 { 612 LoadProgIdList(hSubkey, pwszExt); 613 RegCloseKey(hSubkey); 614 } 615 616 /* Load additional items from referenced PerceivedType */ 617 dwSize = sizeof(wszBuf); 618 if (RegGetValueW(hKey, NULL, L"PerceivedType", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS) 619 { 620 StringCbPrintfW(wszBuf2, sizeof(wszBuf2), L"SystemFileAssociations\\%s", wszBuf); 621 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf2, 0, KEY_READ | KEY_WRITE, &hSubkey) == ERROR_SUCCESS) 622 { 623 /* Load from OpenWithList key */ 624 LoadAppList(hSubkey); 625 RegCloseKey(hSubkey); 626 } 627 } 628 629 /* Close the key */ 630 RegCloseKey(hKey); 631 } 632 633 VOID COpenWithList::LoadRecommendedFromHKCU(LPCWSTR pwszExt) 634 { 635 WCHAR wszBuf[MAX_PATH]; 636 HKEY hKey; 637 638 StringCbPrintfW(wszBuf, sizeof(wszBuf), 639 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s", 640 pwszExt); 641 if (RegOpenKeyExW(HKEY_CURRENT_USER, wszBuf, 0, KEY_READ, &hKey) == ERROR_SUCCESS) 642 { 643 /* Load MRU and ProgId lists */ 644 LoadMRUList(hKey); 645 LoadProgIdList(hKey, pwszExt); 646 647 /* Handle "Aplication" value */ 648 DWORD cbBuf = sizeof(wszBuf); 649 if (RegGetValueW(hKey, NULL, L"Application", RRF_RT_REG_SZ, NULL, wszBuf, &cbBuf) == ERROR_SUCCESS) 650 { 651 SApp *pApp = Find(wszBuf); 652 if (pApp) 653 SetRecommended(pApp); 654 } 655 656 /* Close the key */ 657 RegCloseKey(hKey); 658 } 659 } 660 661 BOOL COpenWithList::AddAppToMRUList(SApp *pApp, LPCWSTR pwszFilename) 662 { 663 WCHAR wszBuf[100]; 664 LPCWSTR pwszExt; 665 HKEY hKey; 666 HANDLE hList; 667 668 /* Get file extension */ 669 pwszExt = PathFindExtensionW(pwszFilename); 670 if (!pwszExt[0]) 671 return FALSE; 672 673 /* Build registry key */ 674 if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), 675 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s", 676 pwszExt))) 677 { 678 ERR("insufficient buffer\n"); 679 return FALSE; 680 } 681 682 /* Open base key for this file extension */ 683 if (RegCreateKeyExW(HKEY_CURRENT_USER, wszBuf, 0, NULL, 0, KEY_WRITE | KEY_READ, NULL, &hKey, NULL) != ERROR_SUCCESS) 684 return FALSE; 685 686 /* Open MRU list */ 687 hList = OpenMRUList(hKey); 688 if (hList) 689 { 690 /* Insert the entry */ 691 AddMRUStringW(hList, pApp->wszFilename); 692 693 /* Set MRU presence */ 694 pApp->bMRUList = TRUE; 695 696 /* Close MRU list */ 697 FreeMRUList(hList); 698 } 699 700 RegCloseKey(hKey); 701 return TRUE; 702 } 703 704 BOOL COpenWithList::SetDefaultHandler(SApp *pApp, LPCWSTR pwszFilename) 705 { 706 HKEY hKey, hSrcKey, hDestKey; 707 WCHAR wszBuf[256]; 708 709 TRACE("SetDefaultHandler %ls %ls\n", pApp->wszFilename, pwszFilename); 710 711 /* Extract file extension */ 712 LPCWSTR pwszExt = PathFindExtensionW(pwszFilename); 713 if (!pwszExt[0] || !pwszExt[1]) 714 return FALSE; 715 716 /* Create file extension key */ 717 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) 718 { 719 ERR("Cannot open ext key\n"); 720 return FALSE; 721 } 722 723 DWORD dwSize = sizeof(wszBuf); 724 LONG lResult = RegGetValueW(hKey, NULL, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize); 725 726 if (lResult == ERROR_FILE_NOT_FOUND) 727 { 728 /* A new entry was created or the default key is not set: set the prog key id */ 729 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s_auto_file", pwszExt + 1); 730 if (RegSetValueExW(hKey, L"", 0, REG_SZ, (const BYTE*)wszBuf, (wcslen(wszBuf) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) 731 { 732 RegCloseKey(hKey); 733 ERR("RegSetValueExW failed\n"); 734 return FALSE; 735 } 736 } 737 else if (lResult != ERROR_SUCCESS) 738 { 739 RegCloseKey(hKey); 740 ERR("RegGetValueExW failed: 0x%08x\n", lResult); 741 return FALSE; 742 } 743 744 /* Close file extension key */ 745 RegCloseKey(hKey); 746 747 /* Create prog id key */ 748 if (RegCreateKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) 749 { 750 ERR("RegCreateKeyExW failed\n"); 751 return FALSE; 752 } 753 754 /* Check if there already verbs existing for that app */ 755 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s\\shell", pApp->wszFilename); 756 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hSrcKey) != ERROR_SUCCESS) 757 { 758 ERR("RegOpenKeyExW %ls failed\n", wszBuf); 759 RegCloseKey(hKey); 760 return FALSE; 761 } 762 763 /* Open destination key */ 764 if (RegCreateKeyExW(hKey, L"shell", 0, NULL, 0, KEY_WRITE, NULL, &hDestKey, NULL) != ERROR_SUCCESS) 765 { 766 ERR("RegCreateKeyExW failed\n"); 767 RegCloseKey(hSrcKey); 768 RegCloseKey(hKey); 769 return FALSE; 770 } 771 772 /* Copy static verbs from Classes\Applications key */ 773 /* FIXME: SHCopyKey does not copy the security attributes of the keys */ 774 LSTATUS Result = SHCopyKeyW(hSrcKey, NULL, hDestKey, 0); 775 RegCloseKey(hDestKey); 776 RegCloseKey(hSrcKey); 777 RegCloseKey(hKey); 778 779 if (Result != ERROR_SUCCESS) 780 { 781 ERR("SHCopyKeyW failed\n"); 782 return FALSE; 783 } 784 785 return TRUE; 786 } 787 788 class COpenWithDialog 789 { 790 public: 791 COpenWithDialog(const OPENASINFO *pInfo, COpenWithList *pAppList); 792 ~COpenWithDialog(); 793 static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 794 BOOL IsNoOpen(HWND hwnd); 795 796 private: 797 VOID Init(HWND hwnd); 798 VOID AddApp(COpenWithList::SApp *pApp, BOOL bSelected); 799 VOID Browse(); 800 VOID Accept(); 801 static INT_PTR CALLBACK NoOpenDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam); 802 COpenWithList::SApp *GetCurrentApp(); 803 804 const OPENASINFO *m_pInfo; 805 COpenWithList *m_pAppList; 806 BOOL m_bListAllocated; 807 HWND m_hDialog, m_hTreeView; 808 HTREEITEM m_hRecommend; 809 HTREEITEM m_hOther; 810 HIMAGELIST m_hImgList; 811 BOOL m_bNoOpen; 812 }; 813 814 COpenWithDialog::COpenWithDialog(const OPENASINFO *pInfo, COpenWithList *pAppList = NULL): 815 m_pInfo(pInfo), m_pAppList(pAppList), m_hImgList(NULL), m_bNoOpen(FALSE) 816 { 817 if (!m_pAppList) 818 { 819 m_pAppList = new COpenWithList; 820 m_bListAllocated = TRUE; 821 } 822 else 823 m_bListAllocated = FALSE; 824 } 825 826 COpenWithDialog::~COpenWithDialog() 827 { 828 if (m_bListAllocated && m_pAppList) 829 delete m_pAppList; 830 if (m_hImgList) 831 ImageList_Destroy(m_hImgList); 832 } 833 834 INT_PTR CALLBACK COpenWithDialog::NoOpenDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) 835 { 836 switch(Message) 837 { 838 case WM_INITDIALOG: 839 { 840 return TRUE; 841 } 842 case WM_CLOSE: 843 EndDialog(hwnd, IDNO); 844 break; 845 case WM_COMMAND: 846 switch(LOWORD(wParam)) 847 { 848 case IDYES: 849 EndDialog(hwnd, IDYES); 850 break; 851 case IDNO: 852 EndDialog(hwnd, IDNO); 853 break; 854 } 855 break; 856 default: 857 return FALSE; 858 } 859 return TRUE; 860 } 861 862 BOOL COpenWithDialog::IsNoOpen(HWND hwnd) 863 { 864 /* Only do the actual check if the file type has the 'NoOpen' flag. */ 865 if (m_bNoOpen) 866 { 867 int dReturnValue = DialogBox(shell32_hInstance, MAKEINTRESOURCE(IDD_NOOPEN), hwnd, NoOpenDlgProc); 868 869 if (dReturnValue == IDNO) 870 return TRUE; 871 else if (dReturnValue == -1) 872 { 873 ERR("IsNoOpen failed to load the dialog box.\n"); 874 return TRUE; 875 } 876 } 877 878 return FALSE; 879 } 880 881 VOID COpenWithDialog::AddApp(COpenWithList::SApp *pApp, BOOL bSelected) 882 { 883 LPCWSTR pwszName = m_pAppList->GetName(pApp); 884 if (!pwszName) return; 885 HICON hIcon = m_pAppList->GetIcon(pApp); 886 887 TRACE("AddApp Cmd %ls Name %ls\n", pApp->wszCmd, pwszName); 888 889 /* Add item to the list */ 890 TVINSERTSTRUCT tvins; 891 892 if (pApp->bRecommended) 893 tvins.hParent = tvins.hInsertAfter = m_hRecommend; 894 else 895 tvins.hParent = tvins.hInsertAfter = m_hOther; 896 897 tvins.item.mask = TVIF_TEXT|TVIF_PARAM; 898 tvins.item.pszText = const_cast<LPWSTR>(pwszName); 899 tvins.item.lParam = (LPARAM)pApp; 900 901 if (hIcon) 902 { 903 tvins.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; 904 tvins.item.iImage = tvins.item.iSelectedImage = ImageList_AddIcon(m_hImgList, hIcon); 905 } 906 907 HTREEITEM hItem = TreeView_InsertItem(m_hTreeView, &tvins); 908 909 if (bSelected) 910 TreeView_SelectItem(m_hTreeView, hItem); 911 } 912 913 VOID COpenWithDialog::Browse() 914 { 915 WCHAR wszTitle[64]; 916 WCHAR wszFilter[256]; 917 WCHAR wszPath[MAX_PATH]; 918 OPENFILENAMEW ofn; 919 920 /* Initialize OPENFILENAMEW structure */ 921 ZeroMemory(&ofn, sizeof(OPENFILENAMEW)); 922 ofn.lStructSize = sizeof(OPENFILENAMEW); 923 ofn.hInstance = shell32_hInstance; 924 ofn.hwndOwner = m_hDialog; 925 ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 926 ofn.nMaxFile = (sizeof(wszPath) / sizeof(WCHAR)); 927 ofn.lpstrFile = wszPath; 928 ofn.lpstrInitialDir = L"%programfiles%"; 929 930 /* Init title */ 931 if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH, wszTitle, sizeof(wszTitle) / sizeof(WCHAR))) 932 { 933 ofn.lpstrTitle = wszTitle; 934 ofn.nMaxFileTitle = wcslen(wszTitle); 935 } 936 937 /* Init the filter string */ 938 if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH_FILTER, wszFilter, sizeof(wszFilter) / sizeof(WCHAR))) 939 ofn.lpstrFilter = wszFilter; 940 ZeroMemory(wszPath, sizeof(wszPath)); 941 942 /* Create OpenFile dialog */ 943 if (!GetOpenFileNameW(&ofn)) 944 return; 945 946 /* Setup context for insert proc */ 947 COpenWithList::SApp *pApp = m_pAppList->Add(wszPath); 948 AddApp(pApp, TRUE); 949 } 950 951 COpenWithList::SApp *COpenWithDialog::GetCurrentApp() 952 { 953 TVITEM tvi; 954 tvi.hItem = TreeView_GetSelection(m_hTreeView); 955 if (!tvi.hItem) 956 return NULL; 957 958 tvi.mask = TVIF_PARAM; 959 if (!TreeView_GetItem(m_hTreeView, &tvi)) 960 return NULL; 961 962 return (COpenWithList::SApp*)tvi.lParam; 963 } 964 965 VOID COpenWithDialog::Init(HWND hwnd) 966 { 967 TRACE("COpenWithDialog::Init hwnd %p\n", hwnd); 968 969 m_hDialog = hwnd; 970 SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)this); 971 972 /* Handle register checkbox */ 973 HWND hRegisterCheckbox = GetDlgItem(hwnd, 14003); 974 if (!(m_pInfo->oaifInFlags & OAIF_ALLOW_REGISTRATION)) 975 EnableWindow(hRegisterCheckbox, FALSE); 976 if (m_pInfo->oaifInFlags & OAIF_FORCE_REGISTRATION) 977 SendMessage(hRegisterCheckbox, BM_SETCHECK, BST_CHECKED, 0); 978 if (m_pInfo->oaifInFlags & OAIF_HIDE_REGISTRATION) 979 ShowWindow(hRegisterCheckbox, SW_HIDE); 980 981 if (m_pInfo->pcszFile) 982 { 983 WCHAR wszBuf[MAX_PATH]; 984 UINT cchBuf; 985 986 /* Add filename to label */ 987 cchBuf = GetDlgItemTextW(hwnd, 14001, wszBuf, _countof(wszBuf)); 988 StringCchCopyW(wszBuf + cchBuf, _countof(wszBuf) - cchBuf, PathFindFileNameW(m_pInfo->pcszFile)); 989 SetDlgItemTextW(hwnd, 14001, wszBuf); 990 991 /* Load applications from registry */ 992 m_pAppList->Load(); 993 m_pAppList->LoadRecommended(m_pInfo->pcszFile); 994 995 /* Determine if the type of file can be opened directly from the shell */ 996 if (m_pAppList->IsNoOpen() != FALSE) 997 m_bNoOpen = TRUE; 998 999 /* Init treeview */ 1000 m_hTreeView = GetDlgItem(hwnd, 14002); 1001 m_hImgList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, m_pAppList->GetCount() + 1, m_pAppList->GetCount() + 1); 1002 (void)TreeView_SetImageList(m_hTreeView, m_hImgList, TVSIL_NORMAL); 1003 1004 /* If there are some recommendations add parent nodes: Recommended and Others */ 1005 UINT cRecommended = m_pAppList->GetRecommendedCount(); 1006 if (cRecommended > 0) 1007 { 1008 TVINSERTSTRUCT tvins; 1009 HICON hFolderIcon; 1010 1011 tvins.hParent = tvins.hInsertAfter = TVI_ROOT; 1012 tvins.item.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; 1013 tvins.item.pszText = (LPWSTR)wszBuf; 1014 tvins.item.state = tvins.item.stateMask = TVIS_EXPANDED; 1015 hFolderIcon = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_PROGRAMS_FOLDER), IMAGE_ICON, 0, 0, 0); 1016 tvins.item.iImage = tvins.item.iSelectedImage = ImageList_AddIcon(m_hImgList, hFolderIcon); 1017 1018 LoadStringW(shell32_hInstance, IDS_OPEN_WITH_RECOMMENDED, wszBuf, _countof(wszBuf)); 1019 m_hRecommend = TreeView_InsertItem(m_hTreeView, &tvins); 1020 1021 LoadStringW(shell32_hInstance, IDS_OPEN_WITH_OTHER, wszBuf, _countof(wszBuf)); 1022 m_hOther = TreeView_InsertItem(m_hTreeView, &tvins); 1023 } 1024 else 1025 m_hRecommend = m_hOther = TVI_ROOT; 1026 1027 /* Add all applications */ 1028 BOOL bNoAppSelected = TRUE; 1029 COpenWithList::SApp *pAppList = m_pAppList->GetList(); 1030 for (UINT i = 0; i < m_pAppList->GetCount(); ++i) 1031 { 1032 if (!COpenWithList::IsHidden(&pAppList[i])) 1033 { 1034 if (bNoAppSelected && (pAppList[i].bRecommended || !cRecommended)) 1035 { 1036 AddApp(&pAppList[i], TRUE); 1037 bNoAppSelected = FALSE; 1038 } 1039 else 1040 AddApp(&pAppList[i], FALSE); 1041 } 1042 } 1043 } 1044 } 1045 1046 VOID COpenWithDialog::Accept() 1047 { 1048 COpenWithList::SApp *pApp = GetCurrentApp(); 1049 if (pApp) 1050 { 1051 /* Set programm as default handler */ 1052 if (SendDlgItemMessage(m_hDialog, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) 1053 m_pAppList->SetDefaultHandler(pApp, m_pInfo->pcszFile); 1054 1055 /* Execute program */ 1056 if (m_pInfo->oaifInFlags & OAIF_EXEC) 1057 m_pAppList->Execute(pApp, m_pInfo->pcszFile); 1058 1059 EndDialog(m_hDialog, 1); 1060 } 1061 } 1062 1063 INT_PTR CALLBACK COpenWithDialog::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 1064 { 1065 COpenWithDialog *pThis = reinterpret_cast<COpenWithDialog *>(GetWindowLongPtr(hwndDlg, DWLP_USER)); 1066 1067 switch(uMsg) 1068 { 1069 case WM_INITDIALOG: 1070 { 1071 COpenWithDialog *pThis = reinterpret_cast<COpenWithDialog *>(lParam); 1072 1073 pThis->Init(hwndDlg); 1074 return TRUE; 1075 } 1076 case WM_COMMAND: 1077 switch(LOWORD(wParam)) 1078 { 1079 case 14004: /* browse */ 1080 { 1081 pThis->Browse(); 1082 return TRUE; 1083 } 1084 case IDOK: /* ok */ 1085 { 1086 pThis->Accept(); 1087 return TRUE; 1088 } 1089 case IDCANCEL: /* cancel */ 1090 EndDialog(hwndDlg, 0); 1091 return TRUE; 1092 default: 1093 break; 1094 } 1095 break; 1096 case WM_NOTIFY: 1097 switch (((LPNMHDR)lParam)->code) 1098 { 1099 case TVN_SELCHANGED: 1100 EnableWindow(GetDlgItem(hwndDlg, IDOK), pThis->GetCurrentApp() ? TRUE : FALSE); 1101 break; 1102 case NM_DBLCLK: 1103 case NM_RETURN: 1104 pThis->Accept(); 1105 break; 1106 } 1107 break; 1108 case WM_CLOSE: 1109 EndDialog(hwndDlg, 0); 1110 return TRUE; 1111 default: 1112 break; 1113 } 1114 return FALSE; 1115 } 1116 1117 COpenWithMenu::COpenWithMenu() 1118 { 1119 m_idCmdFirst = 0; 1120 m_idCmdLast = 0; 1121 m_pAppList = new COpenWithList; 1122 } 1123 1124 COpenWithMenu::~COpenWithMenu() 1125 { 1126 TRACE("Destroying COpenWithMenu(%p)\n", this); 1127 1128 if (m_hSubMenu) 1129 { 1130 INT Count, Index; 1131 MENUITEMINFOW mii; 1132 1133 /* get item count */ 1134 Count = GetMenuItemCount(m_hSubMenu); 1135 if (Count == -1) 1136 return; 1137 1138 /* setup menuitem info */ 1139 ZeroMemory(&mii, sizeof(mii)); 1140 mii.cbSize = sizeof(mii); 1141 mii.fMask = MIIM_DATA | MIIM_FTYPE | MIIM_CHECKMARKS; 1142 1143 for(Index = 0; Index < Count; Index++) 1144 { 1145 if (GetMenuItemInfoW(m_hSubMenu, Index, TRUE, &mii)) 1146 { 1147 if (mii.hbmpChecked) 1148 DeleteObject(mii.hbmpChecked); 1149 } 1150 } 1151 } 1152 1153 if (m_pAppList) 1154 delete m_pAppList; 1155 } 1156 1157 HBITMAP COpenWithMenu::IconToBitmap(HICON hIcon) 1158 { 1159 HDC hdc, hdcScr; 1160 HBITMAP hbm, hbmOld; 1161 RECT rc; 1162 1163 hdcScr = GetDC(NULL); 1164 hdc = CreateCompatibleDC(hdcScr); 1165 SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK)); 1166 hbm = CreateCompatibleBitmap(hdcScr, rc.right, rc.bottom); 1167 ReleaseDC(NULL, hdcScr); 1168 1169 hbmOld = (HBITMAP)SelectObject(hdc, hbm); 1170 FillRect(hdc, &rc, (HBRUSH)(COLOR_MENU + 1)); 1171 if (!DrawIconEx(hdc, 0, 0, hIcon, rc.right, rc.bottom, 0, NULL, DI_NORMAL)) 1172 ERR("DrawIcon failed: %x\n", GetLastError()); 1173 SelectObject(hdc, hbmOld); 1174 1175 DeleteDC(hdc); 1176 1177 return hbm; 1178 } 1179 1180 VOID COpenWithMenu::AddChooseProgramItem() 1181 { 1182 MENUITEMINFOW mii; 1183 WCHAR wszBuf[128]; 1184 1185 ZeroMemory(&mii, sizeof(mii)); 1186 mii.cbSize = sizeof(mii); 1187 mii.fMask = MIIM_TYPE | MIIM_ID; 1188 mii.fType = MFT_SEPARATOR; 1189 mii.wID = -1; 1190 InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii); 1191 1192 if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH_CHOOSE, wszBuf, _countof(wszBuf))) 1193 { 1194 ERR("Failed to load string\n"); 1195 return; 1196 } 1197 1198 mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; 1199 mii.fType = MFT_STRING; 1200 mii.fState = MFS_ENABLED; 1201 mii.wID = m_idCmdLast; 1202 mii.dwTypeData = (LPWSTR)wszBuf; 1203 mii.cch = wcslen(wszBuf); 1204 1205 InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii); 1206 } 1207 1208 VOID COpenWithMenu::AddApp(PVOID pApp) 1209 { 1210 MENUITEMINFOW mii; 1211 LPCWSTR pwszName = m_pAppList->GetName((COpenWithList::SApp*)pApp); 1212 if (!pwszName) return; 1213 1214 ZeroMemory(&mii, sizeof(mii)); 1215 mii.cbSize = sizeof(mii); 1216 mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; 1217 mii.fType = MFT_STRING; 1218 mii.fState = MFS_ENABLED; 1219 mii.wID = m_idCmdLast; 1220 mii.dwTypeData = const_cast<LPWSTR>(pwszName); 1221 mii.cch = wcslen(mii.dwTypeData); 1222 mii.dwItemData = (ULONG_PTR)pApp; 1223 1224 HICON hIcon = m_pAppList->GetIcon((COpenWithList::SApp*)pApp); 1225 if (hIcon) 1226 { 1227 mii.fMask |= MIIM_CHECKMARKS; 1228 mii.hbmpChecked = mii.hbmpUnchecked = IconToBitmap(hIcon); 1229 } 1230 1231 if (InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii)) 1232 m_idCmdLast++; 1233 } 1234 1235 HRESULT WINAPI COpenWithMenu::QueryContextMenu( 1236 HMENU hMenu, 1237 UINT indexMenu, 1238 UINT idCmdFirst, 1239 UINT idCmdLast, 1240 UINT uFlags) 1241 { 1242 TRACE("hMenu %p indexMenu %u idFirst %u idLast %u uFlags %u\n", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); 1243 1244 INT DefaultPos = GetMenuDefaultItem(hMenu, TRUE, 0); 1245 1246 WCHAR wszName[100]; 1247 UINT NameId = (DefaultPos == -1 ? IDS_OPEN : IDS_OPEN_WITH); 1248 if (!LoadStringW(shell32_hInstance, NameId, wszName, _countof(wszName))) 1249 { 1250 ERR("Failed to load string\n"); 1251 return E_FAIL; 1252 } 1253 1254 /* Init first cmd id and submenu */ 1255 m_idCmdFirst = m_idCmdLast = idCmdFirst; 1256 m_hSubMenu = NULL; 1257 1258 /* If we are going to be default item, we shouldn't be submenu */ 1259 if (DefaultPos != -1) 1260 { 1261 /* Load applications list */ 1262 m_pAppList->Load(); 1263 m_pAppList->LoadRecommended(m_wszPath); 1264 1265 /* Create submenu only if there is more than one application and menu has a default item */ 1266 if (m_pAppList->GetRecommendedCount() > 1) 1267 { 1268 m_hSubMenu = CreatePopupMenu(); 1269 1270 for(UINT i = 0; i < m_pAppList->GetCount(); ++i) 1271 { 1272 COpenWithList::SApp *pApp = m_pAppList->GetList() + i; 1273 if (pApp->bRecommended) 1274 AddApp(pApp); 1275 } 1276 1277 AddChooseProgramItem(); 1278 } 1279 } 1280 1281 /* Insert menu item */ 1282 MENUITEMINFOW mii; 1283 ZeroMemory(&mii, sizeof(mii)); 1284 mii.cbSize = sizeof(mii); 1285 mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; 1286 if (m_hSubMenu) 1287 { 1288 mii.fMask |= MIIM_SUBMENU; 1289 mii.hSubMenu = m_hSubMenu; 1290 mii.wID = -1; 1291 } 1292 else 1293 mii.wID = m_idCmdLast; 1294 1295 mii.fType = MFT_STRING; 1296 mii.dwTypeData = (LPWSTR)wszName; 1297 mii.cch = wcslen(wszName); 1298 1299 mii.fState = MFS_ENABLED; 1300 if (DefaultPos == -1) 1301 mii.fState |= MFS_DEFAULT; 1302 1303 if (!InsertMenuItemW(hMenu, DefaultPos + 1, TRUE, &mii)) 1304 return E_FAIL; 1305 1306 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, m_idCmdLast - m_idCmdFirst + 1); 1307 } 1308 1309 HRESULT WINAPI 1310 COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) 1311 { 1312 HRESULT hr = E_FAIL; 1313 1314 TRACE("This %p idFirst %u idLast %u idCmd %u\n", this, m_idCmdFirst, m_idCmdLast, m_idCmdFirst + LOWORD(lpici->lpVerb)); 1315 1316 if (HIWORD(lpici->lpVerb) == 0 && m_idCmdFirst + LOWORD(lpici->lpVerb) <= m_idCmdLast) 1317 { 1318 if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdLast) 1319 { 1320 OPENASINFO info; 1321 LPCWSTR pwszExt = PathFindExtensionW(m_wszPath); 1322 1323 info.pcszFile = m_wszPath; 1324 info.oaifInFlags = OAIF_EXEC; 1325 if (pwszExt[0]) 1326 info.oaifInFlags |= OAIF_REGISTER_EXT | OAIF_ALLOW_REGISTRATION; 1327 info.pcszClass = NULL; 1328 hr = SHOpenWithDialog(lpici->hwnd, &info); 1329 } 1330 else 1331 { 1332 /* retrieve menu item info */ 1333 MENUITEMINFOW mii; 1334 ZeroMemory(&mii, sizeof(mii)); 1335 mii.cbSize = sizeof(mii); 1336 mii.fMask = MIIM_DATA | MIIM_FTYPE; 1337 1338 if (GetMenuItemInfoW(m_hSubMenu, LOWORD(lpici->lpVerb), TRUE, &mii) && mii.dwItemData) 1339 { 1340 /* launch item with specified app */ 1341 COpenWithList::SApp *pApp = (COpenWithList::SApp*)mii.dwItemData; 1342 COpenWithList::Execute(pApp, m_wszPath); 1343 hr = S_OK; 1344 } 1345 } 1346 } 1347 1348 return hr; 1349 } 1350 1351 HRESULT WINAPI 1352 COpenWithMenu::GetCommandString(UINT_PTR idCmd, UINT uType, 1353 UINT* pwReserved, LPSTR pszName, UINT cchMax ) 1354 { 1355 FIXME("%p %lu %u %p %p %u\n", this, 1356 idCmd, uType, pwReserved, pszName, cchMax ); 1357 1358 return E_NOTIMPL; 1359 } 1360 1361 HRESULT WINAPI COpenWithMenu::HandleMenuMsg( 1362 UINT uMsg, 1363 WPARAM wParam, 1364 LPARAM lParam) 1365 { 1366 TRACE("This %p uMsg %x\n", this, uMsg); 1367 1368 return E_NOTIMPL; 1369 } 1370 1371 HRESULT WINAPI 1372 COpenWithMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder, 1373 IDataObject *pdtobj, 1374 HKEY hkeyProgID) 1375 { 1376 LPCITEMIDLIST pidlFolder2; 1377 LPCITEMIDLIST pidlChild; 1378 1379 TRACE("This %p\n", this); 1380 1381 if (pdtobj == NULL) 1382 return E_INVALIDARG; 1383 1384 CDataObjectHIDA pida(pdtobj); 1385 if (FAILED(pida.hr())) 1386 { 1387 ERR("pdtobj->GetData failed with 0x%x\n", pida.hr()); 1388 return pida.hr(); 1389 } 1390 1391 ASSERT(pida->cidl >= 1); 1392 1393 pidlFolder2 = HIDA_GetPIDLFolder(pida); 1394 pidlChild = HIDA_GetPIDLItem(pida, 0); 1395 1396 if (!_ILIsValue(pidlChild)) 1397 { 1398 TRACE("pidl is not a file\n"); 1399 return E_FAIL; 1400 } 1401 1402 CComHeapPtr<ITEMIDLIST> pidl(ILCombine(pidlFolder2, pidlChild)); 1403 if (!pidl) 1404 { 1405 ERR("no mem\n"); 1406 return E_OUTOFMEMORY; 1407 } 1408 1409 if (!SHGetPathFromIDListW(pidl, m_wszPath)) 1410 { 1411 ERR("SHGetPathFromIDListW failed\n"); 1412 return E_FAIL; 1413 } 1414 1415 TRACE("szPath %s\n", debugstr_w(m_wszPath)); 1416 1417 LPCWSTR pwszExt = PathFindExtensionW(m_wszPath); 1418 if (PathIsExeW(pwszExt) || !_wcsicmp(pwszExt, L".lnk")) 1419 { 1420 TRACE("file is a executable or shortcut\n"); 1421 return E_FAIL; 1422 } 1423 1424 return S_OK; 1425 } 1426 1427 HRESULT WINAPI 1428 SHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo) 1429 { 1430 INT_PTR ret; 1431 1432 TRACE("SHOpenWithDialog hwndParent %p poainfo %p\n", hwndParent, poainfo); 1433 1434 InitCommonControls(); 1435 1436 if (poainfo->pcszClass == NULL && poainfo->pcszFile == NULL) 1437 return E_FAIL; 1438 1439 COpenWithDialog pDialog(poainfo); 1440 1441 if (pDialog.IsNoOpen(hwndParent)) 1442 return S_OK; 1443 1444 ret = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCE(IDD_OPEN_WITH), hwndParent, 1445 COpenWithDialog::DialogProc, (LPARAM)&pDialog); 1446 1447 if (ret == (INT_PTR)-1) 1448 { 1449 ERR("Failed to create dialog: %u\n", GetLastError()); 1450 return E_FAIL; 1451 } 1452 1453 return S_OK; 1454 } 1455