[SHELL32] CCopyToMenu/CMoveToMenu: Check if this_ is NULL
[reactos.git] / dll / win32 / shell32 / CNewMenu.cpp
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, (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 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Cannot create file: %s", wszName);
569 MessageBoxW(NULL, wszBuf, L"Cannot create file", MB_OK | MB_ICONERROR); // FIXME load localized error msg
570 }
571
572 return S_OK;
573 }
574
575 HRESULT CNewMenu::CreateNewItem(SHELLNEW_ITEM *pItem, LPCMINVOKECOMMANDINFO lpcmi)
576 {
577 HRESULT hr;
578 WCHAR wszPath[MAX_PATH], wszName[MAX_PATH];
579
580 /* Get folder path */
581 hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
582 if (FAILED_UNEXPECTEDLY(hr))
583 return hr;
584
585 if (pItem == m_pLinkItem)
586 {
587 NewItemByNonCommand(pItem, wszName, _countof(wszName), wszPath);
588 NewItemByCommand(pItem, wszName);
589 return S_OK;
590 }
591
592 switch (pItem->Type)
593 {
594 case SHELLNEW_TYPE_COMMAND:
595 NewItemByCommand(pItem, wszPath);
596 break;
597
598 case SHELLNEW_TYPE_DATA:
599 case SHELLNEW_TYPE_FILENAME:
600 case SHELLNEW_TYPE_NULLFILE:
601 NewItemByNonCommand(pItem, wszName, _countof(wszName), wszPath);
602 break;
603
604 case SHELLNEW_TYPE_INVALID:
605 ERR("Invalid type\n");
606 break;
607 }
608
609 return S_OK;
610 }
611
612 HRESULT STDMETHODCALLTYPE CNewMenu::SetSite(IUnknown *pUnkSite)
613 {
614 m_pSite = pUnkSite;
615 return S_OK;
616 }
617
618 HRESULT STDMETHODCALLTYPE CNewMenu::GetSite(REFIID riid, void **ppvSite)
619 {
620 return m_pSite->QueryInterface(riid, ppvSite);
621 }
622
623 HRESULT
624 WINAPI
625 CNewMenu::QueryContextMenu(HMENU hMenu,
626 UINT indexMenu,
627 UINT idCmdFirst,
628 UINT idCmdLast,
629 UINT uFlags)
630 {
631 MENUITEMINFOW mii;
632 UINT cItems = 0;
633 WCHAR wszNew[200];
634
635 TRACE("%p %p %u %u %u %u\n", this,
636 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
637
638 if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszNew, _countof(wszNew)))
639 return E_FAIL;
640
641 m_hSubMenu = CreateMenu();
642 if (!m_hSubMenu)
643 return E_FAIL;
644
645 cItems = InsertShellNewItems(m_hSubMenu, idCmdFirst, 0);
646
647 ZeroMemory(&mii, sizeof(mii));
648 mii.cbSize = sizeof(mii);
649 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU;
650 mii.fType = MFT_STRING;
651 mii.wID = -1;
652 mii.dwTypeData = wszNew;
653 mii.cch = wcslen(mii.dwTypeData);
654 mii.fState = MFS_ENABLED;
655 mii.hSubMenu = m_hSubMenu;
656
657 if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
658 return E_FAIL;
659
660 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cItems);
661 }
662
663 HRESULT
664 WINAPI
665 CNewMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
666 {
667 HRESULT hr = E_FAIL;
668
669 if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdFolder)
670 {
671 hr = CreateNewFolder(lpici);
672 }
673 else
674 {
675 SHELLNEW_ITEM *pItem = FindItemFromIdOffset(LOWORD(lpici->lpVerb));
676 if (pItem)
677 hr = CreateNewItem(pItem, lpici);
678 }
679
680 TRACE("CNewMenu::InvokeCommand %x\n", hr);
681 return hr;
682 }
683
684 HRESULT
685 WINAPI
686 CNewMenu::GetCommandString(UINT_PTR idCmd,
687 UINT uType,
688 UINT *pwReserved,
689 LPSTR pszName,
690 UINT cchMax)
691 {
692 FIXME("%p %lu %u %p %p %u\n", this,
693 idCmd, uType, pwReserved, pszName, cchMax );
694
695 return E_NOTIMPL;
696 }
697
698 HRESULT
699 WINAPI
700 CNewMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
701 {
702 return S_OK;
703 }
704
705 HRESULT
706 WINAPI
707 CNewMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult)
708 {
709 switch (uMsg)
710 {
711 case WM_MEASUREITEM:
712 {
713 MEASUREITEMSTRUCT* lpmis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam);
714 if (!lpmis || lpmis->CtlType != ODT_MENU)
715 break;
716
717 if (lpmis->itemWidth < (UINT)GetSystemMetrics(SM_CXMENUCHECK))
718 lpmis->itemWidth = GetSystemMetrics(SM_CXMENUCHECK);
719 if (lpmis->itemHeight < 16)
720 lpmis->itemHeight = 16;
721
722 if (plResult)
723 *plResult = TRUE;
724 break;
725 }
726 case WM_DRAWITEM:
727 {
728 DRAWITEMSTRUCT* lpdis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
729 if (!lpdis || lpdis->CtlType != ODT_MENU)
730 break;
731
732 DWORD id = LOWORD(lpdis->itemID);
733 HICON hIcon = NULL;
734 if (m_idCmdFirst + id == m_idCmdFolder)
735 {
736 hIcon = m_hIconFolder;
737 }
738 else if (m_idCmdFirst + id == m_idCmdLink)
739 {
740 hIcon = m_hIconLink;
741 }
742 else
743 {
744 SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id);
745 if (pItem)
746 hIcon = pItem->hIcon;
747 }
748
749 if (!hIcon)
750 break;
751
752 DrawIconEx(lpdis->hDC,
753 2,
754 lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - 16) / 2,
755 hIcon,
756 16,
757 16,
758 0, NULL, DI_NORMAL);
759
760 if(plResult)
761 *plResult = TRUE;
762 }
763 }
764
765 return S_OK;
766 }
767
768 HRESULT WINAPI
769 CNewMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder,
770 IDataObject *pdtobj, HKEY hkeyProgID)
771 {
772 m_pidlFolder = ILClone(pidlFolder);
773
774 /* Load folder and shortcut icons */
775 m_hIconFolder = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, 16, 16, LR_SHARED);
776 m_hIconLink = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), IMAGE_ICON, 16, 16, LR_SHARED);
777 return S_OK;
778 }