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