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