[SHELL32]
[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 {
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(LPCMINVOKECOMMANDINFO lpici, 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 /* FIXME: I think that this can be implemented using callbacks to the shell folder */
419
420 /* Note: CWM_GETISHELLBROWSER returns shell browser without adding reference */
421 lpSB = (LPSHELLBROWSER)SendMessageA(lpici->hwnd, CWM_GETISHELLBROWSER, 0, 0);
422 if (!lpSB)
423 return E_FAIL;
424
425 hr = lpSB->QueryActiveShellView(&lpSV);
426 if (FAILED(hr))
427 return hr;
428
429 /* Attempt to get the pidl of the new item */
430 hr = SHILCreateFromPathW(pszName, &pidl, NULL);
431 if (FAILED_UNEXPECTEDLY(hr))
432 return hr;
433
434 pidlNewItem = ILFindLastID(pidl);
435
436 hr = lpSV->SelectItem(pidlNewItem, SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE |
437 SVSI_FOCUSED | SVSI_SELECT);
438
439 SHFree(pidl);
440
441 return hr;
442 }
443
444 // Code is duplicated in CDefaultContextMenu
445 HRESULT CNewMenu::CreateNewFolder(LPCMINVOKECOMMANDINFO lpici)
446 {
447 WCHAR wszPath[MAX_PATH];
448 WCHAR wszName[MAX_PATH];
449 WCHAR wszNewFolder[25];
450 HRESULT hr;
451
452 /* Get folder path */
453 hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
454 if (FAILED_UNEXPECTEDLY(hr))
455 return hr;
456
457 if (!LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder)))
458 return E_FAIL;
459
460 /* Create the name of the new directory */
461 if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFolder))
462 return E_FAIL;
463
464 /* Create the new directory and show the appropriate dialog in case of error */
465 if (SHCreateDirectory(lpici->hwnd, wszName) != ERROR_SUCCESS)
466 return E_FAIL;
467
468 /* Show and select the new item in the def view */
469 SelectNewItem(lpici, SHCNE_MKDIR, SHCNF_PATHW, wszName);
470
471 return S_OK;
472 }
473
474 HRESULT CNewMenu::CreateNewItem(SHELLNEW_ITEM *pItem, LPCMINVOKECOMMANDINFO lpcmi)
475 {
476 WCHAR wszBuf[MAX_PATH];
477 WCHAR wszPath[MAX_PATH];
478 HRESULT hr;
479
480 /* Get folder path */
481 hr = SHGetPathFromIDListW(m_pidlFolder, wszPath);
482 if (FAILED_UNEXPECTEDLY(hr))
483 return hr;
484
485 switch (pItem->Type)
486 {
487 case SHELLNEW_TYPE_COMMAND:
488 {
489 LPWSTR Ptr, pwszCmd;
490 WCHAR wszTemp[MAX_PATH];
491 STARTUPINFOW si;
492 PROCESS_INFORMATION pi;
493
494 if (!ExpandEnvironmentStringsW((LPWSTR)pItem->pData, wszBuf, _countof(wszBuf)))
495 {
496 TRACE("ExpandEnvironmentStrings failed\n");
497 break;
498 }
499
500 /* Expand command parameter, FIXME: there can be more modifiers */
501 Ptr = wcsstr(wszBuf, L"%1");
502 if (Ptr)
503 {
504 Ptr[1] = L's';
505 StringCbPrintfW(wszTemp, sizeof(wszTemp), wszBuf, wszPath);
506 pwszCmd = wszTemp;
507 }
508 else
509 {
510 pwszCmd = wszBuf;
511 }
512
513 /* Create process */
514 ZeroMemory(&si, sizeof(si));
515 si.cb = sizeof(si);
516 if (CreateProcessW(NULL, pwszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
517 {
518 CloseHandle(pi.hProcess);
519 CloseHandle(pi.hThread);
520 }
521 else
522 {
523 ERR("Failed to create process\n");
524 }
525 break;
526 }
527
528 case SHELLNEW_TYPE_DATA:
529 case SHELLNEW_TYPE_FILENAME:
530 case SHELLNEW_TYPE_NULLFILE:
531 {
532 BOOL bSuccess = TRUE;
533 WCHAR wszName[MAX_PATH];
534 WCHAR wszNewFile[MAX_PATH];
535
536 if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszBuf, _countof(wszBuf)))
537 return E_FAIL;
538
539 StringCchPrintfW(wszNewFile, _countof(wszNewFile), L"%s %s%s", wszBuf, pItem->pwszDesc, pItem->pwszExt);
540
541 /* Create the name of the new file */
542 if (!PathYetAnotherMakeUniqueName(wszName, wszPath, NULL, wszNewFile))
543 return E_FAIL;
544
545 /* Create new file */
546 HANDLE hFile = CreateFileW(wszName, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
547 if (hFile != INVALID_HANDLE_VALUE)
548 {
549 if (pItem->Type == SHELLNEW_TYPE_DATA)
550 {
551 /* Write a content */
552 DWORD cbWritten;
553 WriteFile(hFile, pItem->pData, pItem->cbData, &cbWritten, NULL);
554 }
555
556 /* Close file now */
557 CloseHandle(hFile);
558 }
559 else
560 {
561 bSuccess = FALSE;
562 }
563
564 if (pItem->Type == SHELLNEW_TYPE_FILENAME)
565 {
566 /* Copy file */
567 if (!CopyFileW((LPWSTR)pItem->pData, wszName, FALSE))
568 ERR("Copy file failed: %ls\n", (LPWSTR)pItem->pData);
569 }
570
571 /* Show message if we failed */
572 if (bSuccess)
573 {
574 TRACE("Notifying fs %s\n", debugstr_w(wszName));
575 SelectNewItem(lpcmi, SHCNE_CREATE, SHCNF_PATHW, wszName);
576 }
577 else
578 {
579 StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Cannot create file: %s", wszName);
580 MessageBoxW(NULL, wszBuf, L"Cannot create file", MB_OK|MB_ICONERROR); // FIXME load localized error msg
581 }
582 break;
583 }
584
585 case SHELLNEW_TYPE_INVALID:
586 ERR("Invalid type\n");
587 break;
588 }
589
590 return S_OK;
591 }
592
593 HRESULT STDMETHODCALLTYPE CNewMenu::SetSite(IUnknown *pUnkSite)
594 {
595 m_pSite = pUnkSite;
596 return S_OK;
597 }
598
599 HRESULT STDMETHODCALLTYPE CNewMenu::GetSite(REFIID riid, void **ppvSite)
600 {
601 return m_pSite->QueryInterface(riid, ppvSite);
602 }
603
604 HRESULT
605 WINAPI
606 CNewMenu::QueryContextMenu(HMENU hMenu,
607 UINT indexMenu,
608 UINT idCmdFirst,
609 UINT idCmdLast,
610 UINT uFlags)
611 {
612 WCHAR wszNew[200];
613 MENUITEMINFOW mii;
614 UINT cItems = 0;
615
616 TRACE("%p %p %u %u %u %u\n", this,
617 hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
618
619 if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, wszNew, _countof(wszNew)))
620 return E_FAIL;
621
622 m_hSubMenu = CreateMenu();
623 if (!m_hSubMenu)
624 return E_FAIL;
625
626 cItems = InsertShellNewItems(m_hSubMenu, idCmdFirst, 0);
627
628 memset(&mii, 0, sizeof(mii));
629 mii.cbSize = sizeof(mii);
630 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU;
631 mii.fType = MFT_STRING;
632 mii.wID = -1;
633 mii.dwTypeData = wszNew;
634 mii.cch = wcslen(mii.dwTypeData);
635 mii.fState = MFS_ENABLED;
636 mii.hSubMenu = m_hSubMenu;
637
638 if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
639 return E_FAIL;
640
641 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cItems);
642 }
643
644 HRESULT
645 WINAPI
646 CNewMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
647 {
648 HRESULT hr = E_FAIL;
649
650 if (LOWORD(lpici->lpVerb) == 0)
651 hr = CreateNewFolder(lpici);
652 else
653 {
654 SHELLNEW_ITEM *pItem = FindItemFromIdOffset(LOWORD(lpici->lpVerb));
655 if (pItem)
656 hr = CreateNewItem(pItem, lpici);
657 }
658
659 TRACE("CNewMenu::InvokeCommand %x\n", hr);
660 return hr;
661 }
662
663 HRESULT
664 WINAPI
665 CNewMenu::GetCommandString(UINT_PTR idCmd,
666 UINT uType,
667 UINT *pwReserved,
668 LPSTR pszName,
669 UINT cchMax)
670 {
671 FIXME("%p %lu %u %p %p %u\n", this,
672 idCmd, uType, pwReserved, pszName, cchMax );
673
674 return E_NOTIMPL;
675 }
676
677 HRESULT
678 WINAPI
679 CNewMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
680 {
681 return S_OK;
682 }
683
684 HRESULT
685 WINAPI
686 CNewMenu::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult)
687 {
688 switch (uMsg)
689 {
690 case WM_MEASUREITEM:
691 {
692 MEASUREITEMSTRUCT* lpmis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam);
693 if (!lpmis || lpmis->CtlType != ODT_MENU)
694 break;
695
696 if (lpmis->itemWidth < (UINT)GetSystemMetrics(SM_CXMENUCHECK))
697 lpmis->itemWidth = GetSystemMetrics(SM_CXMENUCHECK);
698 if (lpmis->itemHeight < 16)
699 lpmis->itemHeight = 16;
700
701 if (plResult)
702 *plResult = TRUE;
703 break;
704 }
705 case WM_DRAWITEM:
706 {
707 DRAWITEMSTRUCT* lpdis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
708 if (!lpdis || lpdis->CtlType != ODT_MENU)
709 break;
710
711 DWORD id = LOWORD(lpdis->itemID);
712 HICON hIcon = 0;
713 if (id == 0)
714 hIcon = m_hiconFolder;
715 else if (id == 1)
716 hIcon = m_hiconLink;
717 else
718 {
719 SHELLNEW_ITEM *pItem = FindItemFromIdOffset(id);
720 if (pItem)
721 hIcon = pItem->hIcon;
722 }
723
724 if (!hIcon)
725 break;
726
727 DrawIconEx(lpdis->hDC,
728 2,
729 lpdis->rcItem.top + (lpdis->rcItem.bottom - lpdis->rcItem.top - 16) / 2,
730 hIcon,
731 16,
732 16,
733 0, NULL, DI_NORMAL);
734
735 if(plResult)
736 *plResult = TRUE;
737 }
738 }
739
740 return S_OK;
741 }
742
743 HRESULT WINAPI
744 CNewMenu::Initialize(LPCITEMIDLIST pidlFolder,
745 IDataObject *pdtobj, HKEY hkeyProgID)
746 {
747 m_pidlFolder = ILClone(pidlFolder);
748
749 /* Load folder and shortcut icons */
750 m_hiconFolder = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, 16, 16, LR_SHARED);
751 m_hiconLink = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_SHORTCUT), IMAGE_ICON, 16, 16, LR_SHARED);
752 return S_OK;
753 }