dmusic: Avoid swallowing collection Load failures.
[wine.git] / dlls / shell32 / shlview_cmenu.c
blob181ff36787ebb1a04bf80652ed1be86f180ca63d
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 #include "winerror.h"
27 #include "windef.h"
28 #include "wingdi.h"
29 #include "pidl.h"
30 #include "shlobj.h"
31 #include "winreg.h"
32 #include "prsht.h"
34 #include "shell32_main.h"
35 #include "shellfolder.h"
37 #include "shresdef.h"
38 #include "shlwapi.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(shell);
44 #define FCIDM_BASE 0x7000
46 typedef struct
48 IContextMenu3 IContextMenu3_iface;
49 IShellExtInit IShellExtInit_iface;
50 IObjectWithSite IObjectWithSite_iface;
51 LONG ref;
53 IShellFolder* parent;
55 /* item menu data */
56 LPITEMIDLIST pidl; /* root pidl */
57 LPITEMIDLIST *apidl; /* array of child pidls */
58 UINT cidl;
59 BOOL allvalues;
61 /* background menu data */
62 BOOL desktop;
63 } ContextMenu;
65 static inline ContextMenu *impl_from_IContextMenu3(IContextMenu3 *iface)
67 return CONTAINING_RECORD(iface, ContextMenu, IContextMenu3_iface);
70 static inline ContextMenu *impl_from_IShellExtInit(IShellExtInit *iface)
72 return CONTAINING_RECORD(iface, ContextMenu, IShellExtInit_iface);
75 static inline ContextMenu *impl_from_IObjectWithSite(IObjectWithSite *iface)
77 return CONTAINING_RECORD(iface, ContextMenu, IObjectWithSite_iface);
80 static HRESULT WINAPI ContextMenu_QueryInterface(IContextMenu3 *iface, REFIID riid, LPVOID *ppvObj)
82 ContextMenu *This = impl_from_IContextMenu3(iface);
84 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObj);
86 *ppvObj = NULL;
88 if (IsEqualIID(riid, &IID_IUnknown) ||
89 IsEqualIID(riid, &IID_IContextMenu) ||
90 IsEqualIID(riid, &IID_IContextMenu2) ||
91 IsEqualIID(riid, &IID_IContextMenu3))
93 *ppvObj = &This->IContextMenu3_iface;
95 else if (IsEqualIID(riid, &IID_IShellExtInit))
97 *ppvObj = &This->IShellExtInit_iface;
99 else if (IsEqualIID(riid, &IID_IObjectWithSite))
101 *ppvObj = &This->IObjectWithSite_iface;
104 if(*ppvObj)
106 IContextMenu3_AddRef(iface);
107 return S_OK;
110 TRACE("-- Interface: E_NOINTERFACE\n");
111 return E_NOINTERFACE;
114 static ULONG WINAPI ContextMenu_AddRef(IContextMenu3 *iface)
116 ContextMenu *This = impl_from_IContextMenu3(iface);
117 ULONG ref = InterlockedIncrement(&This->ref);
118 TRACE("(%p)->(%lu)\n", This, ref);
119 return ref;
122 static ULONG WINAPI ContextMenu_Release(IContextMenu3 *iface)
124 ContextMenu *This = impl_from_IContextMenu3(iface);
125 ULONG ref = InterlockedDecrement(&This->ref);
127 TRACE("(%p)->(%lu)\n", This, ref);
129 if (!ref)
131 if(This->parent)
132 IShellFolder_Release(This->parent);
134 SHFree(This->pidl);
135 _ILFreeaPidl(This->apidl, This->cidl);
137 free(This);
140 return ref;
143 static UINT max_menu_id(HMENU hmenu, UINT offset, UINT last)
145 int i;
146 UINT max_id = 0;
148 for (i = GetMenuItemCount(hmenu) - 1; i >= 0; i--)
150 MENUITEMINFOW item;
151 memset(&item, 0, sizeof(MENUITEMINFOW));
152 item.cbSize = sizeof(MENUITEMINFOW);
153 item.fMask = MIIM_ID | MIIM_SUBMENU | MIIM_TYPE;
154 if (!GetMenuItemInfoW(hmenu, i, TRUE, &item))
155 continue;
156 if (!(item.fType & MFT_SEPARATOR))
158 if (item.hSubMenu)
160 UINT submenu_max_id = max_menu_id(item.hSubMenu, offset, last);
161 if (max_id < submenu_max_id)
162 max_id = submenu_max_id;
164 if (item.wID + offset <= last)
166 if (max_id <= item.wID + offset)
167 max_id = item.wID + offset + 1;
171 return max_id;
174 static HRESULT WINAPI ItemMenu_QueryContextMenu(
175 IContextMenu3 *iface,
176 HMENU hmenu,
177 UINT indexMenu,
178 UINT idCmdFirst,
179 UINT idCmdLast,
180 UINT uFlags)
182 ContextMenu *This = impl_from_IContextMenu3(iface);
183 INT uIDMax;
185 TRACE("(%p)->(%p %d 0x%x 0x%x 0x%x )\n", This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
187 if(!(CMF_DEFAULTONLY & uFlags) && This->cidl > 0)
189 HMENU hmenures = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_SHV_FILE));
191 if(uFlags & CMF_EXPLORE)
192 RemoveMenu(hmenures, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
194 Shell_MergeMenus(hmenu, GetSubMenu(hmenures, 0), indexMenu, idCmdFirst - FCIDM_BASE, idCmdLast, MM_SUBMENUSHAVEIDS);
195 uIDMax = max_menu_id(GetSubMenu(hmenures, 0), idCmdFirst - FCIDM_BASE, idCmdLast);
197 DestroyMenu(hmenures);
199 if(This->allvalues)
201 MENUITEMINFOW mi;
202 WCHAR str[255];
203 mi.cbSize = sizeof(mi);
204 mi.fMask = MIIM_ID | MIIM_STRING | MIIM_FTYPE;
205 mi.dwTypeData = str;
206 mi.cch = 255;
207 GetMenuItemInfoW(hmenu, FCIDM_SHVIEW_EXPLORE - FCIDM_BASE + idCmdFirst, MF_BYCOMMAND, &mi);
208 RemoveMenu(hmenu, FCIDM_SHVIEW_EXPLORE - FCIDM_BASE + idCmdFirst, MF_BYCOMMAND);
210 mi.cbSize = sizeof(mi);
211 mi.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_STRING;
212 mi.dwTypeData = str;
213 mi.fState = MFS_ENABLED;
214 mi.wID = FCIDM_SHVIEW_EXPLORE - FCIDM_BASE + idCmdFirst;
215 mi.fType = MFT_STRING;
216 InsertMenuItemW(hmenu, (uFlags & CMF_EXPLORE) ? 1 : 2, MF_BYPOSITION, &mi);
219 SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
221 if(uFlags & ~CMF_CANRENAME)
222 RemoveMenu(hmenu, FCIDM_SHVIEW_RENAME - FCIDM_BASE + idCmdFirst, MF_BYCOMMAND);
223 else
225 UINT enable = MF_BYCOMMAND;
227 /* can't rename more than one item at a time*/
228 if (!This->apidl || This->cidl > 1)
229 enable |= MFS_DISABLED;
230 else
232 DWORD attr = SFGAO_CANRENAME;
234 IShellFolder_GetAttributesOf(This->parent, 1, (LPCITEMIDLIST*)This->apidl, &attr);
235 enable |= (attr & SFGAO_CANRENAME) ? MFS_ENABLED : MFS_DISABLED;
238 EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME - FCIDM_BASE + idCmdFirst, enable);
241 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, uIDMax-idCmdFirst);
243 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
246 /**************************************************************************
247 * DoOpenExplore
249 * for folders only
252 static void DoOpenExplore(ContextMenu *This, HWND hwnd, LPCSTR verb)
254 UINT i;
255 BOOL bFolderFound = FALSE;
256 LPITEMIDLIST pidlFQ;
257 SHELLEXECUTEINFOA sei;
259 /* Find the first item in the list that is not a value. These commands
260 should never be invoked if there isn't at least one folder item in the list.*/
262 for(i = 0; i<This->cidl; i++)
264 if(!_ILIsValue(This->apidl[i]))
266 bFolderFound = TRUE;
267 break;
271 if (!bFolderFound) return;
273 pidlFQ = ILCombine(This->pidl, This->apidl[i]);
275 ZeroMemory(&sei, sizeof(sei));
276 sei.cbSize = sizeof(sei);
277 sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
278 sei.lpIDList = pidlFQ;
279 sei.lpClass = "Folder";
280 sei.hwnd = hwnd;
281 sei.nShow = SW_SHOWNORMAL;
282 sei.lpVerb = verb;
283 ShellExecuteExA(&sei);
284 ILFree(pidlFQ);
287 /**************************************************************************
288 * DoDelete
290 * deletes the currently selected items
292 static void DoDelete(ContextMenu *This)
294 ISFHelper *helper;
296 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
297 if (helper)
299 ISFHelper_DeleteItems(helper, This->cidl, (LPCITEMIDLIST*)This->apidl);
300 ISFHelper_Release(helper);
304 /**************************************************************************
305 * DoCopyOrCut
307 * copies the currently selected items into the clipboard
309 static void DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut)
311 IDataObject *dataobject;
313 TRACE("(%p)->(wnd=%p, cut=%d)\n", This, hwnd, cut);
315 if (SUCCEEDED(IShellFolder_GetUIObjectOf(This->parent, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl, &IID_IDataObject, 0, (void**)&dataobject)))
317 OleSetClipboard(dataobject);
318 IDataObject_Release(dataobject);
322 /**************************************************************************
323 * Properties_AddPropSheetCallback
325 * Used by DoOpenProperties through SHCreatePropSheetExtArrayEx to add
326 * propertysheet pages from shell extensions.
328 static BOOL CALLBACK Properties_AddPropSheetCallback(HPROPSHEETPAGE hpage, LPARAM lparam)
330 LPPROPSHEETHEADERW psh = (LPPROPSHEETHEADERW) lparam;
331 psh->phpage[psh->nPages++] = hpage;
333 return TRUE;
336 static BOOL format_date(FILETIME *time, WCHAR *buffer, DWORD size)
338 FILETIME ft;
339 SYSTEMTIME st;
340 int ret;
342 if (!FileTimeToLocalFileTime(time, &ft))
343 return FALSE;
345 if (!FileTimeToSystemTime(&ft, &st))
346 return FALSE;
348 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buffer, size);
349 if (ret)
351 buffer[ret - 1] = ' ';
352 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buffer + ret , size - ret);
354 return ret != 0;
357 static BOOL get_program_description(WCHAR *path, WCHAR *buffer, DWORD size)
359 WCHAR fileDescW[41], *desc;
360 DWORD versize, *lang;
361 UINT dlen, llen, i;
362 BOOL ret = FALSE;
363 PVOID data;
365 versize = GetFileVersionInfoSizeW(path, NULL);
366 if (!versize) return FALSE;
368 data = malloc(versize);
369 if (!data) return FALSE;
371 if (!GetFileVersionInfoW(path, 0, versize, data))
372 goto out;
374 if (!VerQueryValueW(data, L"\\VarFileInfo\\Translation", (LPVOID *)&lang, &llen))
375 goto out;
377 for (i = 0; i < llen / sizeof(DWORD); i++)
379 swprintf(fileDescW, ARRAY_SIZE(fileDescW), L"\\StringFileInfo\\%04x%04x\\FileDescription",
380 LOWORD(lang[i]), HIWORD(lang[i]));
381 if (VerQueryValueW(data, fileDescW, (LPVOID *)&desc, &dlen))
383 if (dlen > size - 1) dlen = size - 1;
384 memcpy(buffer, desc, dlen * sizeof(WCHAR));
385 buffer[dlen] = 0;
386 ret = TRUE;
387 break;
391 out:
392 free(data);
393 return ret;
396 struct file_properties_info
398 WCHAR path[MAX_PATH];
399 WCHAR dir[MAX_PATH];
400 WCHAR *filename;
401 DWORD attrib;
404 static void init_file_properties_dlg(HWND hwndDlg, struct file_properties_info *props)
406 WCHAR buffer[MAX_PATH], buffer2[MAX_PATH];
407 WIN32_FILE_ATTRIBUTE_DATA exinfo;
408 SHFILEINFOW shinfo;
410 SetDlgItemTextW(hwndDlg, IDC_FPROP_PATH, props->filename);
411 SetDlgItemTextW(hwndDlg, IDC_FPROP_LOCATION, props->dir);
413 if (SHGetFileInfoW(props->path, 0, &shinfo, sizeof(shinfo), SHGFI_TYPENAME|SHGFI_ICON))
415 if (shinfo.hIcon)
417 SendDlgItemMessageW(hwndDlg, IDC_FPROP_ICON, STM_SETICON, (WPARAM)shinfo.hIcon, 0);
418 DestroyIcon(shinfo.hIcon);
420 if (shinfo.szTypeName[0])
421 SetDlgItemTextW(hwndDlg, IDC_FPROP_TYPE, shinfo.szTypeName);
424 if (!GetFileAttributesExW(props->path, GetFileExInfoStandard, &exinfo))
425 return;
427 if (format_date(&exinfo.ftCreationTime, buffer, ARRAY_SIZE(buffer)))
428 SetDlgItemTextW(hwndDlg, IDC_FPROP_CREATED, buffer);
430 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
431 SendDlgItemMessageW(hwndDlg, IDC_FPROP_READONLY, BM_SETCHECK, BST_CHECKED, 0);
432 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
433 SendDlgItemMessageW(hwndDlg, IDC_FPROP_HIDDEN, BM_SETCHECK, BST_CHECKED, 0);
434 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
435 SendDlgItemMessageW(hwndDlg, IDC_FPROP_ARCHIVE, BM_SETCHECK, BST_CHECKED, 0);
437 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
439 SetDlgItemTextW(hwndDlg, IDC_FPROP_SIZE, L"(unknown)");
440 /* TODO: Implement counting for directories */
441 return;
444 /* Information about files only */
445 StrFormatByteSizeW(((LONGLONG)exinfo.nFileSizeHigh << 32) | exinfo.nFileSizeLow,
446 buffer, ARRAY_SIZE(buffer));
447 SetDlgItemTextW(hwndDlg, IDC_FPROP_SIZE, buffer);
449 if (format_date(&exinfo.ftLastWriteTime, buffer, ARRAY_SIZE(buffer)))
450 SetDlgItemTextW(hwndDlg, IDC_FPROP_MODIFIED, buffer);
451 if (format_date(&exinfo.ftLastAccessTime, buffer, ARRAY_SIZE(buffer)))
452 SetDlgItemTextW(hwndDlg, IDC_FPROP_ACCESSED, buffer);
454 if (FindExecutableW(props->path, NULL, buffer) <= (HINSTANCE)32)
455 return;
457 /* Information about executables */
458 if (SHGetFileInfoW(buffer, 0, &shinfo, sizeof(shinfo), SHGFI_ICON | SHGFI_SMALLICON) && shinfo.hIcon)
459 SendDlgItemMessageW(hwndDlg, IDC_FPROP_PROG_ICON, STM_SETICON, (WPARAM)shinfo.hIcon, 0);
461 if (get_program_description(buffer, buffer2, ARRAY_SIZE(buffer2)))
462 SetDlgItemTextW(hwndDlg, IDC_FPROP_PROG_NAME, buffer2);
463 else
465 WCHAR *p = wcsrchr(buffer, '\\');
466 SetDlgItemTextW(hwndDlg, IDC_FPROP_PROG_NAME, p ? ++p : buffer);
470 static INT_PTR CALLBACK file_properties_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
472 switch (uMsg)
474 case WM_INITDIALOG:
476 LPPROPSHEETPAGEW page = (LPPROPSHEETPAGEW)lParam;
477 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)page->lParam);
478 init_file_properties_dlg(hwndDlg, (struct file_properties_info *)page->lParam);
479 break;
482 case WM_COMMAND:
483 if (LOWORD(wParam) == IDC_FPROP_PROG_CHANGE)
485 /* TODO: Implement file association dialog */
486 MessageBoxA(hwndDlg, "Not implemented yet.", "Error", MB_OK | MB_ICONEXCLAMATION);
488 else if (LOWORD(wParam) == IDC_FPROP_READONLY ||
489 LOWORD(wParam) == IDC_FPROP_HIDDEN ||
490 LOWORD(wParam) == IDC_FPROP_ARCHIVE)
492 SendMessageW(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
494 else if (LOWORD(wParam) == IDC_FPROP_PATH && HIWORD(wParam) == EN_CHANGE)
496 SendMessageW(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
498 break;
500 case WM_NOTIFY:
502 LPPSHNOTIFY notify = (LPPSHNOTIFY)lParam;
503 if (notify->hdr.code == PSN_APPLY)
505 struct file_properties_info *props = (struct file_properties_info *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
506 WCHAR newname[MAX_PATH], newpath[MAX_PATH];
507 DWORD attributes;
509 attributes = GetFileAttributesW(props->path);
510 if (attributes != INVALID_FILE_ATTRIBUTES)
512 attributes &= ~(FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE);
514 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_READONLY, BM_GETCHECK, 0, 0) == BST_CHECKED)
515 attributes |= FILE_ATTRIBUTE_READONLY;
516 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_HIDDEN, BM_GETCHECK, 0, 0) == BST_CHECKED)
517 attributes |= FILE_ATTRIBUTE_HIDDEN;
518 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_ARCHIVE, BM_GETCHECK, 0, 0) == BST_CHECKED)
519 attributes |= FILE_ATTRIBUTE_ARCHIVE;
521 if (!SetFileAttributesW(props->path, attributes))
522 ERR("failed to update file attributes of %s\n", debugstr_w(props->path));
525 /* Update filename if it was changed */
526 if (GetDlgItemTextW(hwndDlg, IDC_FPROP_PATH, newname, ARRAY_SIZE(newname)) &&
527 wcscmp(props->filename, newname) &&
528 lstrlenW(props->dir) + lstrlenW(newname) + 2 < ARRAY_SIZE(newpath))
530 lstrcpyW(newpath, props->dir);
531 lstrcatW(newpath, L"\\");
532 lstrcatW(newpath, newname);
534 if (!MoveFileW(props->path, newpath))
535 ERR("failed to move file %s to %s\n", debugstr_w(props->path), debugstr_w(newpath));
536 else
538 WCHAR *p;
539 lstrcpyW(props->path, newpath);
540 lstrcpyW(props->dir, newpath);
541 if ((p = wcsrchr(props->dir, '\\')))
543 *p = 0;
544 props->filename = p + 1;
546 else
547 props->filename = props->dir;
548 SetDlgItemTextW(hwndDlg, IDC_FPROP_LOCATION, props->dir);
552 return TRUE;
555 break;
557 default:
558 break;
560 return FALSE;
563 static UINT CALLBACK file_properties_callback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGEW page)
565 struct file_properties_info *props = (struct file_properties_info *)page->lParam;
566 if (uMsg == PSPCB_RELEASE)
568 free(props);
570 return 1;
573 static void init_file_properties_pages(IDataObject *dataobject, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
575 struct file_properties_info *props;
576 HPROPSHEETPAGE general_page;
577 PROPSHEETPAGEW propsheet;
578 FORMATETC format;
579 STGMEDIUM stgm;
580 HRESULT hr;
581 WCHAR *p;
583 props = malloc(sizeof(*props));
584 if (!props) return;
586 format.cfFormat = CF_HDROP;
587 format.ptd = NULL;
588 format.dwAspect = DVASPECT_CONTENT;
589 format.lindex = -1;
590 format.tymed = TYMED_HGLOBAL;
592 hr = IDataObject_GetData(dataobject, &format, &stgm);
593 if (FAILED(hr)) goto error;
595 if (!DragQueryFileW((HDROP)stgm.hGlobal, 0, props->path, ARRAY_SIZE(props->path)))
597 ReleaseStgMedium(&stgm);
598 goto error;
601 ReleaseStgMedium(&stgm);
603 props->attrib = GetFileAttributesW(props->path);
604 if (props->attrib == INVALID_FILE_ATTRIBUTES)
605 goto error;
607 lstrcpyW(props->dir, props->path);
608 if ((p = wcsrchr(props->dir, '\\')))
610 *p = 0;
611 props->filename = p + 1;
613 else
614 props->filename = props->dir;
616 memset(&propsheet, 0, sizeof(propsheet));
617 propsheet.dwSize = sizeof(propsheet);
618 propsheet.dwFlags = PSP_DEFAULT | PSP_USECALLBACK;
619 propsheet.hInstance = shell32_hInstance;
620 if (props->attrib & FILE_ATTRIBUTE_DIRECTORY)
621 propsheet.pszTemplate = (LPWSTR)MAKEINTRESOURCE(IDD_FOLDER_PROPERTIES);
622 else
623 propsheet.pszTemplate = (LPWSTR)MAKEINTRESOURCE(IDD_FILE_PROPERTIES);
624 propsheet.pfnDlgProc = file_properties_proc;
625 propsheet.pfnCallback = file_properties_callback;
626 propsheet.lParam = (LPARAM)props;
628 general_page = CreatePropertySheetPageW(&propsheet);
629 if (general_page)
630 lpfnAddPage(general_page, lParam);
631 return;
633 error:
634 free(props);
637 #define MAX_PROP_PAGES 99
639 static void DoOpenProperties(ContextMenu *This, HWND hwnd)
641 LPSHELLFOLDER lpDesktopSF;
642 LPSHELLFOLDER lpSF;
643 LPDATAOBJECT lpDo;
644 WCHAR wszFiletype[MAX_PATH];
645 WCHAR wszFilename[MAX_PATH];
646 PROPSHEETHEADERW psh;
647 HPROPSHEETPAGE hpages[MAX_PROP_PAGES];
648 HPSXA hpsxa;
649 UINT ret;
651 TRACE("(%p)->(wnd=%p)\n", This, hwnd);
653 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
654 psh.dwSize = sizeof (PROPSHEETHEADERW);
655 psh.hwndParent = hwnd;
656 psh.dwFlags = PSH_PROPTITLE;
657 psh.nPages = 0;
658 psh.phpage = hpages;
659 psh.nStartPage = 0;
661 _ILSimpleGetTextW(This->apidl[0], (LPVOID)wszFilename, MAX_PATH);
662 psh.pszCaption = (LPCWSTR)wszFilename;
664 /* Find out where to look for the shell extensions */
665 if (_ILIsValue(This->apidl[0]))
667 char sTemp[64];
668 sTemp[0] = 0;
669 if (_ILGetExtension(This->apidl[0], sTemp, 64))
671 HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE);
672 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wszFiletype, MAX_PATH);
674 else
676 wszFiletype[0] = 0;
679 else if (_ILIsFolder(This->apidl[0]))
681 lstrcpynW(wszFiletype, L"Folder", 64);
683 else if (_ILIsSpecialFolder(This->apidl[0]))
685 LPGUID folderGUID;
686 folderGUID = _ILGetGUIDPointer(This->apidl[0]);
687 lstrcpyW(wszFiletype, L"CLSID\\");
688 StringFromGUID2(folderGUID, &wszFiletype[6], MAX_PATH - 6);
690 else
692 FIXME("Requested properties for unknown type.\n");
693 return;
696 /* Get a suitable DataObject for accessing the files */
697 SHGetDesktopFolder(&lpDesktopSF);
698 if (_ILIsPidlSimple(This->pidl))
700 ret = IShellFolder_GetUIObjectOf(lpDesktopSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
701 &IID_IDataObject, NULL, (LPVOID *)&lpDo);
702 IShellFolder_Release(lpDesktopSF);
704 else
706 IShellFolder_BindToObject(lpDesktopSF, This->pidl, NULL, &IID_IShellFolder, (LPVOID*) &lpSF);
707 ret = IShellFolder_GetUIObjectOf(lpSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
708 &IID_IDataObject, NULL, (LPVOID *)&lpDo);
709 IShellFolder_Release(lpSF);
710 IShellFolder_Release(lpDesktopSF);
713 if (SUCCEEDED(ret))
715 init_file_properties_pages(lpDo, Properties_AddPropSheetCallback, (LPARAM)&psh);
717 hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletype, MAX_PROP_PAGES - psh.nPages, lpDo);
718 if (hpsxa != NULL)
720 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
721 SHDestroyPropSheetExtArray(hpsxa);
723 hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, L"*", MAX_PROP_PAGES - psh.nPages, lpDo);
724 if (hpsxa != NULL)
726 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
727 SHDestroyPropSheetExtArray(hpsxa);
729 IDataObject_Release(lpDo);
732 if (psh.nPages)
733 PropertySheetW(&psh);
734 else
735 FIXME("No property pages found.\n");
738 static HRESULT WINAPI ItemMenu_InvokeCommand(
739 IContextMenu3 *iface,
740 LPCMINVOKECOMMANDINFO lpcmi)
742 ContextMenu *This = impl_from_IContextMenu3(iface);
744 if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))
745 FIXME("Is an EX structure\n");
747 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
749 if (IS_INTRESOURCE(lpcmi->lpVerb) && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)
751 TRACE("Invalid Verb %x\n", LOWORD(lpcmi->lpVerb));
752 return E_INVALIDARG;
755 if (IS_INTRESOURCE(lpcmi->lpVerb))
757 switch(LOWORD(lpcmi->lpVerb) + FCIDM_BASE)
759 case FCIDM_SHVIEW_EXPLORE:
760 TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");
761 DoOpenExplore(This, lpcmi->hwnd, "explore");
762 break;
763 case FCIDM_SHVIEW_OPEN:
764 TRACE("Verb FCIDM_SHVIEW_OPEN\n");
765 DoOpenExplore(This, lpcmi->hwnd, "open");
766 break;
767 case FCIDM_SHVIEW_RENAME:
769 IShellBrowser *browser;
771 /* get the active IShellView */
772 browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
773 if (browser)
775 IShellView *view;
777 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
779 TRACE("(shellview=%p)\n", view);
780 IShellView_SelectItem(view, This->apidl[0],
781 SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
782 IShellView_Release(view);
785 break;
787 case FCIDM_SHVIEW_DELETE:
788 TRACE("Verb FCIDM_SHVIEW_DELETE\n");
789 DoDelete(This);
790 break;
791 case FCIDM_SHVIEW_COPY:
792 TRACE("Verb FCIDM_SHVIEW_COPY\n");
793 DoCopyOrCut(This, lpcmi->hwnd, FALSE);
794 break;
795 case FCIDM_SHVIEW_CUT:
796 TRACE("Verb FCIDM_SHVIEW_CUT\n");
797 DoCopyOrCut(This, lpcmi->hwnd, TRUE);
798 break;
799 case FCIDM_SHVIEW_PROPERTIES:
800 TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
801 DoOpenProperties(This, lpcmi->hwnd);
802 break;
803 default:
804 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
805 return E_INVALIDARG;
808 else
810 TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));
811 if (strcmp(lpcmi->lpVerb,"delete")==0)
812 DoDelete(This);
813 else if (strcmp(lpcmi->lpVerb,"copy")==0)
814 DoCopyOrCut(This, lpcmi->hwnd, FALSE);
815 else if (strcmp(lpcmi->lpVerb,"cut")==0)
816 DoCopyOrCut(This, lpcmi->hwnd, TRUE);
817 else if (strcmp(lpcmi->lpVerb,"properties")==0)
818 DoOpenProperties(This, lpcmi->hwnd);
819 else {
820 FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));
821 return E_FAIL;
824 return S_OK;
827 static HRESULT WINAPI ItemMenu_GetCommandString(IContextMenu3 *iface, UINT_PTR cmdid, UINT flags,
828 UINT *reserved, LPSTR name, UINT maxlen)
830 ContextMenu *This = impl_from_IContextMenu3(iface);
831 const WCHAR *cmdW = NULL;
832 HRESULT hr = S_OK;
834 TRACE("(%p)->(%Ix, %#x, %p, %p, %u)\n", This, cmdid, flags, reserved, name, maxlen);
836 switch (flags)
838 case GCS_HELPTEXTA:
839 case GCS_HELPTEXTW:
840 hr = E_NOTIMPL;
841 break;
843 case GCS_VERBA:
844 case GCS_VERBW:
845 switch (cmdid + FCIDM_BASE)
847 case FCIDM_SHVIEW_OPEN:
848 cmdW = L"open";
849 break;
850 case FCIDM_SHVIEW_EXPLORE:
851 cmdW = L"explore";
852 break;
853 case FCIDM_SHVIEW_CUT:
854 cmdW = L"cut";
855 break;
856 case FCIDM_SHVIEW_COPY:
857 cmdW = L"copy";
858 break;
859 case FCIDM_SHVIEW_CREATELINK:
860 cmdW = L"link";
861 break;
862 case FCIDM_SHVIEW_DELETE:
863 cmdW = L"delete";
864 break;
865 case FCIDM_SHVIEW_PROPERTIES:
866 cmdW = L"properties";
867 break;
868 case FCIDM_SHVIEW_RENAME:
869 cmdW = L"rename";
870 break;
873 if (!cmdW)
875 hr = E_INVALIDARG;
876 break;
879 if (flags == GCS_VERBA)
880 WideCharToMultiByte(CP_ACP, 0, cmdW, -1, name, maxlen, NULL, NULL);
881 else
882 lstrcpynW((WCHAR *)name, cmdW, maxlen);
884 TRACE("name %s\n", flags == GCS_VERBA ? debugstr_a(name) : debugstr_w((WCHAR *)name));
885 break;
887 case GCS_VALIDATEA:
888 case GCS_VALIDATEW:
889 break;
892 return hr;
895 /**************************************************************************
896 * NOTES
897 * should be only in IContextMenu2 and IContextMenu3
898 * is nevertheless called from word95
900 static HRESULT WINAPI ContextMenu_HandleMenuMsg(IContextMenu3 *iface, UINT msg,
901 WPARAM wParam, LPARAM lParam)
903 ContextMenu *This = impl_from_IContextMenu3(iface);
904 FIXME("(%p)->(0x%x 0x%Ix 0x%Ix): stub\n", This, msg, wParam, lParam);
905 return E_NOTIMPL;
908 static HRESULT WINAPI ContextMenu_HandleMenuMsg2(IContextMenu3 *iface, UINT msg,
909 WPARAM wParam, LPARAM lParam, LRESULT *result)
911 ContextMenu *This = impl_from_IContextMenu3(iface);
912 FIXME("(%p)->(0x%x 0x%Ix 0x%Ix %p): stub\n", This, msg, wParam, lParam, result);
913 return E_NOTIMPL;
916 static const IContextMenu3Vtbl ItemContextMenuVtbl =
918 ContextMenu_QueryInterface,
919 ContextMenu_AddRef,
920 ContextMenu_Release,
921 ItemMenu_QueryContextMenu,
922 ItemMenu_InvokeCommand,
923 ItemMenu_GetCommandString,
924 ContextMenu_HandleMenuMsg,
925 ContextMenu_HandleMenuMsg2
928 static HRESULT WINAPI ShellExtInit_QueryInterface(IShellExtInit *iface, REFIID riid, void **obj)
930 ContextMenu *This = impl_from_IShellExtInit(iface);
931 return IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, obj);
934 static ULONG WINAPI ShellExtInit_AddRef(IShellExtInit *iface)
936 ContextMenu *This = impl_from_IShellExtInit(iface);
937 return IContextMenu3_AddRef(&This->IContextMenu3_iface);
940 static ULONG WINAPI ShellExtInit_Release(IShellExtInit *iface)
942 ContextMenu *This = impl_from_IShellExtInit(iface);
943 return IContextMenu3_Release(&This->IContextMenu3_iface);
946 static HRESULT WINAPI ShellExtInit_Initialize(IShellExtInit *iface, LPCITEMIDLIST folder,
947 IDataObject *dataobj, HKEY progidkey)
949 ContextMenu *This = impl_from_IShellExtInit(iface);
951 FIXME("(%p)->(%p %p %p): stub\n", This, folder, dataobj, progidkey);
953 return E_NOTIMPL;
956 static const IShellExtInitVtbl ShellExtInitVtbl =
958 ShellExtInit_QueryInterface,
959 ShellExtInit_AddRef,
960 ShellExtInit_Release,
961 ShellExtInit_Initialize
964 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID riid, void **obj)
966 ContextMenu *This = impl_from_IObjectWithSite(iface);
967 return IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, obj);
970 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
972 ContextMenu *This = impl_from_IObjectWithSite(iface);
973 return IContextMenu3_AddRef(&This->IContextMenu3_iface);
976 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
978 ContextMenu *This = impl_from_IObjectWithSite(iface);
979 return IContextMenu3_Release(&This->IContextMenu3_iface);
982 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *site)
984 ContextMenu *This = impl_from_IObjectWithSite(iface);
986 FIXME("(%p)->(%p): stub\n", This, site);
988 return E_NOTIMPL;
991 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, void **site)
993 ContextMenu *This = impl_from_IObjectWithSite(iface);
995 FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), site);
997 return E_NOTIMPL;
1000 static const IObjectWithSiteVtbl ObjectWithSiteVtbl =
1002 ObjectWithSite_QueryInterface,
1003 ObjectWithSite_AddRef,
1004 ObjectWithSite_Release,
1005 ObjectWithSite_SetSite,
1006 ObjectWithSite_GetSite,
1009 HRESULT ItemMenu_Constructor(IShellFolder *parent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *apidl, UINT cidl,
1010 REFIID riid, void **pObj)
1012 ContextMenu* This;
1013 HRESULT hr;
1014 UINT i;
1016 This = malloc(sizeof(*This));
1017 if (!This) return E_OUTOFMEMORY;
1019 This->IContextMenu3_iface.lpVtbl = &ItemContextMenuVtbl;
1020 This->IShellExtInit_iface.lpVtbl = &ShellExtInitVtbl;
1021 This->IObjectWithSite_iface.lpVtbl = &ObjectWithSiteVtbl;
1022 This->ref = 1;
1023 This->parent = parent;
1024 if (parent) IShellFolder_AddRef(parent);
1026 This->pidl = ILClone(pidl);
1027 This->apidl = _ILCopyaPidl(apidl, cidl);
1028 This->cidl = cidl;
1029 This->allvalues = TRUE;
1031 This->desktop = FALSE;
1033 for (i = 0; i < cidl; i++)
1034 This->allvalues &= (_ILIsValue(apidl[i]) ? 1 : 0);
1036 hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
1037 IContextMenu3_Release(&This->IContextMenu3_iface);
1039 return hr;
1042 /* Background menu implementation */
1043 static HRESULT WINAPI BackgroundMenu_QueryContextMenu(
1044 IContextMenu3 *iface,
1045 HMENU hMenu,
1046 UINT indexMenu,
1047 UINT idCmdFirst,
1048 UINT idCmdLast,
1049 UINT uFlags)
1051 ContextMenu *This = impl_from_IContextMenu3(iface);
1052 HMENU hMyMenu;
1053 UINT idMax;
1054 HRESULT hr;
1056 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
1057 This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
1059 hMyMenu = LoadMenuA(shell32_hInstance, "MENU_002");
1060 if (uFlags & CMF_DEFAULTONLY)
1062 HMENU ourMenu = GetSubMenu(hMyMenu,0);
1063 UINT oldDef = GetMenuDefaultItem(hMenu,TRUE,GMDI_USEDISABLED);
1064 UINT newDef = GetMenuDefaultItem(ourMenu,TRUE,GMDI_USEDISABLED);
1065 if (newDef != oldDef)
1066 SetMenuDefaultItem(hMenu,newDef,TRUE);
1067 if (newDef!=0xFFFFFFFF)
1068 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, newDef+1);
1069 else
1070 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
1072 else
1074 Shell_MergeMenus (hMenu, GetSubMenu(hMyMenu,0), indexMenu,
1075 idCmdFirst - FCIDM_BASE, idCmdLast, MM_SUBMENUSHAVEIDS);
1076 idMax = max_menu_id(GetSubMenu(hMyMenu, 0), idCmdFirst - FCIDM_BASE, idCmdLast);
1077 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst);
1079 DestroyMenu(hMyMenu);
1081 TRACE("(%p)->returning 0x%lx\n",This,hr);
1082 return hr;
1085 static void DoNewFolder(ContextMenu *This, IShellView *view)
1087 ISFHelper *helper;
1089 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
1090 if (helper)
1092 WCHAR nameW[MAX_PATH];
1093 LPITEMIDLIST pidl;
1095 ISFHelper_GetUniqueName(helper, nameW, MAX_PATH);
1096 ISFHelper_AddFolder(helper, 0, nameW, &pidl);
1098 if (view)
1100 /* if we are in a shellview do labeledit */
1101 IShellView_SelectItem(view,
1102 pidl,(SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE
1103 |SVSI_FOCUSED|SVSI_SELECT));
1106 SHFree(pidl);
1107 ISFHelper_Release(helper);
1111 static HRESULT paste_pidls(ContextMenu *This, ITEMIDLIST **pidls, UINT count)
1113 IShellFolder *psfDesktop;
1114 UINT i;
1115 HRESULT hr = S_OK;
1117 /* bind to the source shellfolder */
1118 hr = SHGetDesktopFolder(&psfDesktop);
1119 if (FAILED(hr))
1120 return hr;
1122 for (i = 0; SUCCEEDED(hr) && i < count; i++) {
1123 ITEMIDLIST *pidl_dir = NULL;
1124 ITEMIDLIST *pidl_item;
1125 IShellFolder *psfFrom = NULL;
1127 pidl_dir = ILClone(pidls[i]);
1128 ILRemoveLastID(pidl_dir);
1129 pidl_item = ILFindLastID(pidls[i]);
1130 hr = IShellFolder_BindToObject(psfDesktop, pidl_dir, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom);
1132 if (psfFrom)
1134 /* get source and destination shellfolder */
1135 ISFHelper *psfhlpdst = NULL, *psfhlpsrc = NULL;
1136 hr = IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&psfhlpdst);
1137 if (SUCCEEDED(hr))
1138 hr = IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (void**)&psfhlpsrc);
1140 /* do the copy/move */
1141 if (psfhlpdst && psfhlpsrc)
1143 hr = ISFHelper_CopyItems(psfhlpdst, psfFrom, 1, (LPCITEMIDLIST*)&pidl_item);
1144 /* FIXME handle move
1145 ISFHelper_DeleteItems(psfhlpsrc, 1, &pidl_item);
1148 if(psfhlpdst) ISFHelper_Release(psfhlpdst);
1149 if(psfhlpsrc) ISFHelper_Release(psfhlpsrc);
1150 IShellFolder_Release(psfFrom);
1152 ILFree(pidl_dir);
1155 IShellFolder_Release(psfDesktop);
1156 return hr;
1159 static HRESULT DoPaste(ContextMenu *This)
1161 IDataObject * pda;
1162 HRESULT hr;
1164 TRACE("\n");
1166 hr = OleGetClipboard(&pda);
1167 if(SUCCEEDED(hr))
1169 STGMEDIUM medium;
1170 FORMATETC formatetc;
1171 HRESULT format_hr;
1173 TRACE("pda=%p\n", pda);
1175 /* Set the FORMATETC structure*/
1176 InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL);
1178 /* Get the pidls from IDataObject */
1179 format_hr = IDataObject_GetData(pda,&formatetc,&medium);
1180 if(SUCCEEDED(format_hr))
1182 LPITEMIDLIST * apidl;
1183 LPITEMIDLIST pidl;
1185 LPIDA lpcida = GlobalLock(medium.hGlobal);
1186 TRACE("cida=%p\n", lpcida);
1187 if(lpcida)
1189 apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
1190 if (apidl)
1192 hr = paste_pidls(This, apidl, lpcida->cidl);
1193 _ILFreeaPidl(apidl, lpcida->cidl);
1194 SHFree(pidl);
1196 else
1197 hr = HRESULT_FROM_WIN32(GetLastError());
1198 GlobalUnlock(medium.hGlobal);
1200 else
1201 hr = HRESULT_FROM_WIN32(GetLastError());
1202 ReleaseStgMedium(&medium);
1205 if(FAILED(format_hr))
1207 InitFormatEtc(formatetc, CF_HDROP, TYMED_HGLOBAL);
1208 format_hr = IDataObject_GetData(pda,&formatetc,&medium);
1209 if(SUCCEEDED(format_hr))
1211 WCHAR path[MAX_PATH];
1212 UINT i, count;
1213 ITEMIDLIST **pidls;
1215 TRACE("CF_HDROP=%p\n", medium.hGlobal);
1216 count = DragQueryFileW(medium.hGlobal, -1, NULL, 0);
1217 pidls = SHAlloc(count*sizeof(ITEMIDLIST*));
1218 if (pidls)
1220 for (i = 0; i < count; i++)
1222 DragQueryFileW(medium.hGlobal, i, path, ARRAY_SIZE(path));
1223 if ((pidls[i] = ILCreateFromPathW(path)) == NULL)
1225 hr = E_FAIL;
1226 break;
1229 if (SUCCEEDED(hr))
1230 hr = paste_pidls(This, pidls, count);
1231 _ILFreeaPidl(pidls, count);
1233 else
1234 hr = HRESULT_FROM_WIN32(GetLastError());
1235 ReleaseStgMedium(&medium);
1239 if (FAILED(format_hr))
1241 ERR("there are no supported and retrievable clipboard formats\n");
1242 hr = format_hr;
1245 IDataObject_Release(pda);
1247 #if 0
1248 HGLOBAL hMem;
1250 OpenClipboard(NULL);
1251 hMem = GetClipboardData(CF_HDROP);
1253 if(hMem)
1255 char * pDropFiles = GlobalLock(hMem);
1256 if(pDropFiles)
1258 int len, offset = sizeof(DROPFILESTRUCT);
1260 while( pDropFiles[offset] != 0)
1262 len = strlen(pDropFiles + offset);
1263 TRACE("%s\n", pDropFiles + offset);
1264 offset += len+1;
1267 GlobalUnlock(hMem);
1269 CloseClipboard();
1270 #endif
1271 return hr;
1274 static HRESULT WINAPI BackgroundMenu_InvokeCommand(
1275 IContextMenu3 *iface,
1276 LPCMINVOKECOMMANDINFO lpcmi)
1278 ContextMenu *This = impl_from_IContextMenu3(iface);
1279 IShellBrowser *browser;
1280 IShellView *view = NULL;
1281 HWND hWnd = NULL;
1283 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", This, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
1285 /* get the active IShellView */
1286 if ((browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0)))
1288 if (SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
1289 IShellView_GetWindow(view, &hWnd);
1292 if(HIWORD(lpcmi->lpVerb))
1294 TRACE("%s\n", debugstr_a(lpcmi->lpVerb));
1296 if (!strcmp(lpcmi->lpVerb, CMDSTR_NEWFOLDERA))
1298 DoNewFolder(This, view);
1300 else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWLISTA))
1302 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_LISTVIEW, 0), 0);
1304 else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWDETAILSA))
1306 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW, 0), 0);
1308 else if (!strcmp(lpcmi->lpVerb, "paste"))
1310 DoPaste(This);
1312 else
1314 FIXME("please report: unknown verb %s\n", debugstr_a(lpcmi->lpVerb));
1317 else
1319 switch (LOWORD(lpcmi->lpVerb) + FCIDM_BASE)
1321 case FCIDM_SHVIEW_REFRESH:
1322 if (view) IShellView_Refresh(view);
1323 break;
1325 case FCIDM_SHVIEW_NEWFOLDER:
1326 DoNewFolder(This, view);
1327 break;
1329 case FCIDM_SHVIEW_INSERT:
1330 DoPaste(This);
1331 break;
1333 case FCIDM_SHVIEW_PROPERTIES:
1334 if (This->desktop) {
1335 ShellExecuteA(lpcmi->hwnd, "open", "rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL);
1336 } else {
1337 FIXME("launch item properties dialog\n");
1339 break;
1341 default:
1342 /* if it's an id just pass it to the parent shv */
1343 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
1344 break;
1348 if (view)
1349 IShellView_Release(view);
1351 return S_OK;
1354 static HRESULT WINAPI BackgroundMenu_GetCommandString(
1355 IContextMenu3 *iface,
1356 UINT_PTR idCommand,
1357 UINT uFlags,
1358 UINT* lpReserved,
1359 LPSTR lpszName,
1360 UINT uMaxNameLen)
1362 ContextMenu *This = impl_from_IContextMenu3(iface);
1363 const WCHAR *cmdW = NULL;
1364 HRESULT hr = E_FAIL;
1366 TRACE("(%p)->(idcom=%Ix flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
1368 switch (uFlags)
1370 case GCS_HELPTEXTA:
1371 case GCS_HELPTEXTW:
1372 hr = E_NOTIMPL;
1373 break;
1375 case GCS_VERBA:
1376 case GCS_VERBW:
1377 switch (idCommand + FCIDM_BASE)
1379 case FCIDM_SHVIEW_INSERT:
1380 cmdW = L"paste";
1381 break;
1382 case FCIDM_SHVIEW_PROPERTIES:
1383 cmdW = L"properties";
1384 break;
1387 if (!cmdW)
1389 hr = E_INVALIDARG;
1390 break;
1393 if (uFlags == GCS_VERBA)
1394 WideCharToMultiByte(CP_ACP, 0, cmdW, -1, lpszName, uMaxNameLen, NULL, NULL);
1395 else
1396 lstrcpynW((WCHAR *)lpszName, cmdW, uMaxNameLen);
1397 TRACE("name %s\n", uFlags == GCS_VERBA ? debugstr_a(lpszName) : debugstr_w((WCHAR *)lpszName));
1398 hr = S_OK;
1399 break;
1401 case GCS_VALIDATEA:
1402 case GCS_VALIDATEW:
1403 /* test the existence of the menu items, the file dialog enables
1404 the buttons according to this */
1405 if (HIWORD(idCommand))
1407 if (!strcmp((LPSTR)idCommand, CMDSTR_VIEWLISTA) ||
1408 !strcmp((LPSTR)idCommand, CMDSTR_VIEWDETAILSA) ||
1409 !strcmp((LPSTR)idCommand, CMDSTR_NEWFOLDERA))
1410 hr = S_OK;
1411 else
1413 FIXME("unknown command string %s\n", uFlags == GCS_VALIDATEA ? debugstr_a((LPSTR)idCommand) : debugstr_w((WCHAR*)idCommand));
1414 hr = E_FAIL;
1417 break;
1419 return hr;
1422 static const IContextMenu3Vtbl BackgroundContextMenuVtbl =
1424 ContextMenu_QueryInterface,
1425 ContextMenu_AddRef,
1426 ContextMenu_Release,
1427 BackgroundMenu_QueryContextMenu,
1428 BackgroundMenu_InvokeCommand,
1429 BackgroundMenu_GetCommandString,
1430 ContextMenu_HandleMenuMsg,
1431 ContextMenu_HandleMenuMsg2
1434 HRESULT BackgroundMenu_Constructor(IShellFolder *parent, BOOL desktop, REFIID riid, void **pObj)
1436 ContextMenu *This;
1437 HRESULT hr;
1439 This = malloc(sizeof(*This));
1440 if (!This) return E_OUTOFMEMORY;
1442 This->IContextMenu3_iface.lpVtbl = &BackgroundContextMenuVtbl;
1443 This->IShellExtInit_iface.lpVtbl = &ShellExtInitVtbl;
1444 This->IObjectWithSite_iface.lpVtbl = &ObjectWithSiteVtbl;
1445 This->ref = 1;
1446 This->parent = parent;
1448 This->pidl = NULL;
1449 This->apidl = NULL;
1450 This->cidl = 0;
1451 This->allvalues = FALSE;
1453 This->desktop = desktop;
1454 if (parent) IShellFolder_AddRef(parent);
1456 hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
1457 IContextMenu3_Release(&This->IContextMenu3_iface);
1459 return hr;