ntdll: Add a helper for platform-specific threading initialization.
[wine.git] / dlls / shell32 / shlview_cmenu.c
blob04ac0b6fd3cb0c9ec18ab49c9aa16e69f96823ec
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 "undocshell.h"
33 #include "shlobj.h"
34 #include "winreg.h"
35 #include "prsht.h"
37 #include "shell32_main.h"
38 #include "shellfolder.h"
40 #include "shresdef.h"
41 #include "shlwapi.h"
43 #include "wine/heap.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48 typedef struct
50 IContextMenu3 IContextMenu3_iface;
51 IShellExtInit IShellExtInit_iface;
52 IObjectWithSite IObjectWithSite_iface;
53 LONG ref;
55 IShellFolder* parent;
57 /* item menu data */
58 LPITEMIDLIST pidl; /* root pidl */
59 LPITEMIDLIST *apidl; /* array of child pidls */
60 UINT cidl;
61 BOOL allvalues;
63 /* background menu data */
64 BOOL desktop;
65 } ContextMenu;
67 static inline ContextMenu *impl_from_IContextMenu3(IContextMenu3 *iface)
69 return CONTAINING_RECORD(iface, ContextMenu, IContextMenu3_iface);
72 static inline ContextMenu *impl_from_IShellExtInit(IShellExtInit *iface)
74 return CONTAINING_RECORD(iface, ContextMenu, IShellExtInit_iface);
77 static inline ContextMenu *impl_from_IObjectWithSite(IObjectWithSite *iface)
79 return CONTAINING_RECORD(iface, ContextMenu, IObjectWithSite_iface);
82 static HRESULT WINAPI ContextMenu_QueryInterface(IContextMenu3 *iface, REFIID riid, LPVOID *ppvObj)
84 ContextMenu *This = impl_from_IContextMenu3(iface);
86 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObj);
88 *ppvObj = NULL;
90 if (IsEqualIID(riid, &IID_IUnknown) ||
91 IsEqualIID(riid, &IID_IContextMenu) ||
92 IsEqualIID(riid, &IID_IContextMenu2) ||
93 IsEqualIID(riid, &IID_IContextMenu3))
95 *ppvObj = &This->IContextMenu3_iface;
97 else if (IsEqualIID(riid, &IID_IShellExtInit))
99 *ppvObj = &This->IShellExtInit_iface;
101 else if (IsEqualIID(riid, &IID_IObjectWithSite))
103 *ppvObj = &This->IObjectWithSite_iface;
106 if(*ppvObj)
108 IContextMenu3_AddRef(iface);
109 return S_OK;
112 TRACE("-- Interface: E_NOINTERFACE\n");
113 return E_NOINTERFACE;
116 static ULONG WINAPI ContextMenu_AddRef(IContextMenu3 *iface)
118 ContextMenu *This = impl_from_IContextMenu3(iface);
119 ULONG ref = InterlockedIncrement(&This->ref);
120 TRACE("(%p)->(%u)\n", This, ref);
121 return ref;
124 static ULONG WINAPI ContextMenu_Release(IContextMenu3 *iface)
126 ContextMenu *This = impl_from_IContextMenu3(iface);
127 ULONG ref = InterlockedDecrement(&This->ref);
129 TRACE("(%p)->(%u)\n", This, ref);
131 if (!ref)
133 if(This->parent)
134 IShellFolder_Release(This->parent);
136 SHFree(This->pidl);
137 _ILFreeaPidl(This->apidl, This->cidl);
139 heap_free(This);
142 return ref;
145 static HRESULT WINAPI ItemMenu_QueryContextMenu(
146 IContextMenu3 *iface,
147 HMENU hmenu,
148 UINT indexMenu,
149 UINT idCmdFirst,
150 UINT idCmdLast,
151 UINT uFlags)
153 ContextMenu *This = impl_from_IContextMenu3(iface);
154 INT uIDMax;
156 TRACE("(%p)->(%p %d 0x%x 0x%x 0x%x )\n", This, hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
158 if(!(CMF_DEFAULTONLY & uFlags) && This->cidl > 0)
160 HMENU hmenures = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(MENU_SHV_FILE));
162 if(uFlags & CMF_EXPLORE)
163 RemoveMenu(hmenures, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
165 uIDMax = Shell_MergeMenus(hmenu, GetSubMenu(hmenures, 0), indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
167 DestroyMenu(hmenures);
169 if(This->allvalues)
171 MENUITEMINFOW mi;
172 WCHAR str[255];
173 mi.cbSize = sizeof(mi);
174 mi.fMask = MIIM_ID | MIIM_STRING | MIIM_FTYPE;
175 mi.dwTypeData = str;
176 mi.cch = 255;
177 GetMenuItemInfoW(hmenu, FCIDM_SHVIEW_EXPLORE, MF_BYCOMMAND, &mi);
178 RemoveMenu(hmenu, FCIDM_SHVIEW_EXPLORE + idCmdFirst, MF_BYCOMMAND);
180 mi.cbSize = sizeof(mi);
181 mi.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_STRING;
182 mi.dwTypeData = str;
183 mi.fState = MFS_ENABLED;
184 mi.wID = FCIDM_SHVIEW_EXPLORE;
185 mi.fType = MFT_STRING;
186 InsertMenuItemW(hmenu, (uFlags & CMF_EXPLORE) ? 1 : 2, MF_BYPOSITION, &mi);
189 SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
191 if(uFlags & ~CMF_CANRENAME)
192 RemoveMenu(hmenu, FCIDM_SHVIEW_RENAME, MF_BYCOMMAND);
193 else
195 UINT enable = MF_BYCOMMAND;
197 /* can't rename more than one item at a time*/
198 if (!This->apidl || This->cidl > 1)
199 enable |= MFS_DISABLED;
200 else
202 DWORD attr = SFGAO_CANRENAME;
204 IShellFolder_GetAttributesOf(This->parent, 1, (LPCITEMIDLIST*)This->apidl, &attr);
205 enable |= (attr & SFGAO_CANRENAME) ? MFS_ENABLED : MFS_DISABLED;
208 EnableMenuItem(hmenu, FCIDM_SHVIEW_RENAME, enable);
211 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, uIDMax-idCmdFirst);
213 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
216 /**************************************************************************
217 * DoOpenExplore
219 * for folders only
222 static void DoOpenExplore(ContextMenu *This, HWND hwnd, LPCSTR verb)
224 UINT i;
225 BOOL bFolderFound = FALSE;
226 LPITEMIDLIST pidlFQ;
227 SHELLEXECUTEINFOA sei;
229 /* Find the first item in the list that is not a value. These commands
230 should never be invoked if there isn't at least one folder item in the list.*/
232 for(i = 0; i<This->cidl; i++)
234 if(!_ILIsValue(This->apidl[i]))
236 bFolderFound = TRUE;
237 break;
241 if (!bFolderFound) return;
243 pidlFQ = ILCombine(This->pidl, This->apidl[i]);
245 ZeroMemory(&sei, sizeof(sei));
246 sei.cbSize = sizeof(sei);
247 sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME;
248 sei.lpIDList = pidlFQ;
249 sei.lpClass = "Folder";
250 sei.hwnd = hwnd;
251 sei.nShow = SW_SHOWNORMAL;
252 sei.lpVerb = verb;
253 ShellExecuteExA(&sei);
254 SHFree(pidlFQ);
257 /**************************************************************************
258 * DoDelete
260 * deletes the currently selected items
262 static void DoDelete(ContextMenu *This)
264 ISFHelper *helper;
266 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
267 if (helper)
269 ISFHelper_DeleteItems(helper, This->cidl, (LPCITEMIDLIST*)This->apidl);
270 ISFHelper_Release(helper);
274 /**************************************************************************
275 * DoCopyOrCut
277 * copies the currently selected items into the clipboard
279 static void DoCopyOrCut(ContextMenu *This, HWND hwnd, BOOL cut)
281 IDataObject *dataobject;
283 TRACE("(%p)->(wnd=%p, cut=%d)\n", This, hwnd, cut);
285 if (SUCCEEDED(IShellFolder_GetUIObjectOf(This->parent, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl, &IID_IDataObject, 0, (void**)&dataobject)))
287 OleSetClipboard(dataobject);
288 IDataObject_Release(dataobject);
292 /**************************************************************************
293 * Properties_AddPropSheetCallback
295 * Used by DoOpenProperties through SHCreatePropSheetExtArrayEx to add
296 * propertysheet pages from shell extensions.
298 static BOOL CALLBACK Properties_AddPropSheetCallback(HPROPSHEETPAGE hpage, LPARAM lparam)
300 LPPROPSHEETHEADERW psh = (LPPROPSHEETHEADERW) lparam;
301 psh->u3.phpage[psh->nPages++] = hpage;
303 return TRUE;
306 static BOOL format_date(FILETIME *time, WCHAR *buffer, DWORD size)
308 FILETIME ft;
309 SYSTEMTIME st;
310 int ret;
312 if (!FileTimeToLocalFileTime(time, &ft))
313 return FALSE;
315 if (!FileTimeToSystemTime(&ft, &st))
316 return FALSE;
318 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buffer, size);
319 if (ret)
321 buffer[ret - 1] = ' ';
322 ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buffer + ret , size - ret);
324 return ret != 0;
327 static BOOL get_program_description(WCHAR *path, WCHAR *buffer, DWORD size)
329 static const WCHAR translationW[] = {
330 '\\','V','a','r','F','i','l','e','I','n','f','o',
331 '\\','T','r','a','n','s','l','a','t','i','o','n',0
333 static const WCHAR fileDescFmtW[] = {
334 '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
335 '\\','%','0','4','x','%','0','4','x',
336 '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0
338 WCHAR fileDescW[41], *desc;
339 DWORD versize, *lang;
340 UINT dlen, llen, i;
341 BOOL ret = FALSE;
342 PVOID data;
344 versize = GetFileVersionInfoSizeW(path, NULL);
345 if (!versize) return FALSE;
347 data = heap_alloc(versize);
348 if (!data) return FALSE;
350 if (!GetFileVersionInfoW(path, 0, versize, data))
351 goto out;
353 if (!VerQueryValueW(data, translationW, (LPVOID *)&lang, &llen))
354 goto out;
356 for (i = 0; i < llen / sizeof(DWORD); i++)
358 sprintfW(fileDescW, fileDescFmtW, LOWORD(lang[i]), HIWORD(lang[i]));
359 if (VerQueryValueW(data, fileDescW, (LPVOID *)&desc, &dlen))
361 if (dlen > size - 1) dlen = size - 1;
362 memcpy(buffer, desc, dlen * sizeof(WCHAR));
363 buffer[dlen] = 0;
364 ret = TRUE;
365 break;
369 out:
370 heap_free(data);
371 return ret;
374 struct file_properties_info
376 WCHAR path[MAX_PATH];
377 WCHAR dir[MAX_PATH];
378 WCHAR *filename;
379 DWORD attrib;
382 static void init_file_properties_dlg(HWND hwndDlg, struct file_properties_info *props)
384 WCHAR buffer[MAX_PATH], buffer2[MAX_PATH];
385 WIN32_FILE_ATTRIBUTE_DATA exinfo;
386 SHFILEINFOW shinfo;
388 SetDlgItemTextW(hwndDlg, IDC_FPROP_PATH, props->filename);
389 SetDlgItemTextW(hwndDlg, IDC_FPROP_LOCATION, props->dir);
391 if (SHGetFileInfoW(props->path, 0, &shinfo, sizeof(shinfo), SHGFI_TYPENAME|SHGFI_ICON))
393 if (shinfo.hIcon)
395 SendDlgItemMessageW(hwndDlg, IDC_FPROP_ICON, STM_SETICON, (WPARAM)shinfo.hIcon, 0);
396 DestroyIcon(shinfo.hIcon);
398 if (shinfo.szTypeName[0])
399 SetDlgItemTextW(hwndDlg, IDC_FPROP_TYPE, shinfo.szTypeName);
402 if (!GetFileAttributesExW(props->path, GetFileExInfoStandard, &exinfo))
403 return;
405 if (format_date(&exinfo.ftCreationTime, buffer, ARRAY_SIZE(buffer)))
406 SetDlgItemTextW(hwndDlg, IDC_FPROP_CREATED, buffer);
408 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
409 SendDlgItemMessageW(hwndDlg, IDC_FPROP_READONLY, BM_SETCHECK, BST_CHECKED, 0);
410 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
411 SendDlgItemMessageW(hwndDlg, IDC_FPROP_HIDDEN, BM_SETCHECK, BST_CHECKED, 0);
412 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
413 SendDlgItemMessageW(hwndDlg, IDC_FPROP_ARCHIVE, BM_SETCHECK, BST_CHECKED, 0);
415 if (exinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
417 static const WCHAR unknownW[] = {'(','u','n','k','n','o','w','n',')',0};
418 SetDlgItemTextW(hwndDlg, IDC_FPROP_SIZE, unknownW);
420 /* TODO: Implement counting for directories */
421 return;
424 /* Information about files only */
425 StrFormatByteSizeW(((LONGLONG)exinfo.nFileSizeHigh << 32) | exinfo.nFileSizeLow,
426 buffer, ARRAY_SIZE(buffer));
427 SetDlgItemTextW(hwndDlg, IDC_FPROP_SIZE, buffer);
429 if (format_date(&exinfo.ftLastWriteTime, buffer, ARRAY_SIZE(buffer)))
430 SetDlgItemTextW(hwndDlg, IDC_FPROP_MODIFIED, buffer);
431 if (format_date(&exinfo.ftLastAccessTime, buffer, ARRAY_SIZE(buffer)))
432 SetDlgItemTextW(hwndDlg, IDC_FPROP_ACCESSED, buffer);
434 if (FindExecutableW(props->path, NULL, buffer) <= (HINSTANCE)32)
435 return;
437 /* Information about executables */
438 if (SHGetFileInfoW(buffer, 0, &shinfo, sizeof(shinfo), SHGFI_ICON | SHGFI_SMALLICON) && shinfo.hIcon)
439 SendDlgItemMessageW(hwndDlg, IDC_FPROP_PROG_ICON, STM_SETICON, (WPARAM)shinfo.hIcon, 0);
441 if (get_program_description(buffer, buffer2, ARRAY_SIZE(buffer2)))
442 SetDlgItemTextW(hwndDlg, IDC_FPROP_PROG_NAME, buffer2);
443 else
445 WCHAR *p = strrchrW(buffer, '\\');
446 SetDlgItemTextW(hwndDlg, IDC_FPROP_PROG_NAME, p ? ++p : buffer);
450 static INT_PTR CALLBACK file_properties_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
452 switch (uMsg)
454 case WM_INITDIALOG:
456 LPPROPSHEETPAGEW page = (LPPROPSHEETPAGEW)lParam;
457 SetWindowLongPtrW(hwndDlg, DWLP_USER, (LONG_PTR)page->lParam);
458 init_file_properties_dlg(hwndDlg, (struct file_properties_info *)page->lParam);
459 break;
462 case WM_COMMAND:
463 if (LOWORD(wParam) == IDC_FPROP_PROG_CHANGE)
465 /* TODO: Implement file association dialog */
466 MessageBoxA(hwndDlg, "Not implemented yet.", "Error", MB_OK | MB_ICONEXCLAMATION);
468 else if (LOWORD(wParam) == IDC_FPROP_READONLY ||
469 LOWORD(wParam) == IDC_FPROP_HIDDEN ||
470 LOWORD(wParam) == IDC_FPROP_ARCHIVE)
472 SendMessageW(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
474 else if (LOWORD(wParam) == IDC_FPROP_PATH && HIWORD(wParam) == EN_CHANGE)
476 SendMessageW(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
478 break;
480 case WM_NOTIFY:
482 LPPSHNOTIFY notify = (LPPSHNOTIFY)lParam;
483 if (notify->hdr.code == PSN_APPLY)
485 struct file_properties_info *props = (struct file_properties_info *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
486 WCHAR newname[MAX_PATH], newpath[MAX_PATH];
487 DWORD attributes;
489 attributes = GetFileAttributesW(props->path);
490 if (attributes != INVALID_FILE_ATTRIBUTES)
492 attributes &= ~(FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_ARCHIVE);
494 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_READONLY, BM_GETCHECK, 0, 0) == BST_CHECKED)
495 attributes |= FILE_ATTRIBUTE_READONLY;
496 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_HIDDEN, BM_GETCHECK, 0, 0) == BST_CHECKED)
497 attributes |= FILE_ATTRIBUTE_HIDDEN;
498 if (SendDlgItemMessageW(hwndDlg, IDC_FPROP_ARCHIVE, BM_GETCHECK, 0, 0) == BST_CHECKED)
499 attributes |= FILE_ATTRIBUTE_ARCHIVE;
501 if (!SetFileAttributesW(props->path, attributes))
502 ERR("failed to update file attributes of %s\n", debugstr_w(props->path));
505 /* Update filename if it was changed */
506 if (GetDlgItemTextW(hwndDlg, IDC_FPROP_PATH, newname, ARRAY_SIZE(newname)) &&
507 strcmpW(props->filename, newname) &&
508 strlenW(props->dir) + strlenW(newname) + 2 < ARRAY_SIZE(newpath))
510 static const WCHAR slash[] = {'\\', 0};
511 strcpyW(newpath, props->dir);
512 strcatW(newpath, slash);
513 strcatW(newpath, newname);
515 if (!MoveFileW(props->path, newpath))
516 ERR("failed to move file %s to %s\n", debugstr_w(props->path), debugstr_w(newpath));
517 else
519 WCHAR *p;
520 strcpyW(props->path, newpath);
521 strcpyW(props->dir, newpath);
522 if ((p = strrchrW(props->dir, '\\')))
524 *p = 0;
525 props->filename = p + 1;
527 else
528 props->filename = props->dir;
529 SetDlgItemTextW(hwndDlg, IDC_FPROP_LOCATION, props->dir);
533 return TRUE;
536 break;
538 default:
539 break;
541 return FALSE;
544 static UINT CALLBACK file_properties_callback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGEW page)
546 struct file_properties_info *props = (struct file_properties_info *)page->lParam;
547 if (uMsg == PSPCB_RELEASE)
549 heap_free(props);
551 return 1;
554 static void init_file_properties_pages(IDataObject *dataobject, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
556 struct file_properties_info *props;
557 HPROPSHEETPAGE general_page;
558 PROPSHEETPAGEW propsheet;
559 FORMATETC format;
560 STGMEDIUM stgm;
561 HRESULT hr;
562 WCHAR *p;
564 props = heap_alloc(sizeof(*props));
565 if (!props) return;
567 format.cfFormat = CF_HDROP;
568 format.ptd = NULL;
569 format.dwAspect = DVASPECT_CONTENT;
570 format.lindex = -1;
571 format.tymed = TYMED_HGLOBAL;
573 hr = IDataObject_GetData(dataobject, &format, &stgm);
574 if (FAILED(hr)) goto error;
576 if (!DragQueryFileW((HDROP)stgm.u.hGlobal, 0, props->path, ARRAY_SIZE(props->path)))
578 ReleaseStgMedium(&stgm);
579 goto error;
582 ReleaseStgMedium(&stgm);
584 props->attrib = GetFileAttributesW(props->path);
585 if (props->attrib == INVALID_FILE_ATTRIBUTES)
586 goto error;
588 strcpyW(props->dir, props->path);
589 if ((p = strrchrW(props->dir, '\\')))
591 *p = 0;
592 props->filename = p + 1;
594 else
595 props->filename = props->dir;
597 memset(&propsheet, 0, sizeof(propsheet));
598 propsheet.dwSize = sizeof(propsheet);
599 propsheet.dwFlags = PSP_DEFAULT | PSP_USECALLBACK;
600 propsheet.hInstance = shell32_hInstance;
601 if (props->attrib & FILE_ATTRIBUTE_DIRECTORY)
602 propsheet.u.pszTemplate = (LPWSTR)MAKEINTRESOURCE(IDD_FOLDER_PROPERTIES);
603 else
604 propsheet.u.pszTemplate = (LPWSTR)MAKEINTRESOURCE(IDD_FILE_PROPERTIES);
605 propsheet.pfnDlgProc = file_properties_proc;
606 propsheet.pfnCallback = file_properties_callback;
607 propsheet.lParam = (LPARAM)props;
609 general_page = CreatePropertySheetPageW(&propsheet);
610 if (general_page)
611 lpfnAddPage(general_page, lParam);
612 return;
614 error:
615 heap_free(props);
618 #define MAX_PROP_PAGES 99
620 static void DoOpenProperties(ContextMenu *This, HWND hwnd)
622 static const WCHAR wszFolder[] = {'F','o','l','d','e','r', 0};
623 static const WCHAR wszFiletypeAll[] = {'*',0};
624 LPSHELLFOLDER lpDesktopSF;
625 LPSHELLFOLDER lpSF;
626 LPDATAOBJECT lpDo;
627 WCHAR wszFiletype[MAX_PATH];
628 WCHAR wszFilename[MAX_PATH];
629 PROPSHEETHEADERW psh;
630 HPROPSHEETPAGE hpages[MAX_PROP_PAGES];
631 HPSXA hpsxa;
632 UINT ret;
634 TRACE("(%p)->(wnd=%p)\n", This, hwnd);
636 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
637 psh.dwSize = sizeof (PROPSHEETHEADERW);
638 psh.hwndParent = hwnd;
639 psh.dwFlags = PSH_PROPTITLE;
640 psh.nPages = 0;
641 psh.u3.phpage = hpages;
642 psh.u2.nStartPage = 0;
644 _ILSimpleGetTextW(This->apidl[0], (LPVOID)wszFilename, MAX_PATH);
645 psh.pszCaption = (LPCWSTR)wszFilename;
647 /* Find out where to look for the shell extensions */
648 if (_ILIsValue(This->apidl[0]))
650 char sTemp[64];
651 sTemp[0] = 0;
652 if (_ILGetExtension(This->apidl[0], sTemp, 64))
654 HCR_MapTypeToValueA(sTemp, sTemp, 64, TRUE);
655 MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wszFiletype, MAX_PATH);
657 else
659 wszFiletype[0] = 0;
662 else if (_ILIsFolder(This->apidl[0]))
664 lstrcpynW(wszFiletype, wszFolder, 64);
666 else if (_ILIsSpecialFolder(This->apidl[0]))
668 LPGUID folderGUID;
669 static const WCHAR wszclsid[] = {'C','L','S','I','D','\\', 0};
670 folderGUID = _ILGetGUIDPointer(This->apidl[0]);
671 lstrcpyW(wszFiletype, wszclsid);
672 StringFromGUID2(folderGUID, &wszFiletype[6], MAX_PATH - 6);
674 else
676 FIXME("Requested properties for unknown type.\n");
677 return;
680 /* Get a suitable DataObject for accessing the files */
681 SHGetDesktopFolder(&lpDesktopSF);
682 if (_ILIsPidlSimple(This->pidl))
684 ret = IShellFolder_GetUIObjectOf(lpDesktopSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
685 &IID_IDataObject, NULL, (LPVOID *)&lpDo);
686 IShellFolder_Release(lpDesktopSF);
688 else
690 IShellFolder_BindToObject(lpDesktopSF, This->pidl, NULL, &IID_IShellFolder, (LPVOID*) &lpSF);
691 ret = IShellFolder_GetUIObjectOf(lpSF, hwnd, This->cidl, (LPCITEMIDLIST*)This->apidl,
692 &IID_IDataObject, NULL, (LPVOID *)&lpDo);
693 IShellFolder_Release(lpSF);
694 IShellFolder_Release(lpDesktopSF);
697 if (SUCCEEDED(ret))
699 init_file_properties_pages(lpDo, Properties_AddPropSheetCallback, (LPARAM)&psh);
701 hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletype, MAX_PROP_PAGES - psh.nPages, lpDo);
702 if (hpsxa != NULL)
704 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
705 SHDestroyPropSheetExtArray(hpsxa);
707 hpsxa = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, wszFiletypeAll, MAX_PROP_PAGES - psh.nPages, lpDo);
708 if (hpsxa != NULL)
710 SHAddFromPropSheetExtArray(hpsxa, Properties_AddPropSheetCallback, (LPARAM)&psh);
711 SHDestroyPropSheetExtArray(hpsxa);
713 IDataObject_Release(lpDo);
716 if (psh.nPages)
717 PropertySheetW(&psh);
718 else
719 FIXME("No property pages found.\n");
722 static HRESULT WINAPI ItemMenu_InvokeCommand(
723 IContextMenu3 *iface,
724 LPCMINVOKECOMMANDINFO lpcmi)
726 ContextMenu *This = impl_from_IContextMenu3(iface);
728 if (lpcmi->cbSize != sizeof(CMINVOKECOMMANDINFO))
729 FIXME("Is an EX structure\n");
731 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
733 if (IS_INTRESOURCE(lpcmi->lpVerb) && LOWORD(lpcmi->lpVerb) > FCIDM_SHVIEWLAST)
735 TRACE("Invalid Verb %x\n", LOWORD(lpcmi->lpVerb));
736 return E_INVALIDARG;
739 if (IS_INTRESOURCE(lpcmi->lpVerb))
741 switch(LOWORD(lpcmi->lpVerb))
743 case FCIDM_SHVIEW_EXPLORE:
744 TRACE("Verb FCIDM_SHVIEW_EXPLORE\n");
745 DoOpenExplore(This, lpcmi->hwnd, "explore");
746 break;
747 case FCIDM_SHVIEW_OPEN:
748 TRACE("Verb FCIDM_SHVIEW_OPEN\n");
749 DoOpenExplore(This, lpcmi->hwnd, "open");
750 break;
751 case FCIDM_SHVIEW_RENAME:
753 IShellBrowser *browser;
755 /* get the active IShellView */
756 browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
757 if (browser)
759 IShellView *view;
761 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
763 TRACE("(shellview=%p)\n", view);
764 IShellView_SelectItem(view, This->apidl[0],
765 SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT);
766 IShellView_Release(view);
769 break;
771 case FCIDM_SHVIEW_DELETE:
772 TRACE("Verb FCIDM_SHVIEW_DELETE\n");
773 DoDelete(This);
774 break;
775 case FCIDM_SHVIEW_COPY:
776 TRACE("Verb FCIDM_SHVIEW_COPY\n");
777 DoCopyOrCut(This, lpcmi->hwnd, FALSE);
778 break;
779 case FCIDM_SHVIEW_CUT:
780 TRACE("Verb FCIDM_SHVIEW_CUT\n");
781 DoCopyOrCut(This, lpcmi->hwnd, TRUE);
782 break;
783 case FCIDM_SHVIEW_PROPERTIES:
784 TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
785 DoOpenProperties(This, lpcmi->hwnd);
786 break;
787 default:
788 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb));
789 return E_INVALIDARG;
792 else
794 TRACE("Verb is %s\n",debugstr_a(lpcmi->lpVerb));
795 if (strcmp(lpcmi->lpVerb,"delete")==0)
796 DoDelete(This);
797 else if (strcmp(lpcmi->lpVerb,"properties")==0)
798 DoOpenProperties(This, lpcmi->hwnd);
799 else {
800 FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi->lpVerb));
801 return E_FAIL;
804 return S_OK;
807 static HRESULT WINAPI ItemMenu_GetCommandString(IContextMenu3 *iface, UINT_PTR cmdid, UINT flags,
808 UINT *reserved, LPSTR name, UINT maxlen)
810 static const WCHAR openW[] = {'o','p','e','n',0};
811 static const WCHAR exploreW[] = {'e','x','p','l','o','r','e',0};
812 static const WCHAR cutW[] = {'c','u','t',0};
813 static const WCHAR copyW[] = {'c','o','p','y',0};
814 static const WCHAR linkW[] = {'l','i','n','k',0};
815 static const WCHAR deleteW[] = {'d','e','l','e','t','e',0};
816 static const WCHAR propertiesW[] = {'p','r','o','p','e','r','t','i','e','s',0};
817 static const WCHAR renameW[] = {'r','e','n','a','m','e',0};
818 ContextMenu *This = impl_from_IContextMenu3(iface);
819 const WCHAR *cmdW = NULL;
820 HRESULT hr = S_OK;
822 TRACE("(%p)->(%lx, %#x, %p, %p, %u)\n", This, cmdid, flags, reserved, name, maxlen);
824 switch (flags)
826 case GCS_HELPTEXTA:
827 case GCS_HELPTEXTW:
828 hr = E_NOTIMPL;
829 break;
831 case GCS_VERBA:
832 case GCS_VERBW:
833 switch (cmdid)
835 case FCIDM_SHVIEW_OPEN:
836 cmdW = openW;
837 break;
838 case FCIDM_SHVIEW_EXPLORE:
839 cmdW = exploreW;
840 break;
841 case FCIDM_SHVIEW_CUT:
842 cmdW = cutW;
843 break;
844 case FCIDM_SHVIEW_COPY:
845 cmdW = copyW;
846 break;
847 case FCIDM_SHVIEW_CREATELINK:
848 cmdW = linkW;
849 break;
850 case FCIDM_SHVIEW_DELETE:
851 cmdW = deleteW;
852 break;
853 case FCIDM_SHVIEW_PROPERTIES:
854 cmdW = propertiesW;
855 break;
856 case FCIDM_SHVIEW_RENAME:
857 cmdW = renameW;
858 break;
861 if (!cmdW)
863 hr = E_INVALIDARG;
864 break;
867 if (flags == GCS_VERBA)
868 WideCharToMultiByte(CP_ACP, 0, cmdW, -1, name, maxlen, NULL, NULL);
869 else
870 lstrcpynW((WCHAR *)name, cmdW, maxlen);
872 TRACE("name %s\n", flags == GCS_VERBA ? debugstr_a(name) : debugstr_w((WCHAR *)name));
873 break;
875 case GCS_VALIDATEA:
876 case GCS_VALIDATEW:
877 break;
880 return hr;
883 /**************************************************************************
884 * NOTES
885 * should be only in IContextMenu2 and IContextMenu3
886 * is nevertheless called from word95
888 static HRESULT WINAPI ContextMenu_HandleMenuMsg(IContextMenu3 *iface, UINT msg,
889 WPARAM wParam, LPARAM lParam)
891 ContextMenu *This = impl_from_IContextMenu3(iface);
892 FIXME("(%p)->(0x%x 0x%lx 0x%lx): stub\n", This, msg, wParam, lParam);
893 return E_NOTIMPL;
896 static HRESULT WINAPI ContextMenu_HandleMenuMsg2(IContextMenu3 *iface, UINT msg,
897 WPARAM wParam, LPARAM lParam, LRESULT *result)
899 ContextMenu *This = impl_from_IContextMenu3(iface);
900 FIXME("(%p)->(0x%x 0x%lx 0x%lx %p): stub\n", This, msg, wParam, lParam, result);
901 return E_NOTIMPL;
904 static const IContextMenu3Vtbl ItemContextMenuVtbl =
906 ContextMenu_QueryInterface,
907 ContextMenu_AddRef,
908 ContextMenu_Release,
909 ItemMenu_QueryContextMenu,
910 ItemMenu_InvokeCommand,
911 ItemMenu_GetCommandString,
912 ContextMenu_HandleMenuMsg,
913 ContextMenu_HandleMenuMsg2
916 static HRESULT WINAPI ShellExtInit_QueryInterface(IShellExtInit *iface, REFIID riid, void **obj)
918 ContextMenu *This = impl_from_IShellExtInit(iface);
919 return IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, obj);
922 static ULONG WINAPI ShellExtInit_AddRef(IShellExtInit *iface)
924 ContextMenu *This = impl_from_IShellExtInit(iface);
925 return IContextMenu3_AddRef(&This->IContextMenu3_iface);
928 static ULONG WINAPI ShellExtInit_Release(IShellExtInit *iface)
930 ContextMenu *This = impl_from_IShellExtInit(iface);
931 return IContextMenu3_Release(&This->IContextMenu3_iface);
934 static HRESULT WINAPI ShellExtInit_Initialize(IShellExtInit *iface, LPCITEMIDLIST folder,
935 IDataObject *dataobj, HKEY progidkey)
937 ContextMenu *This = impl_from_IShellExtInit(iface);
939 FIXME("(%p)->(%p %p %p): stub\n", This, folder, dataobj, progidkey);
941 return E_NOTIMPL;
944 static const IShellExtInitVtbl ShellExtInitVtbl =
946 ShellExtInit_QueryInterface,
947 ShellExtInit_AddRef,
948 ShellExtInit_Release,
949 ShellExtInit_Initialize
952 static HRESULT WINAPI ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID riid, void **obj)
954 ContextMenu *This = impl_from_IObjectWithSite(iface);
955 return IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, obj);
958 static ULONG WINAPI ObjectWithSite_AddRef(IObjectWithSite *iface)
960 ContextMenu *This = impl_from_IObjectWithSite(iface);
961 return IContextMenu3_AddRef(&This->IContextMenu3_iface);
964 static ULONG WINAPI ObjectWithSite_Release(IObjectWithSite *iface)
966 ContextMenu *This = impl_from_IObjectWithSite(iface);
967 return IContextMenu3_Release(&This->IContextMenu3_iface);
970 static HRESULT WINAPI ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *site)
972 ContextMenu *This = impl_from_IObjectWithSite(iface);
974 FIXME("(%p)->(%p): stub\n", This, site);
976 return E_NOTIMPL;
979 static HRESULT WINAPI ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID riid, void **site)
981 ContextMenu *This = impl_from_IObjectWithSite(iface);
983 FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), site);
985 return E_NOTIMPL;
988 static const IObjectWithSiteVtbl ObjectWithSiteVtbl =
990 ObjectWithSite_QueryInterface,
991 ObjectWithSite_AddRef,
992 ObjectWithSite_Release,
993 ObjectWithSite_SetSite,
994 ObjectWithSite_GetSite,
997 HRESULT ItemMenu_Constructor(IShellFolder *parent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *apidl, UINT cidl,
998 REFIID riid, void **pObj)
1000 ContextMenu* This;
1001 HRESULT hr;
1002 UINT i;
1004 This = heap_alloc(sizeof(*This));
1005 if (!This) return E_OUTOFMEMORY;
1007 This->IContextMenu3_iface.lpVtbl = &ItemContextMenuVtbl;
1008 This->IShellExtInit_iface.lpVtbl = &ShellExtInitVtbl;
1009 This->IObjectWithSite_iface.lpVtbl = &ObjectWithSiteVtbl;
1010 This->ref = 1;
1011 This->parent = parent;
1012 if (parent) IShellFolder_AddRef(parent);
1014 This->pidl = ILClone(pidl);
1015 This->apidl = _ILCopyaPidl(apidl, cidl);
1016 This->cidl = cidl;
1017 This->allvalues = TRUE;
1019 This->desktop = FALSE;
1021 for (i = 0; i < cidl; i++)
1022 This->allvalues &= (_ILIsValue(apidl[i]) ? 1 : 0);
1024 hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
1025 IContextMenu3_Release(&This->IContextMenu3_iface);
1027 return hr;
1030 /* Background menu implementation */
1031 static HRESULT WINAPI BackgroundMenu_QueryContextMenu(
1032 IContextMenu3 *iface,
1033 HMENU hMenu,
1034 UINT indexMenu,
1035 UINT idCmdFirst,
1036 UINT idCmdLast,
1037 UINT uFlags)
1039 ContextMenu *This = impl_from_IContextMenu3(iface);
1040 HMENU hMyMenu;
1041 UINT idMax;
1042 HRESULT hr;
1044 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
1045 This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
1047 hMyMenu = LoadMenuA(shell32_hInstance, "MENU_002");
1048 if (uFlags & CMF_DEFAULTONLY)
1050 HMENU ourMenu = GetSubMenu(hMyMenu,0);
1051 UINT oldDef = GetMenuDefaultItem(hMenu,TRUE,GMDI_USEDISABLED);
1052 UINT newDef = GetMenuDefaultItem(ourMenu,TRUE,GMDI_USEDISABLED);
1053 if (newDef != oldDef)
1054 SetMenuDefaultItem(hMenu,newDef,TRUE);
1055 if (newDef!=0xFFFFFFFF)
1056 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, newDef+1);
1057 else
1058 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
1060 else
1062 idMax = Shell_MergeMenus (hMenu, GetSubMenu(hMyMenu,0), indexMenu,
1063 idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS);
1064 hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst);
1066 DestroyMenu(hMyMenu);
1068 TRACE("(%p)->returning 0x%x\n",This,hr);
1069 return hr;
1072 static void DoNewFolder(ContextMenu *This, IShellView *view)
1074 ISFHelper *helper;
1076 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&helper);
1077 if (helper)
1079 WCHAR nameW[MAX_PATH];
1080 LPITEMIDLIST pidl;
1082 ISFHelper_GetUniqueName(helper, nameW, MAX_PATH);
1083 ISFHelper_AddFolder(helper, 0, nameW, &pidl);
1085 if (view)
1087 /* if we are in a shellview do labeledit */
1088 IShellView_SelectItem(view,
1089 pidl,(SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE
1090 |SVSI_FOCUSED|SVSI_SELECT));
1093 SHFree(pidl);
1094 ISFHelper_Release(helper);
1098 static BOOL DoPaste(ContextMenu *This)
1100 BOOL bSuccess = FALSE;
1101 IDataObject * pda;
1103 TRACE("\n");
1105 if(SUCCEEDED(OleGetClipboard(&pda)))
1107 STGMEDIUM medium;
1108 FORMATETC formatetc;
1110 TRACE("pda=%p\n", pda);
1112 /* Set the FORMATETC structure*/
1113 InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLISTW), TYMED_HGLOBAL);
1115 /* Get the pidls from IDataObject */
1116 if(SUCCEEDED(IDataObject_GetData(pda,&formatetc,&medium)))
1118 LPITEMIDLIST * apidl;
1119 LPITEMIDLIST pidl;
1120 IShellFolder *psfFrom = NULL, *psfDesktop;
1122 LPIDA lpcida = GlobalLock(medium.u.hGlobal);
1123 TRACE("cida=%p\n", lpcida);
1125 apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
1127 /* bind to the source shellfolder */
1128 SHGetDesktopFolder(&psfDesktop);
1129 if(psfDesktop)
1131 IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (LPVOID*)&psfFrom);
1132 IShellFolder_Release(psfDesktop);
1135 if (psfFrom)
1137 /* get source and destination shellfolder */
1138 ISFHelper *psfhlpdst, *psfhlpsrc;
1139 IShellFolder_QueryInterface(This->parent, &IID_ISFHelper, (void**)&psfhlpdst);
1140 IShellFolder_QueryInterface(psfFrom, &IID_ISFHelper, (void**)&psfhlpsrc);
1142 /* do the copy/move */
1143 if (psfhlpdst && psfhlpsrc)
1145 ISFHelper_CopyItems(psfhlpdst, psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
1146 /* FIXME handle move
1147 ISFHelper_DeleteItems(psfhlpsrc, lpcida->cidl, apidl);
1150 if(psfhlpdst) ISFHelper_Release(psfhlpdst);
1151 if(psfhlpsrc) ISFHelper_Release(psfhlpsrc);
1152 IShellFolder_Release(psfFrom);
1155 _ILFreeaPidl(apidl, lpcida->cidl);
1156 SHFree(pidl);
1158 /* release the medium*/
1159 ReleaseStgMedium(&medium);
1161 IDataObject_Release(pda);
1163 #if 0
1164 HGLOBAL hMem;
1166 OpenClipboard(NULL);
1167 hMem = GetClipboardData(CF_HDROP);
1169 if(hMem)
1171 char * pDropFiles = GlobalLock(hMem);
1172 if(pDropFiles)
1174 int len, offset = sizeof(DROPFILESTRUCT);
1176 while( pDropFiles[offset] != 0)
1178 len = strlen(pDropFiles + offset);
1179 TRACE("%s\n", pDropFiles + offset);
1180 offset += len+1;
1183 GlobalUnlock(hMem);
1185 CloseClipboard();
1186 #endif
1187 return bSuccess;
1190 static HRESULT WINAPI BackgroundMenu_InvokeCommand(
1191 IContextMenu3 *iface,
1192 LPCMINVOKECOMMANDINFO lpcmi)
1194 ContextMenu *This = impl_from_IContextMenu3(iface);
1195 IShellBrowser *browser;
1196 IShellView *view = NULL;
1197 HWND hWnd = NULL;
1199 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", This, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
1201 /* get the active IShellView */
1202 if ((browser = (IShellBrowser*)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0)))
1204 if (SUCCEEDED(IShellBrowser_QueryActiveShellView(browser, &view)))
1205 IShellView_GetWindow(view, &hWnd);
1208 if(HIWORD(lpcmi->lpVerb))
1210 TRACE("%s\n", debugstr_a(lpcmi->lpVerb));
1212 if (!strcmp(lpcmi->lpVerb, CMDSTR_NEWFOLDERA))
1214 DoNewFolder(This, view);
1216 else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWLISTA))
1218 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_LISTVIEW, 0), 0);
1220 else if (!strcmp(lpcmi->lpVerb, CMDSTR_VIEWDETAILSA))
1222 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(FCIDM_SHVIEW_REPORTVIEW, 0), 0);
1224 else
1226 FIXME("please report: unknown verb %s\n", debugstr_a(lpcmi->lpVerb));
1229 else
1231 switch (LOWORD(lpcmi->lpVerb))
1233 case FCIDM_SHVIEW_REFRESH:
1234 if (view) IShellView_Refresh(view);
1235 break;
1237 case FCIDM_SHVIEW_NEWFOLDER:
1238 DoNewFolder(This, view);
1239 break;
1241 case FCIDM_SHVIEW_INSERT:
1242 DoPaste(This);
1243 break;
1245 case FCIDM_SHVIEW_PROPERTIES:
1246 if (This->desktop) {
1247 ShellExecuteA(lpcmi->hwnd, "open", "rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL);
1248 } else {
1249 FIXME("launch item properties dialog\n");
1251 break;
1253 default:
1254 /* if it's an id just pass it to the parent shv */
1255 if (hWnd) SendMessageA(hWnd, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
1256 break;
1260 if (view)
1261 IShellView_Release(view);
1263 return S_OK;
1266 static HRESULT WINAPI BackgroundMenu_GetCommandString(
1267 IContextMenu3 *iface,
1268 UINT_PTR idCommand,
1269 UINT uFlags,
1270 UINT* lpReserved,
1271 LPSTR lpszName,
1272 UINT uMaxNameLen)
1274 ContextMenu *This = impl_from_IContextMenu3(iface);
1276 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
1278 /* test the existence of the menu items, the file dialog enables
1279 the buttons according to this */
1280 if (uFlags == GCS_VALIDATEA)
1282 if(HIWORD(idCommand))
1284 if (!strcmp((LPSTR)idCommand, CMDSTR_VIEWLISTA) ||
1285 !strcmp((LPSTR)idCommand, CMDSTR_VIEWDETAILSA) ||
1286 !strcmp((LPSTR)idCommand, CMDSTR_NEWFOLDERA))
1288 return S_OK;
1293 FIXME("unknown command string\n");
1294 return E_FAIL;
1297 static const IContextMenu3Vtbl BackgroundContextMenuVtbl =
1299 ContextMenu_QueryInterface,
1300 ContextMenu_AddRef,
1301 ContextMenu_Release,
1302 BackgroundMenu_QueryContextMenu,
1303 BackgroundMenu_InvokeCommand,
1304 BackgroundMenu_GetCommandString,
1305 ContextMenu_HandleMenuMsg,
1306 ContextMenu_HandleMenuMsg2
1309 HRESULT BackgroundMenu_Constructor(IShellFolder *parent, BOOL desktop, REFIID riid, void **pObj)
1311 ContextMenu *This;
1312 HRESULT hr;
1314 This = heap_alloc(sizeof(*This));
1315 if (!This) return E_OUTOFMEMORY;
1317 This->IContextMenu3_iface.lpVtbl = &BackgroundContextMenuVtbl;
1318 This->IShellExtInit_iface.lpVtbl = &ShellExtInitVtbl;
1319 This->IObjectWithSite_iface.lpVtbl = &ObjectWithSiteVtbl;
1320 This->ref = 1;
1321 This->parent = parent;
1323 This->pidl = NULL;
1324 This->apidl = NULL;
1325 This->cidl = 0;
1326 This->allvalues = FALSE;
1328 This->desktop = desktop;
1329 if (parent) IShellFolder_AddRef(parent);
1331 hr = IContextMenu3_QueryInterface(&This->IContextMenu3_iface, riid, pObj);
1332 IContextMenu3_Release(&This->IContextMenu3_iface);
1334 return hr;