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