xref: /reactos/dll/win32/shell32/CNewMenu.cpp (revision c7bba39a)
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  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include "precomp.h"
24 
25 WINE_DEFAULT_DEBUG_CHANNEL(shell);
26 
27 CNewMenu::CNewMenu() :
28     m_pidlFolder(NULL),
29     m_wszPath(NULL),
30     m_pItems(NULL),
31     m_pLinkItem(NULL),
32     m_pSite(NULL),
33     m_hiconFolder(NULL),
34     m_hiconLink(NULL)
35 {
36 }
37 
38 CNewMenu::~CNewMenu()
39 {
40     UnloadAllItems();
41 
42     if (m_pidlFolder)
43         ILFree(m_pidlFolder);
44 }
45 
46 void CNewMenu::UnloadItem(SHELLNEW_ITEM *pItem)
47 {
48     /* Note: free allows NULL as argument */
49     free(pItem->pData);
50     free(pItem->pwszDesc);
51     free(pItem->pwszExt);
52 
53     if (pItem->hIcon)
54         DestroyIcon(pItem->hIcon);
55 
56     HeapFree(GetProcessHeap(), 0, pItem);
57 }
58 
59 void CNewMenu::UnloadAllItems()
60 {
61     SHELLNEW_ITEM *pCurItem;
62 
63     /* Unload normal items */
64     while (m_pItems)
65     {
66         pCurItem = m_pItems;
67         m_pItems = m_pItems->pNext;
68 
69         UnloadItem(pCurItem);
70     }
71 
72     /* Unload link item */
73     if (m_pLinkItem)
74         UnloadItem(m_pLinkItem);
75     m_pLinkItem = NULL;
76 }
77 
78 CNewMenu::SHELLNEW_ITEM *CNewMenu::LoadItem(LPCWSTR pwszExt)
79 {
80     HKEY hKey;
81     WCHAR wszBuf[MAX_PATH];
82     BYTE *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 = (BYTE*)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         return NULL;
139 
140     SHFILEINFOW fi;
141     if (!SHGetFileInfoW(pwszExt, FILE_ATTRIBUTE_NORMAL, &fi, sizeof(fi), SHGFI_USEFILEATTRIBUTES|SHGFI_TYPENAME|SHGFI_ICON|SHGFI_SMALLICON))
142         return NULL;
143 
144     /* Create new item */
145     SHELLNEW_ITEM *pNewItem = static_cast<SHELLNEW_ITEM *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SHELLNEW_ITEM)));
146     if (!pNewItem)
147     {
148         free(pData);
149         return NULL;
150     }
151 
152     TRACE("new item %ls\n", fi.szTypeName);
153     pNewItem->Type = Types[i].Type;
154     pNewItem->pData = pData;
155     pNewItem->cbData = pData ? cbData : 0;
156     pNewItem->pwszExt = _wcsdup(pwszExt);
157     pNewItem->pwszDesc = _wcsdup(fi.szTypeName);
158     if (fi.hIcon)
159         pNewItem->hIcon = fi.hIcon;
160 
161     return pNewItem;
162 }
163 
164 BOOL
165 CNewMenu::CacheItems()
166 {
167     HKEY hKey;
168     DWORD dwSize = 0;
169     DWORD dwIndex = 0;
170     LPWSTR lpValue;
171     LPWSTR lpValues;
172     WCHAR wszName[MAX_PATH];
173     SHELLNEW_ITEM *pNewItem;
174     SHELLNEW_ITEM *pCurItem = NULL;
175 
176     /* Enumerate all extensions */
177     while (RegEnumKeyW(HKEY_CLASSES_ROOT, dwIndex++, wszName, _countof(wszName)) == ERROR_SUCCESS)
178     {
179         if (wszName[0] != L'.')
180             continue;
181 
182         pNewItem = LoadItem(wszName);
183         if (pNewItem)
184         {
185             dwSize += wcslen(wszName) + 1;
186             if (wcsicmp(pNewItem->pwszExt, L".lnk") == 0)
187             {
188                 /* Link handler */
189                 m_pLinkItem = pNewItem;
190             }
191             else
192             {
193                 /* Add at the end of list */
194                 if (pCurItem)
195                 {
196                     pCurItem->pNext = pNewItem;
197                     pCurItem = pNewItem;
198                 }
199                 else
200                     pCurItem = m_pItems = pNewItem;
201             }
202         }
203     }
204 
205     dwSize++;
206 
207     lpValues = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize * sizeof(WCHAR));
208     if (!lpValues)
209         return FALSE;
210 
211     lpValue = lpValues;
212     pCurItem = m_pItems;
213     while (pCurItem)
214     {
215         memcpy(lpValue, pCurItem->pwszExt, (wcslen(pCurItem->pwszExt) + 1) * sizeof(WCHAR));
216         lpValue += wcslen(pCurItem->pwszExt) + 1;
217         pCurItem = pCurItem->pNext;
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 (; '\0' != *wszName; wszName += wcslen(wszName) + 1)
268     {
269         pNewItem = LoadItem(wszName);
270         if (pNewItem)
271         {
272             if (wcsicmp(pNewItem->pwszExt, L".lnk") == 0)
273             {
274                 /* Link handler */
275                 m_pLinkItem = pNewItem;
276             }
277             else
278             {
279                 /* Add at the end of list */
280                 if (pCurItem)
281                 {
282                     pCurItem->pNext = pNewItem;
283                     pCurItem = pNewItem;
284                 }
285                 else
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     if (!m_pLinkItem)
309     {
310         m_pLinkItem = static_cast<SHELLNEW_ITEM *>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SHELLNEW_ITEM)));
311         if (m_pLinkItem)
312         {
313             m_pLinkItem->Type = SHELLNEW_TYPE_NULLFILE;
314             m_pLinkItem->pwszDesc = _wcsdup(L"Link");
315             m_pLinkItem->pwszExt = _wcsdup(L".lnk");
316         }
317     }
318 
319     if (m_pItems == NULL)
320         return FALSE;
321     else
322         return TRUE;
323 }
324 
325 UINT
326 CNewMenu::InsertShellNewItems(HMENU hMenu, UINT idCmdFirst, UINT Pos)
327 {
328     MENUITEMINFOW mii;
329     WCHAR wszBuf[256];
330     UINT idCmd = idCmdFirst;
331 
332     if (m_pItems == NULL)
333     {
334         if (!LoadAllItems())
335             return 0;
336     }
337 
338     ZeroMemory(&mii, sizeof(mii));
339     mii.cbSize = sizeof(mii);
340 
341     /* Insert new folder action */
342     if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWFOLDER, wszBuf, _countof(wszBuf)))
343         wszBuf[0] = 0;
344     mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_STRING;
345     mii.dwTypeData = wszBuf;
346     mii.cch = wcslen(mii.dwTypeData);
347     mii.wID = idCmd;
348     mii.hbmpItem = HBMMENU_CALLBACK;
349     if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii))
350         ++idCmd;
351 
352     /* Insert new shortcut action */
353     if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWLINK, wszBuf, _countof(wszBuf)))
354         wszBuf[0] = 0;
355     mii.dwTypeData = wszBuf;
356     mii.cch = wcslen(mii.dwTypeData);
357     mii.wID = idCmd;
358     if (InsertMenuItemW(hMenu, Pos++, TRUE, &mii))
359         ++idCmd;
360 
361     /* Insert seperator for custom new action */
362     mii.fMask = MIIM_TYPE | MIIM_ID;
363     mii.fType = MFT_SEPARATOR;
364     mii.wID = -1;
365     InsertMenuItemW(hMenu, Pos++, TRUE, &mii);
366 
367     /* Insert rest of items */
368     mii.fMask = MIIM_ID | MIIM_BITMAP | MIIM_STRING;
369     mii.fType = 0;
370 
371     SHELLNEW_ITEM *pCurItem = m_pItems;
372     while (pCurItem)
373     {
374         TRACE("szDesc %s\n", debugstr_w(pCurItem->pwszDesc));
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         pCurItem = pCurItem->pNext;
381     }
382 
383     return idCmd - idCmdFirst;
384 }
385 
386 CNewMenu::SHELLNEW_ITEM *CNewMenu::FindItemFromIdOffset(UINT IdOffset)
387 {
388     if (IdOffset == 0)
389         return NULL; /* Folder */
390 
391     if (IdOffset == 1)
392         return m_pLinkItem; /* shortcut */
393 
394     /* Find shell new item */
395     SHELLNEW_ITEM *pItem = m_pItems;
396     for (UINT i = 2; pItem; ++i)
397     {
398         if (i == IdOffset)
399             break;
400 
401         pItem = pItem->pNext;
402     }
403 
404     return pItem;
405 }
406 
407 HRESULT CNewMenu::SelectNewItem(LONG wEventId, UINT uFlags, LPWSTR pszName)
408 {
409     CComPtr<IShellBrowser> lpSB;
410     CComPtr<IShellView> lpSV;
411     HRESULT hr = E_FAIL;
412     LPITEMIDLIST pidl;
413     PITEMID_CHILD pidlNewItem;
414 
415     /* Notify the view object about the new item */
416     SHChangeNotify(wEventId, uFlags, (LPCVOID) pszName, NULL);
417 
418     if (!m_pSite)
419         return S_OK;
420 
421     /* Get a pointer to the shell view */
422     hr = IUnknown_QueryService(m_pSite, SID_IFolderView, IID_PPV_ARG(IShellView, &lpSV));
423     if (FAILED_UNEXPECTEDLY(hr))
424         return S_OK;
425 
426     /* Attempt to get the pidl of the new item */
427     hr = SHILCreateFromPathW(pszName, &pidl, NULL);
428     if (FAILED_UNEXPECTEDLY(hr))
429         return hr;
430 
431     pidlNewItem = ILFindLastID(pidl);
432 
433     hr = lpSV->SelectItem(pidlNewItem, SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE |
434                                        SVSI_FOCUSED | SVSI_SELECT);
435 
436     SHFree(pidl);
437 
438     return hr;
439 }
440 
441 // Code is duplicated in CDefaultContextMenu
442 HRESULT CNewMenu::CreateNewFolder(LPCMINVOKECOMMANDINFO lpici)
443 {
444     WCHAR wszPath[MAX_PATH];
445     WCHAR wszName[MAX_PATH];
446     WCHAR wszNewFolder[25];
447     HRESULT hr;
448 
449     /* Get folder path */
450     hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
451     if (FAILED_UNEXPECTEDLY(hr))
452         return hr;
453 
454     if (!LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder)))
455         return E_FAIL;
456 
457     /* Create the name of the new directory */
458     if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFolder))
459         return E_FAIL;
460 
461     /* Create the new directory and show the appropriate dialog in case of error */
462     if (SHCreateDirectory(lpici->hwnd, wszName) != ERROR_SUCCESS)
463         return E_FAIL;
464 
465     /* Show and select the new item in the def view */
466     SelectNewItem(SHCNE_MKDIR, SHCNF_PATHW, wszName);
467 
468     return S_OK;
469 }
470 
471 HRESULT CNewMenu::CreateNewItem(SHELLNEW_ITEM *pItem, LPCMINVOKECOMMANDINFO lpcmi)
472 {
473     WCHAR wszBuf[MAX_PATH];
474     WCHAR wszPath[MAX_PATH];
475     HRESULT hr;
476 
477     /* Get folder path */
478     hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
479     if (FAILED_UNEXPECTEDLY(hr))
480         return hr;
481 
482     switch (pItem->Type)
483     {
484         case SHELLNEW_TYPE_COMMAND:
485         {
486             LPWSTR Ptr, pwszCmd;
487             WCHAR wszTemp[MAX_PATH];
488             STARTUPINFOW si;
489             PROCESS_INFORMATION pi;
490 
491             if (!ExpandEnvironmentStringsW((LPWSTR)pItem->pData, wszBuf, _countof(wszBuf)))
492             {
493                 TRACE("ExpandEnvironmentStrings failed\n");
494                 break;
495             }
496 
497             /* Expand command parameter, FIXME: there can be more modifiers */
498             Ptr = wcsstr(wszBuf, L"%1");
499             if (Ptr)
500             {
501                 Ptr[1] = L's';
502                 StringCbPrintfW(wszTemp, sizeof(wszTemp), wszBuf, wszPath);
503                 pwszCmd = wszTemp;
504             }
505             else
506             {
507                 pwszCmd = wszBuf;
508             }
509 
510             /* Create process */
511             ZeroMemory(&si, sizeof(si));
512             si.cb = sizeof(si);
513             if (CreateProcessW(NULL, pwszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
514             {
515                 CloseHandle(pi.hProcess);
516                 CloseHandle(pi.hThread);
517             }
518             else
519             {
520                 ERR("Failed to create process\n");
521             }
522             break;
523         }
524 
525         case SHELLNEW_TYPE_DATA:
526         case SHELLNEW_TYPE_FILENAME:
527         case SHELLNEW_TYPE_NULLFILE:
528         {
529             BOOL bSuccess = TRUE;
530             WCHAR wszName[MAX_PATH];
531             WCHAR wszNewFile[MAX_PATH];
532 
533             if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszBuf, _countof(wszBuf)))
534                 return E_FAIL;
535 
536             StringCchPrintfW(wszNewFile, _countof(wszNewFile), L"%s %s%s", wszBuf, pItem->pwszDesc, pItem->pwszExt);
537 
538             /* Create the name of the new file */
539             if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFile))
540                 return E_FAIL;
541 
542             /* Create new file */
543             HANDLE hFile = CreateFileW(wszName, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
544             if (hFile != INVALID_HANDLE_VALUE)
545             {
546                 if (pItem->Type == SHELLNEW_TYPE_DATA)
547                 {
548                     /* Write a content */
549                     DWORD cbWritten;
550                     WriteFile(hFile, pItem->pData, pItem->cbData, &cbWritten, NULL);
551                 }
552 
553                 /* Close file now */
554                 CloseHandle(hFile);
555             }
556             else
557             {
558                 bSuccess = FALSE;
559             }
560 
561             if (pItem->Type == SHELLNEW_TYPE_FILENAME)
562             {
563                 /* Copy file */
564                 if (!CopyFileW((LPWSTR)pItem->pData, wszName, FALSE))
565                     ERR("Copy file failed: %ls\n", (LPWSTR)pItem->pData);
566             }
567 
568             /* Show message if we failed */
569             if (bSuccess)
570             {
571                 TRACE("Notifying fs %s\n", debugstr_w(wszName));
572                 SelectNewItem(SHCNE_CREATE, SHCNF_PATHW, wszName);
573             }
574             else
575             {
576                 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Cannot create file: %s", wszName);
577                 MessageBoxW(NULL, wszBuf, L"Cannot create file", MB_OK|MB_ICONERROR); // FIXME load localized error msg
578             }
579             break;
580         }
581 
582         case SHELLNEW_TYPE_INVALID:
583             ERR("Invalid type\n");
584             break;
585     }
586 
587     return S_OK;
588 }
589 
590 HRESULT STDMETHODCALLTYPE CNewMenu::SetSite(IUnknown *pUnkSite)
591 {
592     m_pSite = pUnkSite;
593     return S_OK;
594 }
595 
596 HRESULT STDMETHODCALLTYPE CNewMenu::GetSite(REFIID riid, void **ppvSite)
597 {
598     return m_pSite->QueryInterface(riid, ppvSite);
599 }
600 
601 HRESULT
602 WINAPI
603 CNewMenu::QueryContextMenu(HMENU hMenu,
604                            UINT indexMenu,
605                            UINT idCmdFirst,
606                            UINT idCmdLast,
607                            UINT uFlags)
608 {
609     WCHAR wszNew[200];
610     MENUITEMINFOW mii;
611     UINT cItems = 0;
612 
613     TRACE("%p %p %u %u %u %u\n", this,
614           hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
615 
616     if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszNew, _countof(wszNew)))
617         return E_FAIL;
618 
619     m_hSubMenu = CreateMenu();
620     if (!m_hSubMenu)
621         return E_FAIL;
622 
623     cItems = InsertShellNewItems(m_hSubMenu, idCmdFirst, 0);
624 
625     memset(&mii, 0, sizeof(mii));
626     mii.cbSize = sizeof(mii);
627     mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU;
628     mii.fType = MFT_STRING;
629     mii.wID = -1;
630     mii.dwTypeData = wszNew;
631     mii.cch = wcslen(mii.dwTypeData);
632     mii.fState = MFS_ENABLED;
633     mii.hSubMenu = m_hSubMenu;
634 
635     if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
636         return E_FAIL;
637 
638     return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cItems);
639 }
640 
641 HRESULT
642 WINAPI
643 CNewMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
644 {
645     HRESULT hr = E_FAIL;
646 
647     if (LOWORD(lpici->lpVerb) == 0)
648         hr = CreateNewFolder(lpici);
649     else
650     {
651         SHELLNEW_ITEM *pItem = FindItemFromIdOffset(LOWORD(lpici->lpVerb));
652         if (pItem)
653             hr = CreateNewItem(pItem, lpici);
654     }
655 
656     TRACE("CNewMenu::InvokeCommand %x\n", hr);
657     return hr;
658 }
659 
660 HRESULT
661 WINAPI
662 CNewMenu::GetCommandString(UINT_PTR idCmd,
663                            UINT uType,
664                            UINT *pwReserved,
665                            LPSTR pszName,
666                            UINT cchMax)
667 {
668     FIXME("%p %lu %u %p %p %u\n", this,
669           idCmd, uType, pwReserved, pszName, cchMax );
670 
671     return E_NOTIMPL;
672 }
673 
674 HRESULT
675 WINAPI
676 CNewMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
677 {
678     return S_OK;
679 }
680 
681 HRESULT
682 WINAPI
683 CNewMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult)
684 {
685     switch (uMsg)
686     {
687     case WM_MEASUREITEM:
688         {
689             MEASUREITEMSTRUCT* lpmis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam);
690             if (!lpmis || lpmis->CtlType != ODT_MENU)
691                 break;
692 
693             if (lpmis->itemWidth < (UINT)GetSystemMetrics(SM_CXMENUCHECK))
694                 lpmis->itemWidth = GetSystemMetrics(SM_CXMENUCHECK);
695             if (lpmis->itemHeight < 16)
696                 lpmis->itemHeight = 16;
697 
698             if (plResult)
699                 *plResult = TRUE;
700             break;
701         }
702     case WM_DRAWITEM:
703         {
704             DRAWITEMSTRUCT* lpdis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
705             if (!lpdis || lpdis->CtlType != ODT_MENU)
706                 break;
707 
708             DWORD id = LOWORD(lpdis->itemID);
709             HICON hIcon = 0;
710             if (id == 0)
711                 hIcon = m_hiconFolder;
712             else if (id == 1)
713                 hIcon = m_hiconLink;
714             else
715             {
716                 SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id);
717                 if (pItem)
718                     hIcon = pItem->hIcon;
719             }
720 
721             if (!hIcon)
722                 break;
723 
724             DrawIconEx(lpdis->hDC,
725                        2,
726                        lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - 16) / 2,
727                        hIcon,
728                        16,
729                        16,
730                        0, NULL, DI_NORMAL);
731 
732             if(plResult)
733                 *plResult = TRUE;
734         }
735     }
736 
737     return S_OK;
738 }
739 
740 HRESULT WINAPI
741 CNewMenu::Initialize(LPCITEMIDLIST pidlFolder,
742                      IDataObject *pdtobj, HKEY hkeyProgID)
743 {
744     m_pidlFolder = ILClone(pidlFolder);
745 
746     /* Load folder and shortcut icons */
747     m_hiconFolder = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, 16, 16, LR_SHARED);
748     m_hiconLink = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), IMAGE_ICON, 16, 16, LR_SHARED);
749     return S_OK;
750 }
751