Reactos
at master 818 lines 22 kB view raw
1/* 2 * provides new shell item service 3 * 4 * Copyright 2007 Johannes Anderwald (johannes.anderwald@reactos.org) 5 * Copyright 2009 Andrew Hill 6 * Copyright 2012 Rafal Harabien 7 * Copyright 2019 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24#include "precomp.h" 25 26WINE_DEFAULT_DEBUG_CHANNEL(shell); 27 28CNewMenu::CNewMenu() : 29 m_pidlFolder(NULL), 30 m_pItems(NULL), 31 m_pLinkItem(NULL), 32 m_pSite(NULL), 33 m_idCmdFirst(0), 34 m_idCmdFolder(-1), 35 m_idCmdLink(-1), 36 m_bCustomIconFolder(FALSE), 37 m_bCustomIconLink(FALSE), 38 m_hIconFolder(NULL), 39 m_hIconLink(NULL) 40{ 41} 42 43CNewMenu::~CNewMenu() 44{ 45 UnloadAllItems(); 46 47 if (m_bCustomIconFolder && m_hIconFolder) 48 DestroyIcon(m_hIconFolder); 49 if (m_bCustomIconLink && m_hIconLink) 50 DestroyIcon(m_hIconLink); 51 if (m_pidlFolder) 52 ILFree(m_pidlFolder); 53} 54 55void CNewMenu::UnloadItem(SHELLNEW_ITEM *pItem) 56{ 57 /* Note: free allows NULL as argument */ 58 free(pItem->pData); 59 free(pItem->pwszDesc); 60 free(pItem->pwszExt); 61 62 if (pItem->hIcon) 63 DestroyIcon(pItem->hIcon); 64 65 HeapFree(GetProcessHeap(), 0, pItem); 66} 67 68void CNewMenu::UnloadAllItems() 69{ 70 SHELLNEW_ITEM *pCurItem; 71 72 /* Unload the handler items, including the link item */ 73 while (m_pItems) 74 { 75 pCurItem = m_pItems; 76 m_pItems = m_pItems->pNext; 77 UnloadItem(pCurItem); 78 } 79 m_pItems = NULL; 80 m_pLinkItem = NULL; 81} 82 83CNewMenu::SHELLNEW_ITEM *CNewMenu::LoadItem(LPCWSTR pwszExt) 84{ 85 HKEY hKey; 86 WCHAR wszBuf[MAX_PATH]; 87 PBYTE pData = NULL; 88 DWORD cbData; 89 90 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s\\ShellNew", pwszExt); 91 92 TRACE("LoadItem Keyname %s Name %s\n", debugstr_w(pwszExt), debugstr_w(wszBuf)); 93 94 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 95 { 96 WCHAR wszValue[MAX_PATH]; 97 cbData = sizeof(wszValue); 98 if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszValue, 99 &cbData) != ERROR_SUCCESS || !wszValue[0]) 100 { 101 TRACE("Failed to open key\n"); 102 return NULL; 103 } 104 wszValue[_countof(wszValue) - 1] = UNICODE_NULL; // Avoid buffer overrun 105 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s\\%s\\ShellNew", pwszExt, wszValue); 106 if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 107 { 108 TRACE("Failed to open key\n"); 109 return NULL; 110 } 111 } 112 113 /* Find first valid value */ 114 struct 115 { 116 LPCWSTR pszName; 117 SHELLNEW_TYPE Type; 118 BOOL bNeedData; 119 BOOL bStr; 120 } Types[] = { 121 {L"FileName", SHELLNEW_TYPE_FILENAME, TRUE, TRUE}, 122 {L"Command", SHELLNEW_TYPE_COMMAND, TRUE, TRUE}, 123 {L"Data", SHELLNEW_TYPE_DATA, TRUE, FALSE}, 124 {L"NullFile", SHELLNEW_TYPE_NULLFILE, FALSE}, 125 {NULL} 126 }; 127 UINT i; 128 129 for (i = 0; Types[i].pszName; ++i) 130 { 131 /* Note: We are using ANSI function because strings can be treated as data */ 132 cbData = 0; 133 DWORD dwFlags = Types[i].bStr ? RRF_RT_REG_SZ : RRF_RT_ANY; 134 DWORD dwType; 135 if (RegGetValueW(hKey, NULL, Types[i].pszName, dwFlags, NULL, NULL, &cbData) == ERROR_SUCCESS) 136 { 137 if (Types[i].bNeedData && cbData > 0) 138 { 139 pData = (PBYTE)malloc(cbData); 140 RegGetValueW(hKey, NULL, Types[i].pszName, dwFlags, &dwType, pData, &cbData); 141 if (!Types[i].bStr && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) 142 { 143 PBYTE pData2 = (PBYTE)malloc(cbData); 144 cbData = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pData, -1, (LPSTR)pData2, cbData, NULL, NULL); 145 free(pData); 146 pData = pData2; 147 } 148 } 149 break; 150 } 151 } 152 RegCloseKey(hKey); 153 154 /* Was any key found? */ 155 if (!Types[i].pszName) 156 { 157 free(pData); 158 return NULL; 159 } 160 161 SHFILEINFOW fi; 162 if (!SHGetFileInfoW(pwszExt, FILE_ATTRIBUTE_NORMAL, &fi, sizeof(fi), SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME | SHGFI_ICON | SHGFI_SMALLICON)) 163 { 164 free(pData); 165 return NULL; 166 } 167 168 /* Create new item */ 169 SHELLNEW_ITEM *pNewItem = static_cast<SHELLNEW_ITEM *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SHELLNEW_ITEM))); 170 if (!pNewItem) 171 { 172 free(pData); 173 return NULL; 174 } 175 176 TRACE("new item %ls\n", fi.szTypeName); 177 pNewItem->Type = Types[i].Type; 178 pNewItem->pData = pData; 179 pNewItem->cbData = pData ? cbData : 0; 180 pNewItem->pwszExt = _wcsdup(pwszExt); 181 pNewItem->pwszDesc = _wcsdup(fi.szTypeName); 182 if (fi.hIcon) 183 pNewItem->hIcon = fi.hIcon; 184 185 return pNewItem; 186} 187 188BOOL 189CNewMenu::CacheItems() 190{ 191 HKEY hKey; 192 DWORD dwSize = 0; 193 DWORD dwIndex = 0; 194 LPWSTR lpValue; 195 LPWSTR lpValues; 196 WCHAR wszName[MAX_PATH]; 197 SHELLNEW_ITEM *pNewItem; 198 SHELLNEW_ITEM *pCurItem = NULL; 199 200 /* Enumerate all extensions */ 201 while (RegEnumKeyW(HKEY_CLASSES_ROOT, dwIndex++, wszName, _countof(wszName)) == ERROR_SUCCESS) 202 { 203 if (wszName[0] != L'.') 204 continue; 205 206 pNewItem = LoadItem(wszName); 207 if (pNewItem) 208 { 209 dwSize += wcslen(wszName) + 1; 210 if (!m_pLinkItem && _wcsicmp(pNewItem->pwszExt, L".lnk") == 0) 211 { 212 /* The unique link handler */ 213 m_pLinkItem = pNewItem; 214 } 215 216 /* Add at the end of the list */ 217 if (pCurItem) 218 { 219 pCurItem->pNext = pNewItem; 220 pCurItem = pNewItem; 221 } 222 else 223 { 224 pCurItem = m_pItems = pNewItem; 225 } 226 } 227 } 228 229 dwSize++; 230 231 lpValues = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize * sizeof(WCHAR)); 232 if (!lpValues) 233 return FALSE; 234 235 for (pCurItem = m_pItems, lpValue = lpValues; pCurItem; pCurItem = pCurItem->pNext) 236 { 237 memcpy(lpValue, pCurItem->pwszExt, (wcslen(pCurItem->pwszExt) + 1) * sizeof(WCHAR)); 238 lpValue += wcslen(pCurItem->pwszExt) + 1; 239 } 240 241 if (RegCreateKeyEx(HKEY_CURRENT_USER, ShellNewKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) 242 { 243 HeapFree(GetProcessHeap(), 0, lpValues); 244 return FALSE; 245 } 246 247 if (RegSetValueExW(hKey, L"Classes", NULL, REG_MULTI_SZ, (LPBYTE)lpValues, dwSize * sizeof(WCHAR)) != ERROR_SUCCESS) 248 { 249 HeapFree(GetProcessHeap(), 0, lpValues); 250 RegCloseKey(hKey); 251 return FALSE; 252 } 253 254 HeapFree(GetProcessHeap(), 0, lpValues); 255 RegCloseKey(hKey); 256 257 return TRUE; 258} 259 260BOOL 261CNewMenu::LoadCachedItems() 262{ 263 LPWSTR wszName; 264 LPWSTR lpValues; 265 DWORD dwSize; 266 HKEY hKey; 267 SHELLNEW_ITEM *pNewItem; 268 SHELLNEW_ITEM *pCurItem = NULL; 269 270 if (RegOpenKeyExW(HKEY_CURRENT_USER, ShellNewKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 271 return FALSE; 272 273 if (RegQueryValueExW(hKey, L"Classes", NULL, NULL, NULL, &dwSize) != ERROR_SUCCESS) 274 return FALSE; 275 276 lpValues = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, dwSize); 277 if (!lpValues) 278 return FALSE; 279 280 if (RegQueryValueExW(hKey, L"Classes", NULL, NULL, (LPBYTE)lpValues, &dwSize) != ERROR_SUCCESS) 281 { 282 HeapFree(GetProcessHeap(), 0, lpValues); 283 return FALSE; 284 } 285 286 wszName = lpValues; 287 288 for (; *wszName != '\0'; wszName += wcslen(wszName) + 1) 289 { 290 pNewItem = LoadItem(wszName); 291 if (pNewItem) 292 { 293 if (!m_pLinkItem && _wcsicmp(pNewItem->pwszExt, L".lnk") == 0) 294 { 295 /* The unique link handler */ 296 m_pLinkItem = pNewItem; 297 } 298 299 /* Add at the end of the list */ 300 if (pCurItem) 301 { 302 pCurItem->pNext = pNewItem; 303 pCurItem = pNewItem; 304 } 305 else 306 { 307 pCurItem = m_pItems = pNewItem; 308 } 309 } 310 } 311 312 HeapFree(GetProcessHeap(), 0, lpValues); 313 RegCloseKey(hKey); 314 315 return TRUE; 316} 317 318BOOL 319CNewMenu::LoadAllItems() 320{ 321 // TODO: We need to find a way to refresh the cache from time to time, when 322 // e.g. new extensions with ShellNew handlers have been added or removed. 323 324 /* If there are any unload them */ 325 UnloadAllItems(); 326 327 if (!LoadCachedItems()) 328 { 329 CacheItems(); 330 } 331 332 return (m_pItems != NULL); 333} 334 335UINT 336CNewMenu::InsertShellNewItems(HMENU hMenu, UINT idCmdFirst, UINT Pos) 337{ 338 MENUITEMINFOW mii; 339 UINT idCmd = idCmdFirst; 340 WCHAR wszBuf[256]; 341 342 if (m_pItems == NULL) 343 { 344 if (!LoadAllItems()) 345 return 0; 346 } 347 348 ZeroMemory(&mii, sizeof(mii)); 349 mii.cbSize = sizeof(mii); 350 351 m_idCmdFirst = idCmd; 352 353 /* Insert the new folder action */ 354 if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWFOLDER, wszBuf, _countof(wszBuf))) 355 wszBuf[0] = 0; 356 mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_STRING; 357 mii.dwTypeData = wszBuf; 358 mii.cch = wcslen(mii.dwTypeData); 359 mii.wID = idCmd; 360 mii.hbmpItem = HBMMENU_CALLBACK; 361 if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii)) 362 m_idCmdFolder = idCmd++; 363 364 /* Insert the new shortcut action */ 365 if (m_pLinkItem) 366 { 367 if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWLINK, wszBuf, _countof(wszBuf))) 368 wszBuf[0] = 0; 369 mii.dwTypeData = wszBuf; 370 mii.cch = wcslen(mii.dwTypeData); 371 mii.wID = idCmd; 372 if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii)) 373 m_idCmdLink = idCmd++; 374 } 375 376 /* Insert a seperator for the custom new action */ 377 mii.fMask = MIIM_TYPE | MIIM_ID; 378 mii.fType = MFT_SEPARATOR; 379 mii.wID = -1; 380 InsertMenuItemW(hMenu, Pos++, TRUE, &mii); 381 382 /* Insert the rest of the items */ 383 mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_STRING | MIIM_DATA; 384 mii.fType = 0; 385 386 for (SHELLNEW_ITEM *pCurItem = m_pItems; pCurItem; pCurItem = pCurItem->pNext) 387 { 388 /* Skip shortcut item */ 389 if (pCurItem == m_pLinkItem) 390 continue; 391 392 TRACE("szDesc %s\n", debugstr_w(pCurItem->pwszDesc)); 393 mii.dwItemData = (ULONG_PTR)pCurItem; 394 mii.dwTypeData = pCurItem->pwszDesc; 395 mii.cch = wcslen(mii.dwTypeData); 396 mii.wID = idCmd; 397 if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii)) 398 ++idCmd; 399 } 400 401 return idCmd - idCmdFirst; 402} 403 404CNewMenu::SHELLNEW_ITEM *CNewMenu::FindItemFromIdOffset(UINT IdOffset) 405{ 406 /* Folder */ 407 if (m_idCmdFirst + IdOffset == m_idCmdFolder) 408 return NULL; 409 410 /* Shortcut */ 411 if (m_idCmdFirst + IdOffset == m_idCmdLink) 412 return m_pLinkItem; 413 414 /* Find shell new item - Retrieve menu item info */ 415 MENUITEMINFOW mii; 416 ZeroMemory(&mii, sizeof(mii)); 417 mii.cbSize = sizeof(mii); 418 mii.fMask = MIIM_DATA; 419 420 if (GetMenuItemInfoW(m_hSubMenu, m_idCmdFirst + IdOffset, FALSE, &mii) && mii.dwItemData) 421 return (SHELLNEW_ITEM *)mii.dwItemData; 422 else 423 return NULL; 424} 425 426HRESULT CNewMenu::SelectNewItem(LONG wEventId, UINT uFlags, LPWSTR pszName, BOOL bRename) 427{ 428 CComPtr<IShellBrowser> lpSB; 429 CComPtr<IShellView> lpSV; 430 HRESULT hr = E_FAIL; 431 LPITEMIDLIST pidl; 432 PITEMID_CHILD pidlNewItem; 433 DWORD dwSelectFlags; 434 435 dwSelectFlags = SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT; 436 if (bRename) 437 dwSelectFlags |= SVSI_EDIT; 438 439 /* Notify the view object about the new item */ 440 SHChangeNotify(wEventId, uFlags | SHCNF_FLUSH, (LPCVOID)pszName, NULL); 441 442 if (!m_pSite) 443 return S_OK; 444 445 /* Get a pointer to the shell view */ 446 hr = IUnknown_QueryService(m_pSite, SID_SFolderView, IID_PPV_ARG(IShellView, &lpSV)); 447 if (FAILED_UNEXPECTEDLY(hr)) 448 return S_OK; 449 450 /* Attempt to get the pidl of the new item */ 451 hr = SHILCreateFromPathW(pszName, &pidl, NULL); 452 if (FAILED_UNEXPECTEDLY(hr)) 453 return hr; 454 455 pidlNewItem = ILFindLastID(pidl); 456 457 hr = lpSV->SelectItem(pidlNewItem, dwSelectFlags); 458 459 SHFree(pidl); 460 461 return hr; 462} 463 464// Code is duplicated in CDefaultContextMenu 465HRESULT CNewMenu::CreateNewFolder(LPCMINVOKECOMMANDINFO lpici) 466{ 467 WCHAR wszPath[MAX_PATH]; 468 WCHAR wszName[MAX_PATH]; 469 WCHAR wszNewFolder[25]; 470 HRESULT hr; 471 472 /* Get folder path */ 473 hr = SHGetPathFromIDListW(m_pidlFolder, wszPath); 474 if (FAILED_UNEXPECTEDLY(hr)) 475 return hr; 476 477 if (!LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder))) 478 return E_FAIL; 479 480 /* Create the name of the new directory */ 481 if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFolder)) 482 return E_FAIL; 483 484 /* Create the new directory and show the appropriate dialog in case of error */ 485 if (SHCreateDirectory(lpici->hwnd, wszName) != ERROR_SUCCESS) 486 return E_FAIL; 487 488 /* Show and select the new item in the def view */ 489 SelectNewItem(SHCNE_MKDIR, SHCNF_PATHW, wszName, TRUE); 490 491 return S_OK; 492} 493 494HRESULT CNewMenu::NewItemByCommand(SHELLNEW_ITEM *pItem, LPCWSTR wszPath) 495{ 496 WCHAR wszBuf[MAX_PATH]; 497 LPWSTR Ptr, pwszCmd; 498 WCHAR wszTemp[MAX_PATH]; 499 STARTUPINFOW si; 500 PROCESS_INFORMATION pi; 501 502 if (!ExpandEnvironmentStringsW((LPWSTR)pItem->pData, wszBuf, _countof(wszBuf))) 503 { 504 TRACE("ExpandEnvironmentStrings failed\n"); 505 return E_FAIL; 506 } 507 508 /* Expand command parameter, FIXME: there can be more modifiers */ 509 Ptr = wcsstr(wszBuf, L"%1"); 510 if (Ptr) 511 { 512 Ptr[1] = L's'; 513 StringCbPrintfW(wszTemp, sizeof(wszTemp), wszBuf, wszPath); 514 pwszCmd = wszTemp; 515 } 516 else 517 { 518 pwszCmd = wszBuf; 519 } 520 521 /* Create process */ 522 ZeroMemory(&si, sizeof(si)); 523 si.cb = sizeof(si); 524 if (CreateProcessW(NULL, pwszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) 525 { 526 CloseHandle(pi.hProcess); 527 CloseHandle(pi.hThread); 528 return S_OK; 529 } 530 else 531 { 532 ERR("Failed to create process\n"); 533 return E_FAIL; 534 } 535} 536 537HRESULT CNewMenu::NewItemByNonCommand(SHELLNEW_ITEM *pItem, LPWSTR wszName, 538 DWORD cchNameMax, LPCWSTR wszPath) 539{ 540 BOOL bSuccess = TRUE; 541 542 CStringW strNewItem; 543 strNewItem.Format(IDS_NEWITEMFORMAT, pItem->pwszDesc); 544 strNewItem += pItem->pwszExt; 545 546 /* Create the name of the new file */ 547 if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, strNewItem)) 548 return E_FAIL; 549 550 /* Create new file */ 551 HANDLE hFile = CreateFileW(wszName, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); 552 if (hFile != INVALID_HANDLE_VALUE) 553 { 554 if (pItem->Type == SHELLNEW_TYPE_DATA) 555 { 556 /* Write a content */ 557 DWORD cbWritten; 558 WriteFile(hFile, pItem->pData, pItem->cbData, &cbWritten, NULL); 559 } 560 561 /* Close file now */ 562 CloseHandle(hFile); 563 } 564 else 565 { 566 bSuccess = FALSE; 567 } 568 569 if (pItem->Type == SHELLNEW_TYPE_FILENAME) 570 { 571 /* Copy file */ 572 if (!CopyFileW((LPWSTR)pItem->pData, wszName, FALSE)) 573 ERR("Copy file failed: %ls\n", (LPWSTR)pItem->pData); 574 } 575 576 /* Show message if we failed */ 577 if (bSuccess) 578 { 579 TRACE("Notifying fs %s\n", debugstr_w(wszName)); 580 SelectNewItem(SHCNE_CREATE, SHCNF_PATHW, wszName, pItem != m_pLinkItem); 581 } 582 else 583 { 584 CStringW Caption(MAKEINTRESOURCEW(IDS_CREATEFILE_CAPTION)); 585 CStringW Message(MAKEINTRESOURCEW(IDS_CREATEFILE_DENIED)); 586 Message.FormatMessage(Message.GetString(), wszName); 587 MessageBoxW(0, Message, Caption, MB_ICONEXCLAMATION | MB_OK); 588 } 589 590 return S_OK; 591} 592 593HRESULT CNewMenu::CreateNewItem(SHELLNEW_ITEM *pItem, LPCMINVOKECOMMANDINFO lpcmi) 594{ 595 HRESULT hr; 596 WCHAR wszPath[MAX_PATH], wszName[MAX_PATH]; 597 598 /* Get folder path */ 599 hr = SHGetPathFromIDListW(m_pidlFolder, wszPath); 600 if (FAILED_UNEXPECTEDLY(hr)) 601 return hr; 602 603 if (pItem == m_pLinkItem) 604 { 605 NewItemByNonCommand(pItem, wszName, _countof(wszName), wszPath); 606 NewItemByCommand(pItem, wszName); 607 return S_OK; 608 } 609 610 switch (pItem->Type) 611 { 612 case SHELLNEW_TYPE_COMMAND: 613 NewItemByCommand(pItem, wszPath); 614 break; 615 616 case SHELLNEW_TYPE_DATA: 617 case SHELLNEW_TYPE_FILENAME: 618 case SHELLNEW_TYPE_NULLFILE: 619 NewItemByNonCommand(pItem, wszName, _countof(wszName), wszPath); 620 break; 621 622 case SHELLNEW_TYPE_INVALID: 623 ERR("Invalid type\n"); 624 break; 625 } 626 627 return S_OK; 628} 629 630HRESULT STDMETHODCALLTYPE CNewMenu::SetSite(IUnknown *pUnkSite) 631{ 632 m_pSite = pUnkSite; 633 return S_OK; 634} 635 636HRESULT STDMETHODCALLTYPE CNewMenu::GetSite(REFIID riid, void **ppvSite) 637{ 638 return m_pSite->QueryInterface(riid, ppvSite); 639} 640 641HRESULT 642WINAPI 643CNewMenu::QueryContextMenu(HMENU hMenu, 644 UINT indexMenu, 645 UINT idCmdFirst, 646 UINT idCmdLast, 647 UINT uFlags) 648{ 649 MENUITEMINFOW mii; 650 UINT cItems = 0; 651 WCHAR wszNew[200]; 652 653 TRACE("%p %p %u %u %u %u\n", this, 654 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); 655 656 if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszNew, _countof(wszNew))) 657 return E_FAIL; 658 659 m_hSubMenu = CreateMenu(); 660 if (!m_hSubMenu) 661 return E_FAIL; 662 663 cItems = InsertShellNewItems(m_hSubMenu, idCmdFirst, 0); 664 665 ZeroMemory(&mii, sizeof(mii)); 666 mii.cbSize = sizeof(mii); 667 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU; 668 mii.fType = MFT_STRING; 669 mii.wID = -1; 670 mii.dwTypeData = wszNew; 671 mii.cch = wcslen(mii.dwTypeData); 672 mii.fState = MFS_ENABLED; 673 mii.hSubMenu = m_hSubMenu; 674 675 if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii)) 676 return E_FAIL; 677 678 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cItems); 679} 680 681HRESULT 682WINAPI 683CNewMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) 684{ 685 HRESULT hr = E_FAIL; 686 687 if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdFolder) 688 { 689 hr = CreateNewFolder(lpici); 690 } 691 else 692 { 693 SHELLNEW_ITEM *pItem = FindItemFromIdOffset(LOWORD(lpici->lpVerb)); 694 if (pItem) 695 hr = CreateNewItem(pItem, lpici); 696 } 697 698 TRACE("CNewMenu::InvokeCommand %x\n", hr); 699 return hr; 700} 701 702HRESULT 703WINAPI 704CNewMenu::GetCommandString(UINT_PTR idCmd, 705 UINT uType, 706 UINT *pwReserved, 707 LPSTR pszName, 708 UINT cchMax) 709{ 710 FIXME("%p %lu %u %p %p %u\n", this, 711 idCmd, uType, pwReserved, pszName, cchMax ); 712 713 return E_NOTIMPL; 714} 715 716HRESULT 717WINAPI 718CNewMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) 719{ 720 return HandleMenuMsg2(uMsg, wParam, lParam, NULL); 721} 722 723HRESULT 724WINAPI 725CNewMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) 726{ 727 switch (uMsg) 728 { 729 case WM_MEASUREITEM: 730 { 731 MEASUREITEMSTRUCT* lpmis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam); 732 if (!lpmis || lpmis->CtlType != ODT_MENU) 733 break; 734 735 if (lpmis->itemWidth < (UINT)GetSystemMetrics(SM_CXMENUCHECK)) 736 lpmis->itemWidth = GetSystemMetrics(SM_CXMENUCHECK); 737 if (lpmis->itemHeight < 16) 738 lpmis->itemHeight = 16; 739 740 if (plResult) 741 *plResult = TRUE; 742 break; 743 } 744 case WM_DRAWITEM: 745 { 746 DRAWITEMSTRUCT* lpdis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam); 747 if (!lpdis || lpdis->CtlType != ODT_MENU) 748 break; 749 750 DWORD id = lpdis->itemID; 751 HICON hIcon = NULL; 752 if (id == m_idCmdFolder) 753 { 754 hIcon = m_hIconFolder; 755 } 756 else if (id == m_idCmdLink) 757 { 758 hIcon = m_hIconLink; 759 } 760 else 761 { 762 SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id - m_idCmdFirst); 763 if (pItem) 764 hIcon = pItem->hIcon; 765 } 766 767 if (!hIcon) 768 break; 769 770 DrawIconEx(lpdis->hDC, 771 2, 772 lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - 16) / 2, 773 hIcon, 774 16, 775 16, 776 0, NULL, DI_NORMAL); 777 778 if(plResult) 779 *plResult = TRUE; 780 } 781 } 782 783 return S_OK; 784} 785 786HRESULT WINAPI 787CNewMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder, 788 IDataObject *pdtobj, HKEY hkeyProgID) 789{ 790 const INT cx = GetSystemMetrics(SM_CXSMICON), cy = GetSystemMetrics(SM_CYSMICON); 791 WCHAR wszIconPath[MAX_PATH]; 792 int icon_idx; 793 794 m_pidlFolder = ILClone(pidlFolder); 795 796 /* Load folder and shortcut icons */ 797 if (HLM_GetIconW(IDI_SHELL_FOLDER - 1, wszIconPath, _countof(wszIconPath), &icon_idx)) 798 { 799 ::ExtractIconExW(wszIconPath, icon_idx, &m_hIconFolder, NULL, 1); 800 m_bCustomIconFolder = TRUE; 801 } 802 else 803 { 804 m_hIconFolder = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, cx, cy, LR_SHARED); 805 } 806 807 if (HLM_GetIconW(IDI_SHELL_SHORTCUT - 1, wszIconPath, _countof(wszIconPath), &icon_idx)) 808 { 809 ::ExtractIconExW(wszIconPath, icon_idx, &m_hIconLink, NULL, 1); 810 m_bCustomIconLink = TRUE; 811 } 812 else 813 { 814 m_hIconLink = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), IMAGE_ICON, cx, cy, LR_SHARED); 815 } 816 817 return S_OK; 818}