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