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