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