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