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