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
25 #define NONAMELESSUNION
32 #include "undocshell.h"
37 #include "shell32_main.h"
38 #include "shellfolder.h"
43 #include "wine/heap.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
50 IContextMenu3 IContextMenu3_iface
;
51 IShellExtInit IShellExtInit_iface
;
52 IObjectWithSite IObjectWithSite_iface
;
58 LPITEMIDLIST pidl
; /* root pidl */
59 LPITEMIDLIST
*apidl
; /* array of child pidls */
63 /* background menu data */
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
);
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
;
108 IContextMenu3_AddRef(iface
);
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
);
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
);
134 IShellFolder_Release(This
->parent
);
137 _ILFreeaPidl(This
->apidl
, This
->cidl
);
145 static HRESULT WINAPI
ItemMenu_QueryContextMenu(
146 IContextMenu3
*iface
,
153 ContextMenu
*This
= impl_from_IContextMenu3(iface
);
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
);
173 mi
.cbSize
= sizeof(mi
);
174 mi
.fMask
= MIIM_ID
| MIIM_STRING
| MIIM_FTYPE
;
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
;
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
);
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
;
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 /**************************************************************************
222 static void DoOpenExplore(ContextMenu
*This
, HWND hwnd
, LPCSTR verb
)
225 BOOL bFolderFound
= FALSE
;
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
]))
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";
251 sei
.nShow
= SW_SHOWNORMAL
;
253 ShellExecuteExA(&sei
);
257 /**************************************************************************
260 * deletes the currently selected items
262 static void DoDelete(ContextMenu
*This
)
266 IShellFolder_QueryInterface(This
->parent
, &IID_ISFHelper
, (void**)&helper
);
269 ISFHelper_DeleteItems(helper
, This
->cidl
, (LPCITEMIDLIST
*)This
->apidl
);
270 ISFHelper_Release(helper
);
274 /**************************************************************************
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
;
306 static BOOL
format_date(FILETIME
*time
, WCHAR
*buffer
, DWORD size
)
312 if (!FileTimeToLocalFileTime(time
, &ft
))
315 if (!FileTimeToSystemTime(&ft
, &st
))
318 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_LONGDATE
, &st
, NULL
, buffer
, size
);
321 buffer
[ret
- 1] = ' ';
322 ret
= GetTimeFormatW(LOCALE_USER_DEFAULT
, 0, &st
, NULL
, buffer
+ ret
, size
- ret
);
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
;
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
))
353 if (!VerQueryValueW(data
, translationW
, (LPVOID
*)&lang
, &llen
))
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
));
374 struct file_properties_info
376 WCHAR path
[MAX_PATH
];
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
;
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
))
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
))
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 */
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)
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
);
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
)
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
);
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);
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
];
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
));
520 strcpyW(props
->path
, newpath
);
521 strcpyW(props
->dir
, newpath
);
522 if ((p
= strrchrW(props
->dir
, '\\')))
525 props
->filename
= p
+ 1;
528 props
->filename
= props
->dir
;
529 SetDlgItemTextW(hwndDlg
, IDC_FPROP_LOCATION
, props
->dir
);
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
)
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
;
564 props
= heap_alloc(sizeof(*props
));
567 format
.cfFormat
= CF_HDROP
;
569 format
.dwAspect
= DVASPECT_CONTENT
;
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
);
582 ReleaseStgMedium(&stgm
);
584 props
->attrib
= GetFileAttributesW(props
->path
);
585 if (props
->attrib
== INVALID_FILE_ATTRIBUTES
)
588 strcpyW(props
->dir
, props
->path
);
589 if ((p
= strrchrW(props
->dir
, '\\')))
592 props
->filename
= p
+ 1;
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
);
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
);
611 lpfnAddPage(general_page
, lParam
);
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
;
627 WCHAR wszFiletype
[MAX_PATH
];
628 WCHAR wszFilename
[MAX_PATH
];
629 PROPSHEETHEADERW psh
;
630 HPROPSHEETPAGE hpages
[MAX_PROP_PAGES
];
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
;
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]))
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
);
662 else if (_ILIsFolder(This
->apidl
[0]))
664 lstrcpynW(wszFiletype
, wszFolder
, 64);
666 else if (_ILIsSpecialFolder(This
->apidl
[0]))
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);
676 FIXME("Requested properties for unknown type.\n");
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
);
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
);
699 init_file_properties_pages(lpDo
, Properties_AddPropSheetCallback
, (LPARAM
)&psh
);
701 hpsxa
= SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT
, wszFiletype
, MAX_PROP_PAGES
- psh
.nPages
, lpDo
);
704 SHAddFromPropSheetExtArray(hpsxa
, Properties_AddPropSheetCallback
, (LPARAM
)&psh
);
705 SHDestroyPropSheetExtArray(hpsxa
);
707 hpsxa
= SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT
, wszFiletypeAll
, MAX_PROP_PAGES
- psh
.nPages
, lpDo
);
710 SHAddFromPropSheetExtArray(hpsxa
, Properties_AddPropSheetCallback
, (LPARAM
)&psh
);
711 SHDestroyPropSheetExtArray(hpsxa
);
713 IDataObject_Release(lpDo
);
717 PropertySheetW(&psh
);
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
));
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");
747 case FCIDM_SHVIEW_OPEN
:
748 TRACE("Verb FCIDM_SHVIEW_OPEN\n");
749 DoOpenExplore(This
, lpcmi
->hwnd
, "open");
751 case FCIDM_SHVIEW_RENAME
:
753 IShellBrowser
*browser
;
755 /* get the active IShellView */
756 browser
= (IShellBrowser
*)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
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
);
771 case FCIDM_SHVIEW_DELETE
:
772 TRACE("Verb FCIDM_SHVIEW_DELETE\n");
775 case FCIDM_SHVIEW_COPY
:
776 TRACE("Verb FCIDM_SHVIEW_COPY\n");
777 DoCopyOrCut(This
, lpcmi
->hwnd
, FALSE
);
779 case FCIDM_SHVIEW_CUT
:
780 TRACE("Verb FCIDM_SHVIEW_CUT\n");
781 DoCopyOrCut(This
, lpcmi
->hwnd
, TRUE
);
783 case FCIDM_SHVIEW_PROPERTIES
:
784 TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
785 DoOpenProperties(This
, lpcmi
->hwnd
);
788 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi
->lpVerb
));
794 TRACE("Verb is %s\n",debugstr_a(lpcmi
->lpVerb
));
795 if (strcmp(lpcmi
->lpVerb
,"delete")==0)
797 else if (strcmp(lpcmi
->lpVerb
,"properties")==0)
798 DoOpenProperties(This
, lpcmi
->hwnd
);
800 FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi
->lpVerb
));
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
;
822 TRACE("(%p)->(%lx, %#x, %p, %p, %u)\n", This
, cmdid
, flags
, reserved
, name
, maxlen
);
835 case FCIDM_SHVIEW_OPEN
:
838 case FCIDM_SHVIEW_EXPLORE
:
841 case FCIDM_SHVIEW_CUT
:
844 case FCIDM_SHVIEW_COPY
:
847 case FCIDM_SHVIEW_CREATELINK
:
850 case FCIDM_SHVIEW_DELETE
:
853 case FCIDM_SHVIEW_PROPERTIES
:
856 case FCIDM_SHVIEW_RENAME
:
867 if (flags
== GCS_VERBA
)
868 WideCharToMultiByte(CP_ACP
, 0, cmdW
, -1, name
, maxlen
, NULL
, NULL
);
870 lstrcpynW((WCHAR
*)name
, cmdW
, maxlen
);
872 TRACE("name %s\n", flags
== GCS_VERBA
? debugstr_a(name
) : debugstr_w((WCHAR
*)name
));
883 /**************************************************************************
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
);
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
);
904 static const IContextMenu3Vtbl ItemContextMenuVtbl
=
906 ContextMenu_QueryInterface
,
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
);
944 static const IShellExtInitVtbl ShellExtInitVtbl
=
946 ShellExtInit_QueryInterface
,
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
);
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
);
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
)
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
;
1011 This
->parent
= parent
;
1012 if (parent
) IShellFolder_AddRef(parent
);
1014 This
->pidl
= ILClone(pidl
);
1015 This
->apidl
= _ILCopyaPidl(apidl
, 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
);
1030 /* Background menu implementation */
1031 static HRESULT WINAPI
BackgroundMenu_QueryContextMenu(
1032 IContextMenu3
*iface
,
1039 ContextMenu
*This
= impl_from_IContextMenu3(iface
);
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);
1058 hr
= MAKE_HRESULT(SEVERITY_SUCCESS
, FACILITY_NULL
, 0);
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
);
1072 static void DoNewFolder(ContextMenu
*This
, IShellView
*view
)
1076 IShellFolder_QueryInterface(This
->parent
, &IID_ISFHelper
, (void**)&helper
);
1079 WCHAR nameW
[MAX_PATH
];
1082 ISFHelper_GetUniqueName(helper
, nameW
, MAX_PATH
);
1083 ISFHelper_AddFolder(helper
, 0, nameW
, &pidl
);
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
));
1094 ISFHelper_Release(helper
);
1098 static BOOL
DoPaste(ContextMenu
*This
)
1100 BOOL bSuccess
= FALSE
;
1105 if(SUCCEEDED(OleGetClipboard(&pda
)))
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
;
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
);
1131 IShellFolder_BindToObject(psfDesktop
, pidl
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfFrom
);
1132 IShellFolder_Release(psfDesktop
);
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
);
1158 /* release the medium*/
1159 ReleaseStgMedium(&medium
);
1161 IDataObject_Release(pda
);
1166 OpenClipboard(NULL
);
1167 hMem
= GetClipboardData(CF_HDROP
);
1171 char * pDropFiles
= GlobalLock(hMem
);
1174 int len
, offset
= sizeof(DROPFILESTRUCT
);
1176 while( pDropFiles
[offset
] != 0)
1178 len
= strlen(pDropFiles
+ offset
);
1179 TRACE("%s\n", pDropFiles
+ offset
);
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
;
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);
1226 FIXME("please report: unknown verb %s\n", debugstr_a(lpcmi
->lpVerb
));
1231 switch (LOWORD(lpcmi
->lpVerb
))
1233 case FCIDM_SHVIEW_REFRESH
:
1234 if (view
) IShellView_Refresh(view
);
1237 case FCIDM_SHVIEW_NEWFOLDER
:
1238 DoNewFolder(This
, view
);
1241 case FCIDM_SHVIEW_INSERT
:
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
);
1249 FIXME("launch item properties dialog\n");
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);
1261 IShellView_Release(view
);
1266 static HRESULT WINAPI
BackgroundMenu_GetCommandString(
1267 IContextMenu3
*iface
,
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
))
1293 FIXME("unknown command string\n");
1297 static const IContextMenu3Vtbl BackgroundContextMenuVtbl
=
1299 ContextMenu_QueryInterface
,
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
)
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
;
1321 This
->parent
= parent
;
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
);