ntdll: Use a separate memory allocation for the kernel stack.
[wine.git] / dlls / shell32 / shlview_cmenu.c
blob14cd9aeeebece3c228ca3dc6149f07ddb6ce67a8
1 /*
2 * IContextMenu for items in the shellview
4 * Copyright 1998-2000 Juergen Schmied <juergen.schmied@debitel.net>,
5 * <juergen.schmied@metronet.de>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <string.h>
24 #define COBJMACROS
25 #define NONAMELESSUNION
27 #include "winerror.h"
29 #include "windef.h"
30 #include "wingdi.h"
31 #include "pidl.h"
32 #include "shlobj.h"
33 #include "winreg.h"
34 #include "prsht.h"
36 #include "shell32_main.h"
37 #include "shellfolder.h"
39 #include "shresdef.h"
40 #include "shlwapi.h"
42 #include "wine/heap.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(shell);
47 #define FCIDM_BASE 0x7000
49 typedef struct
51 IContextMenu3 IContextMenu3_iface;
52 IShellExtInit IShellExtInit_iface;
53 IObjectWithSite IObjectWithSite_iface;
54 LONG ref;
56 IShellFolder* parent;
58 /* item menu data */
59 LPITEMIDLIST pidl; /* root pidl */
60 LPITEMIDLIST *apidl; /* array of child pidls */
61 UINT cidl;
62 BOOL allvalues;
64 /* background menu data */
65 BOOL desktop;
66 } ContextMenu;
68 static inline ContextMenu *impl_from_IContextMenu3(IContextMenu3 *iface)
70 return CONTAINING_RECORD(iface, ContextMenu, IContextMenu3_iface);
73 static inline ContextMenu *impl_from_IShellExtInit(IShellExtInit *iface)
75 return CONTAINING_RECORD(iface, ContextMenu, IShellExtInit_iface);
78 static inline ContextMenu *impl_from_IObjectWithSite(IObjectWithSite *iface)
80 return CONTAINING_RECORD(iface, ContextMenu, IObjectWithSite_iface);
83 static HRESULT WINAPI ContextMenu_QueryInterface(IContextMenu3 *iface, REFIID riid, LPVOID *ppvObj)
85 ContextMenu *This = impl_from_IContextMenu3(iface);
87 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObj);
89 *ppvObj = NULL;
91 if (IsEqualIID(riid, &IID_IUnknown) ||
92 IsEqualIID(riid, &IID_IContextMenu) ||
93 IsEqualIID(riid, &IID_IContextMenu2) ||
94 IsEqualIID(riid, &IID_IContextMenu3))
96 *ppvObj = &This->IContextMenu3_iface;
98 else if (IsEqualIID(riid, &IID_IShellExtInit))
100 *ppvObj = &This->IShellExtInit_iface;
102 else if (IsEqualIID(riid, &IID_IObjectWithSite))
104 *ppvObj = &This->IObjectWithSite_iface;
107 if(*ppvObj)
109 IContextMenu3_AddRef(iface);
110 return S_OK;
113 TRACE("-- Interface: E_NOINTERFACE\n");
114 return E_NOINTERFACE;
117 static ULONG WINAPI ContextMenu_AddRef(IContextMenu3 *iface)
119 ContextMenu *This = impl_from_IContextMenu3(iface);
120 ULONG ref = InterlockedIncrement(&This->ref);
121 TRACE("(%p)->(%lu)\n", This, ref);
122 return ref;
125 static ULONG WINAPI ContextMenu_Release(IContextMenu3 *iface)
127 ContextMenu *This = impl_from_IContextMenu3(iface);
128 ULONG ref = InterlockedDecrement(&This->ref);
130 TRACE("(%p)->(%lu)\n", This, ref);
132 if (!ref)
134 if(This->parent)
135 IShellFolder_Release(This->parent);
137 SHFree(This->pidl);
138 _ILFreeaPidl(This->apidl, This->cidl);
140 heap_free(This);
143 return ref;
146 static UINT max_menu_id(HMENU hmenu, UINT offset, UINT last)
148 int i;
149 UINT max_id = 0;
151 for (i = GetMenuItemCount(hmenu) - 1; i >= 0; i--)
153 MENUITEMINFOW item;
154 memset(&item, 0, sizeof(MENUITEMINFOW));
155 item.cbSize = sizeof(MENUITEMINFOW);
156 item.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE;
157 if (!GetMenuItemInfoW(hmenu, i, TRUE, &item))
158 continue;
159 if (!(item.fType & MFT_SEPARATOR))
161 if (item.hSubMenu)
163 UINT submenu_max_id = max_menu_id(item.hSubMenu, offset, last);
164 if (max_id < submenu_max_id)
165 max_id = submenu_max_id;
167 if (item.wID + offset <= last)
169 if (max_id <= item.wID + offset)
170 max_id = item.wID + offset + 1;
174 return max_id;
177 static HRESULT WINAPI ItemMenu_QueryContextMenu(
178 IContextMenu3 *iface,
179 HMENU hmenu,
180 UINT indexMenu,
181 UINT idCmdFirst,
182 UINT idCmdLast,
183 UINT uFlags)
185 ContextMenu *This = impl_from_IContextMenu3(iface);
186 INT uIDMax;
188 TRACE("(%p)->(%p %d 0x%x 0x%x 0x%x )\n", This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
190 if(!(CMF_DEFAULTONLY & uFlags) && This->cidl > 0)
192 HMENU hmenures = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_SHV_FILE));
194 if(uFlags & CMF_EXPLORE)
195 RemoveMenu(hmenures, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
197 Shell_MergeMenus(hmenu, GetSubMenu(hmenures, 0), indexMenu, idCmdFirst - FCIDM_BASE, idCmdLast, MM_SUBMENUSHAVEIDS);
198 uIDMax = max_menu_id(GetSubMenu(hmenures, 0), idCmdFirst - FCIDM_BASE, idCmdLast);
200 DestroyMenu(hmenures);
202 if(This->allvalues)
204 MENUITEMINFOW mi;
205 WCHAR str[255];
206 mi.cbSize = sizeof(mi);
207 mi.fMask = MIIM_ID | MIIM_STRING | MIIM_FTYPE;
208 mi.dwTypeData = str;
209 mi.cch = 255;
210 GetMenuItemInfoW(hmenu, FCIDM_SHVIEW_EXPLORE - FCIDM_BASE + idCmdFirst, MF_BYCOMMAND, &mi);
211 RemoveMenu(hmenu, FCIDM_SHVIEW_EXPLORE - FCIDM_BASE + idCmdFirst, MF_BYCOMMAND);
213 mi.cbSize = sizeof(mi);
214 mi.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_STRING;
215 mi.dwTypeData = str;
216 mi.fState = MFS_ENABLED;
217 mi.wID = FCIDM_SHVIEW_EXPLORE - FCIDM_BASE + idCmdFirst;
218 mi.fType = MFT_STRING;
219 InsertMenuItemW(hmenu, (uFlags & CMF_EXPLORE) ? 1 : 2, MF_BYPOSITION, &mi);
222 SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
224 if(uFlags & ~CMF_CANRENAME)
225 RemoveMenu(hmenu, FCIDM_SHVIEW_RENAME - FCIDM_BASE + idCmdFirst, MF_BYCOMMAND);
226 else
228 UINT enable = MF_BYCOMMAND;
230 /* can't rename more than one item at a time*/
231 if (!This->apidl || This->cidl > 1)
232 enable |= MFS_DISABLED;
233 else
235 DWORD attr = SFGAO_CANRENAME;
237 IShellFolder_GetAttributesOf(This->parent, 1, (LPCITEMIDLIST*)This->apidl, &attr);
238 enable |= (attr & SFGAO_CANRENAME) ? MFS_ENABLED : MFS_DISABLED;
241 EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME - FCIDM_BASE + idCmdFirst, enable);
244 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, uIDMax-idCmdFirst);
246 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
249 /**************************************************************************
250 * DoOpenExplore
252 * for folders only
255 static void DoOpenExplore(ContextMenu *This, HWND hwnd, LPCSTR verb)
257 UINT i;
258 BOOL bFolderFound = FALSE;
259 LPITEMIDLIST pidlFQ;
260 SHELLEXECUTEINFOA sei;
262 /* Find the first item in the list that is not a value. These commands
263 should never be invoked if there isn't at least one folder item in the list.*/
265 for(i = 0; i<This->cidl; i++)
267 if(!_ILIsValue(This->apidl[i]))
269 bFolderFound = TRUE;
270 break;
274 if (!bFolderFound) return;
276 pidlFQ = ILCombine(This->pidl, This->apidl[i]);
278 ZeroMemory(&sei, sizeof(sei));
279 sei.cbSize = sizeof(sei);
280 sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
281 sei.lpIDList = pidlFQ;
282 sei.lpClass = "Folder";
283 sei.hwnd = hwnd;
284 sei.nShow = SW_SHOWNORMAL;
285 sei.lpVerb = verb;
286 ShellExecuteExA(&sei);
287 SHFree(pidlFQ);
290 /**************************************************************************
291 * DoDelete
293 * deletes the currently selected items
295 static void DoDelete(ContextMenu *This)
297 ISFHelper *helper;
299 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
300 if (helper)
302 ISFHelper_DeleteItems(helper, This->cidl, (LPCITEMIDLIST*)This->apidl);
303 ISFHelper_Release(helper);
307 /**************************************************************************
308 * DoCopyOrCut
310 * copies the currently selected items into the clipboard
312 static void DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut)
314 IDataObject *dataobject;
316 TRACE("(%p)->(wnd=%p, cut=%d)\n", This, hwnd, cut);
318 if (SUCCEEDED(IShellFolder_GetUIObjectOf(This->parent, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl, &IID_IDataObject, 0, (void**)&dataobject)))
320 OleSetClipboard(dataobject);
321 IDataObject_Release(dataobject);
325 /**************************************************************************
326 * Properties_AddPropSheetCallback
328 * Used by DoOpenProperties through SHCreatePropSheetExtArrayEx to add
329 * propertysheet pages from shell extensions.
331 static BOOL CALLBACK Properties_AddPropSheetCallback(HPROPSHEETPAGE hpage, LPARAM lparam)
333 LPPROPSHEETHEADERW psh = (LPPROPSHEETHEADERW) lparam;
334 psh->u3.phpage[psh->nPages++] = hpage;
336 return TRUE;
339 static BOOL format_date(FILETIME *time, WCHAR *buffer, DWORD size)
341 FILETIME ft;
342 SYSTEMTIME st;
343 int ret;
345 if (!FileTimeToLocalFileTime(time, &ft))
346 return FALSE;
348 if (!FileTimeToSystemTime(&ft, &st))
349 return FALSE;
351 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buffer, size);
352 if (ret)
354 buffer[ret - 1] = ' ';
355 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buffer + ret , size - ret);
357 return ret != 0;
360 static BOOL get_program_description(WCHAR *path, WCHAR *buffer, DWORD size)
362 WCHAR fileDescW[41], *desc;
363 DWORD versize, *lang;
364 UINT dlen, llen, i;
365 BOOL ret = FALSE;
366 PVOID data;
368 versize = GetFileVersionInfoSizeW(path, NULL);
369 if (!versize) return FALSE;
371 data = heap_alloc(versize);
372 if (!data) return FALSE;
374 if (!GetFileVersionInfoW(path, 0, versize, data))
375 goto out;
377 if (!VerQueryValueW(data, L"\\VarFileInfo\\Translation", (LPVOID *)&lang, &llen))
378 goto out;
380 for (i = 0; i < llen / sizeof(DWORD); i++)
382 swprintf(fileDescW, ARRAY_SIZE(fileDescW), L"\\StringFileInfo\\%04x%04x\\FileDescription",
383 LOWORD(lang[i]), HIWORD(lang[i]));
384 if (VerQueryValueW(data, fileDescW, (LPVOID *)&desc, &dlen))
386 if (dlen > size - 1) dlen = size - 1;
387 memcpy(buffer, desc, dlen * sizeof(WCHAR));
388 buffer[dlen] = 0;
389 ret = TRUE;
390 break;
394 out:
395 heap_free(data);
396 return ret;
399 struct file_properties_info
401 WCHAR path[MAX_PATH];
402 WCHAR dir[MAX_PATH];
403 WCHAR *filename;
404 DWORD attrib;
407 static void init_file_properties_dlg(HWND hwndDlg, struct file_properties_info *props)
409 WCHAR buffer[MAX_PATH], buffer2[MAX_PATH];
410 WIN32_FILE_ATTRIBUTE_DATA exinfo;
411 SHFILEINFOW shinfo;
413 SetDlgItemTextW(hwndDlg, IDC_FPROP_PATH, props->filename);
414 SetDlgItemTextW(hwndDlg, IDC_FPROP_LOCATION, props->dir);
416 if (SHGetFileInfoW(props->path, 0, &shinfo, sizeof(shinfo), SHGFI_TYPENAME|SHGFI_ICON))
418 if (shinfo.hIcon)
420 SendDlgItemMessageW(hwndDlg, IDC_FPROP_ICON, STM_SETICON, (WPARAM)shinfo.hIcon, 0);
421 DestroyIcon(shinfo.hIcon);
423 if (shinfo.szTypeName[0])
424 SetDlgItemTextW(hwndDlg, IDC_FPROP_TYPE, shinfo.szTypeName);
427 if (!GetFileAttributesExW(props->path, GetFileExInfoStandard, &exinfo))
428 return;
430 if (format_date(&exinfo.ftCreationTime, buffer, ARRAY_SIZE(buffer)))
431 SetDlgItemTextW(hwndDlg, IDC_FPROP_CREATED, buffer);
433 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
434 SendDlgItemMessageW(hwndDlg, IDC_FPROP_READONLY, BM_SETCHECK, BST_CHECKED, 0);
435 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
436 SendDlgItemMessageW(hwndDlg, IDC_FPROP_HIDDEN, BM_SETCHECK, BST_CHECKED, 0);
437 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
438 SendDlgItemMessageW(hwndDlg, IDC_FPROP_ARCHIVE, BM_SETCHECK, BST_CHECKED, 0);
440 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
442 SetDlgItemTextW(hwndDlg, IDC_FPROP_SIZE, L"(unknown)");
443 /* TODO: Implement counting for directories */
444 return;
447 /* Information about files only */
448 StrFormatByteSizeW(((LONGLONG)exinfo.nFileSizeHigh << 32) | exinfo.nFileSizeLow,
449 buffer, ARRAY_SIZE(buffer));
450 SetDlgItemTextW(hwndDlg, IDC_FPROP_SIZE, buffer);
452 if (format_date(&exinfo.ftLastWriteTime, buffer, ARRAY_SIZE(buffer)))
453 SetDlgItemTextW(hwndDlg, IDC_FPROP_MODIFIED, buffer);
454 if (format_date(&exinfo.ftLastAccessTime, buffer, ARRAY_SIZE(buffer)))
455 SetDlgItemTextW(hwndDlg, IDC_FPROP_ACCESSED, buffer);
457 if (FindExecutableW(props->path, NULL, buffer) <= (HINSTANCE)32)
458 return;
460 /* Information about executables */
461 if (SHGetFileInfoW(buffer, 0, &shinfo, sizeof(shinfo), SHGFI_ICON | SHGFI_SMALLICON) && shinfo.hIcon)
462 SendDlgItemMessageW(hwndDlg, IDC_FPROP_PROG_ICON, STM_SETICON, (WPARAM)shinfo.hIcon, 0);
464 if (get_program_description(buffer, buffer2, ARRAY_SIZE(buffer2)))
465 SetDlgItemTextW(hwndDlg, IDC_FPROP_PROG_NAME, buffer2);
466 else
468 WCHAR *p = wcsrchr(buffer, '\\');
469 SetDlgItemTextW(hwndDlg, IDC_FPROP_PROG_NAME, p ? ++p : buffer);
473 static INT_PTR CALLBACK file_properties_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
475 switch (uMsg)
477 case WM_INITDIALOG:
479 LPPROPSHEETPAGEW page = (LPPROPSHEETPAGEW)lParam;
480 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)page->lParam);
481 init_file_properties_dlg(hwndDlg, (struct file_properties_info *)page->lParam);
482 break;
485 case WM_COMMAND:
486 if (LOWORD(wParam) == IDC_FPROP_PROG_CHANGE)
488 /* TODO: Implement file association dialog */
489 MessageBoxA(hwndDlg, "Not implemented yet.", "Error", MB_OK | MB_ICONEXCLAMATION);
491 else if (LOWORD(wParam) == IDC_FPROP_READONLY ||
492 LOWORD(wParam) == IDC_FPROP_HIDDEN ||
493 LOWORD(wParam) == IDC_FPROP_ARCHIVE)
495 SendMessageW(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
497 else if (LOWORD(wParam) == IDC_FPROP_PATH && HIWORD(wParam) == EN_CHANGE)
499 SendMessageW(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
501 break;
503 case WM_NOTIFY:
505 LPPSHNOTIFY notify = (LPPSHNOTIFY)lParam;
506 if (notify->hdr.code == PSN_APPLY)
508 struct file_properties_info *props = (struct file_properties_info *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
509 WCHAR newname[MAX_PATH], newpath[MAX_PATH];
510 DWORD attributes;
512 attributes = GetFileAttributesW(props->path);
513 if (attributes != INVALID_FILE_ATTRIBUTES)
515 attributes &= ~(FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE);
517 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_READONLY, BM_GETCHECK, 0, 0) == BST_CHECKED)
518 attributes |= FILE_ATTRIBUTE_READONLY;
519 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_HIDDEN, BM_GETCHECK, 0, 0) == BST_CHECKED)
520 attributes |= FILE_ATTRIBUTE_HIDDEN;
521 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_ARCHIVE, BM_GETCHECK, 0, 0) == BST_CHECKED)
522 attributes |= FILE_ATTRIBUTE_ARCHIVE;
524 if (!SetFileAttributesW(props->path, attributes))
525 ERR("failed to update file attributes of %s\n", debugstr_w(props->path));
528 /* Update filename if it was changed */
529 if (GetDlgItemTextW(hwndDlg, IDC_FPROP_PATH, newname, ARRAY_SIZE(newname)) &&
530 wcscmp(props->filename, newname) &&
531 lstrlenW(props->dir) + lstrlenW(newname) + 2 < ARRAY_SIZE(newpath))
533 lstrcpyW(newpath, props->dir);
534 lstrcatW(newpath, L"\\");
535 lstrcatW(newpath, newname);
537 if (!MoveFileW(props->path, newpath))
538 ERR("failed to move file %s to %s\n", debugstr_w(props->path), debugstr_w(newpath));
539 else
541 WCHAR *p;
542 lstrcpyW(props->path, newpath);
543 lstrcpyW(props->dir, newpath);
544 if ((p = wcsrchr(props->dir, '\\')))
546 *p = 0;
547 props->filename = p + 1;
549 else
550 props->filename = props->dir;
551 SetDlgItemTextW(hwndDlg, IDC_FPROP_LOCATION, props->dir);
555 return TRUE;
558 break;
560 default:
561 break;
563 return FALSE;
566 static UINT CALLBACK file_properties_callback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGEW page)
568 struct file_properties_info *props = (struct file_properties_info *)page->lParam;
569 if (uMsg == PSPCB_RELEASE)
571 heap_free(props);
573 return 1;
576 static void init_file_properties_pages(IDataObject *dataobject, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
578 struct file_properties_info *props;
579 HPROPSHEETPAGE general_page;
580 PROPSHEETPAGEW propsheet;
581 FORMATETC format;
582 STGMEDIUM stgm;
583 HRESULT hr;
584 WCHAR *p;
586 props = heap_alloc(sizeof(*props));
587 if (!props) return;
589 format.cfFormat = CF_HDROP;
590 format.ptd = NULL;
591 format.dwAspect = DVASPECT_CONTENT;
592 format.lindex = -1;
593 format.tymed = TYMED_HGLOBAL;
595 hr = IDataObject_GetData(dataobject, &format, &stgm);
596 if (FAILED(hr)) goto error;
598 if (!DragQueryFileW((HDROP)stgm.u.hGlobal, 0, props->path, ARRAY_SIZE(props->path)))
600 ReleaseStgMedium(&stgm);
601 goto error;
604 ReleaseStgMedium(&stgm);
606 props->attrib = GetFileAttributesW(props->path);
607 if (props->attrib == INVALID_FILE_ATTRIBUTES)
608 goto error;
610 lstrcpyW(props->dir, props->path);
611 if ((p = wcsrchr(props->dir, '\\')))
613 *p = 0;
614 props->filename = p + 1;
616 else
617 props->filename = props->dir;
619 memset(&propsheet, 0, sizeof(propsheet));
620 propsheet.dwSize = sizeof(propsheet);
621 propsheet.dwFlags = PSP_DEFAULT | PSP_USECALLBACK;
622 propsheet.hInstance = shell32_hInstance;
623 if (props->attrib & FILE_ATTRIBUTE_DIRECTORY)
624 propsheet.u.pszTemplate = (LPWSTR)MAKEINTRESOURCE(IDD_FOLDER_PROPERTIES);
625 else
626 propsheet.u.pszTemplate = (LPWSTR)MAKEINTRESOURCE(IDD_FILE_PROPERTIES);
627 propsheet.pfnDlgProc = file_properties_proc;
628 propsheet.pfnCallback = file_properties_callback;
629 propsheet.lParam = (LPARAM)props;
631 general_page = CreatePropertySheetPageW(&propsheet);
632 if (general_page)
633 lpfnAddPage(general_page, lParam);
634 return;
636 error:
637 heap_free(props);
640 #define MAX_PROP_PAGES 99
642 static void DoOpenProperties(ContextMenu *This, HWND hwnd)
644 LPSHELLFOLDER lpDesktopSF;
645 LPSHELLFOLDER lpSF;
646 LPDATAOBJECT lpDo;
647 WCHAR wszFiletype[MAX_PATH];
648 WCHAR wszFilename[MAX_PATH];
649 PROPSHEETHEADERW psh;
650 HPROPSHEETPAGE hpages[MAX_PROP_PAGES];
651 HPSXA hpsxa;
652 UINT ret;
654 TRACE("(%p)->(wnd=%p)\n", This, hwnd);
656 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
657 psh.dwSize = sizeof (PROPSHEETHEADERW);
658 psh.hwndParent = hwnd;
659 psh.dwFlags = PSH_PROPTITLE;
660 psh.nPages = 0;
661 psh.u3.phpage = hpages;
662 psh.u2.nStartPage = 0;
664 _ILSimpleGetTextW(This->apidl[0], (LPVOID)wszFilename, MAX_PATH);
665 psh.pszCaption = (LPCWSTR)wszFilename;
667 /* Find out where to look for the shell extensions */
668 if (_ILIsValue(This->apidl[0]))
670 char sTemp[64];
671 sTemp[0] = 0;
672 if (_ILGetExtension(This->apidl[0], sTemp, 64))
674 HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE);
675 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wszFiletype, MAX_PATH);
677 else
679 wszFiletype[0] = 0;
682 else if (_ILIsFolder(This->apidl[0]))
684 lstrcpynW(wszFiletype, L"Folder", 64);
686 else if (_ILIsSpecialFolder(This->apidl[0]))
688 LPGUID folderGUID;
689 folderGUID = _ILGetGUIDPointer(This->apidl[0]);
690 lstrcpyW(wszFiletype, L"CLSID\\");
691 StringFromGUID2(folderGUID, &wszFiletype[6], MAX_PATH - 6);
693 else
695 FIXME("Requested properties for unknown type.\n");
696 return;
699 /* Get a suitable DataObject for accessing the files */
700 SHGetDesktopFolder(&lpDesktopSF);
701 if (_ILIsPidlSimple(This->pidl))
703 ret = IShellFolder_GetUIObjectOf(lpDesktopSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
704 &IID_IDataObject, NULL, (LPVOID *)&lpDo);
705 IShellFolder_Release(lpDesktopSF);
707 else
709 IShellFolder_BindToObject(lpDesktopSF, This->pidl, NULL, &IID_IShellFolder, (LPVOID*) &lpSF);
710 ret = IShellFolder_GetUIObjectOf(lpSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
711 &IID_IDataObject, NULL, (LPVOID *)&lpDo);
712 IShellFolder_Release(lpSF);
713 IShellFolder_Release(lpDesktopSF);
716 if (SUCCEEDED(ret))
718 init_file_properties_pages(lpDo, Properties_AddPropSheetCallback, (LPARAM)&psh);
720 hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletype, MAX_PROP_PAGES - psh.nPages, lpDo);
721 if (hpsxa != NULL)
723 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
724 SHDestroyPropSheetExtArray(hpsxa);
726 hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, L"*", MAX_PROP_PAGES - psh.nPages, lpDo);
727 if (hpsxa != NULL)
729 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
730 SHDestroyPropSheetExtArray(hpsxa);
732 IDataObject_Release(lpDo);
735 if (psh.nPages)
736 PropertySheetW(&psh);
737 else
738 FIXME("No property pages found.\n");
741 static HRESULT WINAPI ItemMenu_InvokeCommand(
742 IContextMenu3 *iface,
743 LPCMINVOKECOMMANDINFO lpcmi)
745 ContextMenu *This = impl_from_IContextMenu3(iface);
747 if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))
748 FIXME("Is an EX structure\n");
750 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
752 if (IS_INTRESOURCE(lpcmi->lpVerb) && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)
754 TRACE("Invalid Verb %x\n", LOWORD(lpcmi->lpVerb));
755 return E_INVALIDARG;
758 if (IS_INTRESOURCE(lpcmi->lpVerb))
760 switch(LOWORD(lpcmi->lpVerb) + FCIDM_BASE)
762 case FCIDM_SHVIEW_EXPLORE:
763 TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");
764 DoOpenExplore(This, lpcmi->hwnd, "explore");
765 break;
766 case FCIDM_SHVIEW_OPEN:
767 TRACE("Verb FCIDM_SHVIEW_OPEN\n");
768 DoOpenExplore(This, lpcmi->hwnd, "open");
769 break;
770 case FCIDM_SHVIEW_RENAME:
772 IShellBrowser *browser;
774 /* get the active IShellView */
775 browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
776 if (browser)
778 IShellView *view;
780 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
782 TRACE("(shellview=%p)\n", view);
783 IShellView_SelectItem(view, This->apidl[0],
784 SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
785 IShellView_Release(view);
788 break;
790 case FCIDM_SHVIEW_DELETE:
791 TRACE("Verb FCIDM_SHVIEW_DELETE\n");
792 DoDelete(This);
793 break;
794 case FCIDM_SHVIEW_COPY:
795 TRACE("Verb FCIDM_SHVIEW_COPY\n");
796 DoCopyOrCut(This, lpcmi->hwnd, FALSE);
797 break;
798 case FCIDM_SHVIEW_CUT:
799 TRACE("Verb FCIDM_SHVIEW_CUT\n");
800 DoCopyOrCut(This, lpcmi->hwnd, TRUE);
801 break;
802 case FCIDM_SHVIEW_PROPERTIES:
803 TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
804 DoOpenProperties(This, lpcmi->hwnd);
805 break;
806 default:
807 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
808 return E_INVALIDARG;
811 else
813 TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));
814 if (strcmp(lpcmi->lpVerb,"delete")==0)
815 DoDelete(This);
816 else if (strcmp(lpcmi->lpVerb,"copy")==0)
817 DoCopyOrCut(This, lpcmi->hwnd, FALSE);
818 else if (strcmp(lpcmi->lpVerb,"cut")==0)
819 DoCopyOrCut(This, lpcmi->hwnd, TRUE);
820 else if (strcmp(lpcmi->lpVerb,"properties")==0)
821 DoOpenProperties(This, lpcmi->hwnd);
822 else {
823 FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));
824 return E_FAIL;
827 return S_OK;
830 static HRESULT WINAPI ItemMenu_GetCommandString(IContextMenu3 *iface, UINT_PTR cmdid, UINT flags,
831 UINT *reserved, LPSTR name, UINT maxlen)
833 ContextMenu *This = impl_from_IContextMenu3(iface);
834 const WCHAR *cmdW = NULL;
835 HRESULT hr = S_OK;
837 TRACE("(%p)->(%Ix, %#x, %p, %p, %u)\n", This, cmdid, flags, reserved, name, maxlen);
839 switch (flags)
841 case GCS_HELPTEXTA:
842 case GCS_HELPTEXTW:
843 hr = E_NOTIMPL;
844 break;
846 case GCS_VERBA:
847 case GCS_VERBW:
848 switch (cmdid + FCIDM_BASE)
850 case FCIDM_SHVIEW_OPEN:
851 cmdW = L"open";
852 break;
853 case FCIDM_SHVIEW_EXPLORE:
854 cmdW = L"explore";
855 break;
856 case FCIDM_SHVIEW_CUT:
857 cmdW = L"cut";
858 break;
859 case FCIDM_SHVIEW_COPY:
860 cmdW = L"copy";
861 break;
862 case FCIDM_SHVIEW_CREATELINK:
863 cmdW = L"link";
864 break;
865 case FCIDM_SHVIEW_DELETE:
866 cmdW = L"delete";
867 break;
868 case FCIDM_SHVIEW_PROPERTIES:
869 cmdW = L"properties";
870 break;
871 case FCIDM_SHVIEW_RENAME:
872 cmdW = L"rename";
873 break;
876 if (!cmdW)
878 hr = E_INVALIDARG;
879 break;
882 if (flags == GCS_VERBA)
883 WideCharToMultiByte(CP_ACP, 0, cmdW, -1, name, maxlen, NULL, NULL);
884 else
885 lstrcpynW((WCHAR *)name, cmdW, maxlen);
887 TRACE("name %s\n", flags == GCS_VERBA ? debugstr_a(name) : debugstr_w((WCHAR *)name));
888 break;
890 case GCS_VALIDATEA:
891 case GCS_VALIDATEW:
892 break;
895 return hr;
898 /**************************************************************************
899 * NOTES
900 * should be only in IContextMenu2 and IContextMenu3
901 * is nevertheless called from word95
903 static HRESULT WINAPI ContextMenu_HandleMenuMsg(IContextMenu3 *iface, UINT msg,
904 WPARAM wParam, LPARAM lParam)
906 ContextMenu *This = impl_from_IContextMenu3(iface);
907 FIXME("(%p)->(0x%x 0x%Ix 0x%Ix): stub\n", This, msg, wParam, lParam);
908 return E_NOTIMPL;
911 static HRESULT WINAPI ContextMenu_HandleMenuMsg2(IContextMenu3 *iface, UINT msg,
912 WPARAM wParam, LPARAM lParam, LRESULT *result)
914 ContextMenu *This = impl_from_IContextMenu3(iface);
915 FIXME("(%p)->(0x%x 0x%Ix 0x%Ix %p): stub\n", This, msg, wParam, lParam, result);
916 return E_NOTIMPL;
919 static const IContextMenu3Vtbl ItemContextMenuVtbl =
921 ContextMenu_QueryInterface,
922 ContextMenu_AddRef,
923 ContextMenu_Release,
924 ItemMenu_QueryContextMenu,
925 ItemMenu_InvokeCommand,
926 ItemMenu_GetCommandString,
927 ContextMenu_HandleMenuMsg,
928 ContextMenu_HandleMenuMsg2
931 static HRESULT WINAPI ShellExtInit_QueryInterface(IShellExtInit *iface, REFIID riid, void **obj)
933 ContextMenu *This = impl_from_IShellExtInit(iface);
934 return IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, obj);
937 static ULONG WINAPI ShellExtInit_AddRef(IShellExtInit *iface)
939 ContextMenu *This = impl_from_IShellExtInit(iface);
940 return IContextMenu3_AddRef(&This->IContextMenu3_iface);
943 static ULONG WINAPI ShellExtInit_Release(IShellExtInit *iface)
945 ContextMenu *This = impl_from_IShellExtInit(iface);
946 return IContextMenu3_Release(&This->IContextMenu3_iface);
949 static HRESULT WINAPI ShellExtInit_Initialize(IShellExtInit *iface, LPCITEMIDLIST folder,
950 IDataObject *dataobj, HKEY progidkey)
952 ContextMenu *This = impl_from_IShellExtInit(iface);
954 FIXME("(%p)->(%p %p %p): stub\n", This, folder, dataobj, progidkey);
956 return E_NOTIMPL;
959 static const IShellExtInitVtbl ShellExtInitVtbl =
961 ShellExtInit_QueryInterface,
962 ShellExtInit_AddRef,
963 ShellExtInit_Release,
964 ShellExtInit_Initialize
967 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID riid, void **obj)
969 ContextMenu *This = impl_from_IObjectWithSite(iface);
970 return IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, obj);
973 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
975 ContextMenu *This = impl_from_IObjectWithSite(iface);
976 return IContextMenu3_AddRef(&This->IContextMenu3_iface);
979 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
981 ContextMenu *This = impl_from_IObjectWithSite(iface);
982 return IContextMenu3_Release(&This->IContextMenu3_iface);
985 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *site)
987 ContextMenu *This = impl_from_IObjectWithSite(iface);
989 FIXME("(%p)->(%p): stub\n", This, site);
991 return E_NOTIMPL;
994 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, void **site)
996 ContextMenu *This = impl_from_IObjectWithSite(iface);
998 FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), site);
1000 return E_NOTIMPL;
1003 static const IObjectWithSiteVtbl ObjectWithSiteVtbl =
1005 ObjectWithSite_QueryInterface,
1006 ObjectWithSite_AddRef,
1007 ObjectWithSite_Release,
1008 ObjectWithSite_SetSite,
1009 ObjectWithSite_GetSite,
1012 HRESULT ItemMenu_Constructor(IShellFolder *parent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *apidl, UINT cidl,
1013 REFIID riid, void **pObj)
1015 ContextMenu* This;
1016 HRESULT hr;
1017 UINT i;
1019 This = heap_alloc(sizeof(*This));
1020 if (!This) return E_OUTOFMEMORY;
1022 This->IContextMenu3_iface.lpVtbl = &ItemContextMenuVtbl;
1023 This->IShellExtInit_iface.lpVtbl = &ShellExtInitVtbl;
1024 This->IObjectWithSite_iface.lpVtbl = &ObjectWithSiteVtbl;
1025 This->ref = 1;
1026 This->parent = parent;
1027 if (parent) IShellFolder_AddRef(parent);
1029 This->pidl = ILClone(pidl);
1030 This->apidl = _ILCopyaPidl(apidl, cidl);
1031 This->cidl = cidl;
1032 This->allvalues = TRUE;
1034 This->desktop = FALSE;
1036 for (i = 0; i < cidl; i++)
1037 This->allvalues &= (_ILIsValue(apidl[i]) ? 1 : 0);
1039 hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
1040 IContextMenu3_Release(&This->IContextMenu3_iface);
1042 return hr;
1045 /* Background menu implementation */
1046 static HRESULT WINAPI BackgroundMenu_QueryContextMenu(
1047 IContextMenu3 *iface,
1048 HMENU hMenu,
1049 UINT indexMenu,
1050 UINT idCmdFirst,
1051 UINT idCmdLast,
1052 UINT uFlags)
1054 ContextMenu *This = impl_from_IContextMenu3(iface);
1055 HMENU hMyMenu;
1056 UINT idMax;
1057 HRESULT hr;
1059 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
1060 This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
1062 hMyMenu = LoadMenuA(shell32_hInstance, "MENU_002");
1063 if (uFlags & CMF_DEFAULTONLY)
1065 HMENU ourMenu = GetSubMenu(hMyMenu,0);
1066 UINT oldDef = GetMenuDefaultItem(hMenu,TRUE,GMDI_USEDISABLED);
1067 UINT newDef = GetMenuDefaultItem(ourMenu,TRUE,GMDI_USEDISABLED);
1068 if (newDef != oldDef)
1069 SetMenuDefaultItem(hMenu,newDef,TRUE);
1070 if (newDef!=0xFFFFFFFF)
1071 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, newDef+1);
1072 else
1073 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
1075 else
1077 Shell_MergeMenus (hMenu, GetSubMenu(hMyMenu,0), indexMenu,
1078 idCmdFirst - FCIDM_BASE, idCmdLast, MM_SUBMENUSHAVEIDS);
1079 idMax = max_menu_id(GetSubMenu(hMyMenu, 0), idCmdFirst - FCIDM_BASE, idCmdLast);
1080 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst);
1082 DestroyMenu(hMyMenu);
1084 TRACE("(%p)->returning 0x%lx\n",This,hr);
1085 return hr;
1088 static void DoNewFolder(ContextMenu *This, IShellView *view)
1090 ISFHelper *helper;
1092 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
1093 if (helper)
1095 WCHAR nameW[MAX_PATH];
1096 LPITEMIDLIST pidl;
1098 ISFHelper_GetUniqueName(helper, nameW, MAX_PATH);
1099 ISFHelper_AddFolder(helper, 0, nameW, &pidl);
1101 if (view)
1103 /* if we are in a shellview do labeledit */
1104 IShellView_SelectItem(view,
1105 pidl,(SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE
1106 |SVSI_FOCUSED|SVSI_SELECT));
1109 SHFree(pidl);
1110 ISFHelper_Release(helper);
1114 static HRESULT paste_pidls(ContextMenu *This, ITEMIDLIST **pidls, UINT count)
1116 IShellFolder *psfDesktop;
1117 UINT i;
1118 HRESULT hr = S_OK;
1120 /* bind to the source shellfolder */
1121 hr = SHGetDesktopFolder(&psfDesktop);
1122 if (FAILED(hr))
1123 return hr;
1125 for (i = 0; SUCCEEDED(hr) && i < count; i++) {
1126 ITEMIDLIST *pidl_dir = NULL;
1127 ITEMIDLIST *pidl_item;
1128 IShellFolder *psfFrom = NULL;
1130 pidl_dir = ILClone(pidls[i]);
1131 ILRemoveLastID(pidl_dir);
1132 pidl_item = ILFindLastID(pidls[i]);
1133 hr = IShellFolder_BindToObject(psfDesktop, pidl_dir, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom);
1135 if (psfFrom)
1137 /* get source and destination shellfolder */
1138 ISFHelper *psfhlpdst = NULL, *psfhlpsrc = NULL;
1139 hr = IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&psfhlpdst);
1140 if (SUCCEEDED(hr))
1141 hr = IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (void**)&psfhlpsrc);
1143 /* do the copy/move */
1144 if (psfhlpdst && psfhlpsrc)
1146 hr = ISFHelper_CopyItems(psfhlpdst, psfFrom, 1, (LPCITEMIDLIST*)&pidl_item);
1147 /* FIXME handle move
1148 ISFHelper_DeleteItems(psfhlpsrc, 1, &pidl_item);
1151 if(psfhlpdst) ISFHelper_Release(psfhlpdst);
1152 if(psfhlpsrc) ISFHelper_Release(psfhlpsrc);
1153 IShellFolder_Release(psfFrom);
1155 SHFree(pidl_dir);
1158 IShellFolder_Release(psfDesktop);
1159 return hr;
1162 static HRESULT DoPaste(ContextMenu *This)
1164 IDataObject * pda;
1165 HRESULT hr;
1167 TRACE("\n");
1169 hr = OleGetClipboard(&pda);
1170 if(SUCCEEDED(hr))
1172 STGMEDIUM medium;
1173 FORMATETC formatetc;
1174 HRESULT format_hr;
1176 TRACE("pda=%p\n", pda);
1178 /* Set the FORMATETC structure*/
1179 InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL);
1181 /* Get the pidls from IDataObject */
1182 format_hr = IDataObject_GetData(pda,&formatetc,&medium);
1183 if(SUCCEEDED(format_hr))
1185 LPITEMIDLIST * apidl;
1186 LPITEMIDLIST pidl;
1188 LPIDA lpcida = GlobalLock(medium.u.hGlobal);
1189 TRACE("cida=%p\n", lpcida);
1190 if(lpcida)
1192 apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
1193 if (apidl)
1195 hr = paste_pidls(This, apidl, lpcida->cidl);
1196 _ILFreeaPidl(apidl, lpcida->cidl);
1197 SHFree(pidl);
1199 else
1200 hr = HRESULT_FROM_WIN32(GetLastError());
1201 GlobalUnlock(medium.u.hGlobal);
1203 else
1204 hr = HRESULT_FROM_WIN32(GetLastError());
1205 ReleaseStgMedium(&medium);
1208 if(FAILED(format_hr))
1210 InitFormatEtc(formatetc, CF_HDROP, TYMED_HGLOBAL);
1211 format_hr = IDataObject_GetData(pda,&formatetc,&medium);
1212 if(SUCCEEDED(format_hr))
1214 WCHAR path[MAX_PATH];
1215 UINT i, count;
1216 ITEMIDLIST **pidls;
1218 TRACE("CF_HDROP=%p\n", medium.u.hGlobal);
1219 count = DragQueryFileW(medium.u.hGlobal, -1, NULL, 0);
1220 pidls = SHAlloc(count*sizeof(ITEMIDLIST*));
1221 if (pidls)
1223 for (i = 0; i < count; i++)
1225 DragQueryFileW(medium.u.hGlobal, i, path, ARRAY_SIZE(path));
1226 if ((pidls[i] = ILCreateFromPathW(path)) == NULL)
1228 hr = E_FAIL;
1229 break;
1232 if (SUCCEEDED(hr))
1233 hr = paste_pidls(This, pidls, count);
1234 _ILFreeaPidl(pidls, count);
1236 else
1237 hr = HRESULT_FROM_WIN32(GetLastError());
1238 ReleaseStgMedium(&medium);
1242 if (FAILED(format_hr))
1244 ERR("there are no supported and retrievable clipboard formats\n");
1245 hr = format_hr;
1248 IDataObject_Release(pda);
1250 #if 0
1251 HGLOBAL hMem;
1253 OpenClipboard(NULL);
1254 hMem = GetClipboardData(CF_HDROP);
1256 if(hMem)
1258 char * pDropFiles = GlobalLock(hMem);
1259 if(pDropFiles)
1261 int len, offset = sizeof(DROPFILESTRUCT);
1263 while( pDropFiles[offset] != 0)
1265 len = strlen(pDropFiles + offset);
1266 TRACE("%s\n", pDropFiles + offset);
1267 offset += len+1;
1270 GlobalUnlock(hMem);
1272 CloseClipboard();
1273 #endif
1274 return hr;
1277 static HRESULT WINAPI BackgroundMenu_InvokeCommand(
1278 IContextMenu3 *iface,
1279 LPCMINVOKECOMMANDINFO lpcmi)
1281 ContextMenu *This = impl_from_IContextMenu3(iface);
1282 IShellBrowser *browser;
1283 IShellView *view = NULL;
1284 HWND hWnd = NULL;
1286 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", This, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
1288 /* get the active IShellView */
1289 if ((browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0)))
1291 if (SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
1292 IShellView_GetWindow(view, &hWnd);
1295 if(HIWORD(lpcmi->lpVerb))
1297 TRACE("%s\n", debugstr_a(lpcmi->lpVerb));
1299 if (!strcmp(lpcmi->lpVerb, CMDSTR_NEWFOLDERA))
1301 DoNewFolder(This, view);
1303 else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWLISTA))
1305 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_LISTVIEW, 0), 0);
1307 else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWDETAILSA))
1309 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW, 0), 0);
1311 else if (!strcmp(lpcmi->lpVerb, "paste"))
1313 DoPaste(This);
1315 else
1317 FIXME("please report: unknown verb %s\n", debugstr_a(lpcmi->lpVerb));
1320 else
1322 switch (LOWORD(lpcmi->lpVerb) + FCIDM_BASE)
1324 case FCIDM_SHVIEW_REFRESH:
1325 if (view) IShellView_Refresh(view);
1326 break;
1328 case FCIDM_SHVIEW_NEWFOLDER:
1329 DoNewFolder(This, view);
1330 break;
1332 case FCIDM_SHVIEW_INSERT:
1333 DoPaste(This);
1334 break;
1336 case FCIDM_SHVIEW_PROPERTIES:
1337 if (This->desktop) {
1338 ShellExecuteA(lpcmi->hwnd, "open", "rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL);
1339 } else {
1340 FIXME("launch item properties dialog\n");
1342 break;
1344 default:
1345 /* if it's an id just pass it to the parent shv */
1346 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
1347 break;
1351 if (view)
1352 IShellView_Release(view);
1354 return S_OK;
1357 static HRESULT WINAPI BackgroundMenu_GetCommandString(
1358 IContextMenu3 *iface,
1359 UINT_PTR idCommand,
1360 UINT uFlags,
1361 UINT* lpReserved,
1362 LPSTR lpszName,
1363 UINT uMaxNameLen)
1365 ContextMenu *This = impl_from_IContextMenu3(iface);
1366 const WCHAR *cmdW = NULL;
1367 HRESULT hr = E_FAIL;
1369 TRACE("(%p)->(idcom=%Ix flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
1371 switch (uFlags)
1373 case GCS_HELPTEXTA:
1374 case GCS_HELPTEXTW:
1375 hr = E_NOTIMPL;
1376 break;
1378 case GCS_VERBA:
1379 case GCS_VERBW:
1380 switch (idCommand + FCIDM_BASE)
1382 case FCIDM_SHVIEW_INSERT:
1383 cmdW = L"paste";
1384 break;
1385 case FCIDM_SHVIEW_PROPERTIES:
1386 cmdW = L"properties";
1387 break;
1390 if (!cmdW)
1392 hr = E_INVALIDARG;
1393 break;
1396 if (uFlags == GCS_VERBA)
1397 WideCharToMultiByte(CP_ACP, 0, cmdW, -1, lpszName, uMaxNameLen, NULL, NULL);
1398 else
1399 lstrcpynW((WCHAR *)lpszName, cmdW, uMaxNameLen);
1400 TRACE("name %s\n", uFlags == GCS_VERBA ? debugstr_a(lpszName) : debugstr_w((WCHAR *)lpszName));
1401 hr = S_OK;
1402 break;
1404 case GCS_VALIDATEA:
1405 case GCS_VALIDATEW:
1406 /* test the existence of the menu items, the file dialog enables
1407 the buttons according to this */
1408 if (HIWORD(idCommand))
1410 if (!strcmp((LPSTR)idCommand, CMDSTR_VIEWLISTA) ||
1411 !strcmp((LPSTR)idCommand, CMDSTR_VIEWDETAILSA) ||
1412 !strcmp((LPSTR)idCommand, CMDSTR_NEWFOLDERA))
1413 hr = S_OK;
1414 else
1416 FIXME("unknown command string %s\n", uFlags == GCS_VALIDATEA ? debugstr_a((LPSTR)idCommand) : debugstr_w((WCHAR*)idCommand));
1417 hr = E_FAIL;
1420 break;
1422 return hr;
1425 static const IContextMenu3Vtbl BackgroundContextMenuVtbl =
1427 ContextMenu_QueryInterface,
1428 ContextMenu_AddRef,
1429 ContextMenu_Release,
1430 BackgroundMenu_QueryContextMenu,
1431 BackgroundMenu_InvokeCommand,
1432 BackgroundMenu_GetCommandString,
1433 ContextMenu_HandleMenuMsg,
1434 ContextMenu_HandleMenuMsg2
1437 HRESULT BackgroundMenu_Constructor(IShellFolder *parent, BOOL desktop, REFIID riid, void **pObj)
1439 ContextMenu *This;
1440 HRESULT hr;
1442 This = heap_alloc(sizeof(*This));
1443 if (!This) return E_OUTOFMEMORY;
1445 This->IContextMenu3_iface.lpVtbl = &BackgroundContextMenuVtbl;
1446 This->IShellExtInit_iface.lpVtbl = &ShellExtInitVtbl;
1447 This->IObjectWithSite_iface.lpVtbl = &ObjectWithSiteVtbl;
1448 This->ref = 1;
1449 This->parent = parent;
1451 This->pidl = NULL;
1452 This->apidl = NULL;
1453 This->cidl = 0;
1454 This->allvalues = FALSE;
1456 This->desktop = desktop;
1457 if (parent) IShellFolder_AddRef(parent);
1459 hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
1460 IContextMenu3_Release(&This->IContextMenu3_iface);
1462 return hr;