2 * IContextMenu for items in the shellview
4 * Copyright 1998, 2000 Juergen Schmied <juergen.schmied@debitel.net>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
27 #include "wine/debug.h"
32 #include "undocshell.h"
37 #include "shell32_main.h"
38 #include "shellfolder.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
43 /* ugly hack for cut&paste files */
44 BOOL fileMoving
= FALSE
;
46 typedef struct _StaticShellEntry_
50 struct _StaticShellEntry_
* Next
;
51 }StaticShellEntry
, *PStaticShellEntry
;
53 typedef struct _DynamicShellEntry_
58 struct _DynamicShellEntry_
* Next
;
59 }DynamicShellEntry
, *PDynamicShellEntry
;
61 /**************************************************************************
62 * IContextMenu Implementation
66 { const IContextMenu2Vtbl
*lpVtbl
;
68 IShellFolder
* pSFParent
;
69 LPITEMIDLIST pidl
; /* root pidl */
70 LPITEMIDLIST
*apidl
; /* array of child pidls */
73 PDynamicShellEntry dhead
;
74 PStaticShellEntry head
;
83 SH_EnumerateDynamicContextHandlerForKey(LPWSTR szFileClass
, ItemCmImpl
*This
, IDataObject
* pDataObj
, DWORD bGroupPolicyActive
);
84 WCHAR
*build_paths_list(LPCWSTR wszBasePath
, int cidl
, LPCITEMIDLIST
*pidls
);
85 WCHAR
*strdupW(LPWSTR str
);
86 static const IContextMenu2Vtbl cmvt
;
88 /**************************************************************************
89 * ISvItemCm_CanRenameItems()
91 static BOOL
ISvItemCm_CanRenameItems(ItemCmImpl
*This
)
95 TRACE("(%p)->()\n",This
);
99 for(i
= 0; i
< This
->cidl
; i
++){}
100 if(i
> 1) return FALSE
; /* can't rename more than one item at a time*/
101 dwAttributes
= SFGAO_CANRENAME
;
102 IShellFolder_GetAttributesOf(This
->pSFParent
, 1, (LPCITEMIDLIST
*)This
->apidl
, &dwAttributes
);
103 return dwAttributes
& SFGAO_CANRENAME
;
108 /**************************************************************************
109 * ISvItemCm_Constructor()
111 IContextMenu2
*ISvItemCm_Constructor(LPSHELLFOLDER pSFParent
, LPCITEMIDLIST pidl
, const LPCITEMIDLIST
*apidl
, UINT cidl
)
115 cm
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(ItemCmImpl
));
118 cm
->pidl
= ILClone(pidl
);
119 cm
->pSFParent
= pSFParent
;
124 IShellFolder_AddRef(pSFParent
);
125 cm
->rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
;
126 hr
= IShellFolder_GetAttributesOf(pSFParent
, cidl
, (LPCITEMIDLIST
*)apidl
, &cm
->rfg
);
128 cm
->rfg
= 0; /* No action available */
131 cm
->apidl
= _ILCopyaPidl(apidl
, cidl
);
135 for(u
= 0; u
< cidl
; u
++)
137 cm
->bAllValues
&= (_ILIsValue(apidl
[u
]) ? 1 : 0);
140 TRACE("(%p)->()\n",cm
);
142 return (IContextMenu2
*)cm
;
145 /**************************************************************************
146 * ISvItemCm_fnQueryInterface
148 static HRESULT WINAPI
ISvItemCm_fnQueryInterface(IContextMenu2
*iface
, REFIID riid
, LPVOID
*ppvObj
)
150 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
152 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This
,debugstr_guid(riid
),ppvObj
);
156 if(IsEqualIID(riid
, &IID_IUnknown
) ||
157 IsEqualIID(riid
, &IID_IContextMenu
) ||
158 IsEqualIID(riid
, &IID_IContextMenu2
))
162 else if(IsEqualIID(riid
, &IID_IShellExtInit
)) /*IShellExtInit*/
164 FIXME("-- LPSHELLEXTINIT pointer requested\n");
169 IUnknown_AddRef((IUnknown
*)*ppvObj
);
170 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
173 TRACE("-- Interface: E_NOINTERFACE\n");
174 return E_NOINTERFACE
;
177 /**************************************************************************
180 static ULONG WINAPI
ISvItemCm_fnAddRef(IContextMenu2
*iface
)
182 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
183 ULONG refCount
= InterlockedIncrement(&This
->ref
);
185 TRACE("(%p)->(count=%u)\n", This
, refCount
- 1);
190 /**************************************************************************
191 * ISvItemCm_fnRelease
193 static ULONG WINAPI
ISvItemCm_fnRelease(IContextMenu2
*iface
)
195 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
196 ULONG refCount
= InterlockedDecrement(&This
->ref
);
197 PStaticShellEntry curEntry
;
198 PStaticShellEntry nextEntry
;
201 TRACE("(%p)->(count=%i)\n", This
, refCount
+ 1);
205 TRACE(" destroying IContextMenu(%p)\n",This
);
207 curEntry
= nextEntry
= This
->head
;
210 nextEntry
= nextEntry
->Next
;
211 free(curEntry
->szVerb
);
212 free(curEntry
->szClass
);
214 curEntry
= nextEntry
;
218 IShellFolder_Release(This
->pSFParent
);
222 /*make sure the pidl is freed*/
223 _ILFreeaPidl(This
->apidl
, This
->cidl
);
225 HeapFree(GetProcessHeap(),0,This
);
230 /**************************************************************************
233 void WINAPI
_InsertMenuItem (
244 ZeroMemory(&mii
, sizeof(mii
));
245 mii
.cbSize
= sizeof(mii
);
246 if (fType
== MFT_SEPARATOR
)
248 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
252 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
253 mii
.dwTypeData
= (LPSTR
) dwTypeData
;
258 InsertMenuItemA( hmenu
, indexMenu
, fByPosition
, &mii
);
262 DoCustomItemAction(ItemCmImpl
*This
, LPARAM lParam
, UINT uMsg
)
264 IContextMenu2
* cmenu
;
265 MEASUREITEMSTRUCT
* lpmis
= (MEASUREITEMSTRUCT
*)lParam
;
268 PDynamicShellEntry curEntry
;
270 TRACE("DoCustomItemAction entered with uMsg %x lParam %p\n", uMsg
, lParam
);
272 curEntry
= This
->dhead
;
273 i
= This
->iIdSHEFirst
;
278 if (i
== lpmis
->itemID
)
282 curEntry
= curEntry
->Next
;
288 hResult
= IContextMenu_QueryInterface(curEntry
->CMenu
, &IID_IContextMenu2
, (void**)&cmenu
);
291 ERR("failed to get IID_IContextMenu2 interface\n");
295 hResult
= IContextMenu2_HandleMenuMsg(cmenu
, uMsg
, (WPARAM
)0, lParam
);
296 IContextMenu2_Release(cmenu
);
298 TRACE("returning hResult %x\n", hResult
);
303 SH_LoadContextMenuHandlers(ItemCmImpl
*This
, IDataObject
* pDataObj
, HMENU hMenu
, UINT indexMenu
)
311 UINT idCmdFirst
= 0x6000;
312 UINT idCmdLast
= 0xFFF0;
313 PDynamicShellEntry curEntry
;
314 DWORD bGroupPolicyActive
= FALSE
;
316 static WCHAR szAny
[] = { '*',0};
318 dwSize
= sizeof(DWORD
);
319 RegGetValueW(HKEY_CURRENT_USER
,
320 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer",
321 L
"EnforceShellExtensionSecurity",
327 SH_EnumerateDynamicContextHandlerForKey(szAny
, This
, pDataObj
, bGroupPolicyActive
);
329 for (i
= 0; i
< This
->cidl
; i
++)
331 GUID
* guid
= _ILGetGUIDPointer(This
->apidl
[i
]);
335 static const WCHAR CLSID
[] = { 'C','L','S','I','D','\\',0 };
336 wcscpy(buffer
, CLSID
);
337 hr
= StringFromCLSID(guid
, &pwszCLSID
);
340 wcscpy(&buffer
[6], pwszCLSID
);
341 TRACE("buffer %s\n", debugstr_w(buffer
));
342 SH_EnumerateDynamicContextHandlerForKey(buffer
, This
, pDataObj
, bGroupPolicyActive
);
346 if (_ILGetExtension(This
->apidl
[i
], &ebuf
[1], sizeof(ebuf
) / sizeof(char)))
350 if (MultiByteToWideChar(CP_ACP
, 0, ebuf
, -1, buffer
, 111))
352 SH_EnumerateDynamicContextHandlerForKey(buffer
, This
, pDataObj
, bGroupPolicyActive
);
353 dwSize
= sizeof(szProgKey
);
354 if (RegGetValueW(HKEY_CLASSES_ROOT
, buffer
, NULL
, RRF_RT_REG_SZ
, NULL
, szProgKey
, &dwSize
) == ERROR_SUCCESS
)
356 szProgKey
[(sizeof(szProgKey
)/sizeof(WCHAR
))-1] = L
'\0';
357 SH_EnumerateDynamicContextHandlerForKey(szProgKey
, This
, pDataObj
, bGroupPolicyActive
);
362 TRACE("-- done loading\n");
365 This
->iIdSHEFirst
= 0;
366 This
->iIdSHELast
= 0;
370 curEntry
= This
->dhead
;
371 This
->iIdSHEFirst
= idCmdFirst
;
375 hResult
= IContextMenu_QueryContextMenu(curEntry
->CMenu
, hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, CMF_NORMAL
);
376 if (SUCCEEDED(hResult
))
378 curEntry
->iIdCmdFirst
= idCmdFirst
;
379 curEntry
->NumIds
= LOWORD(hResult
);
380 indexMenu
+= curEntry
->NumIds
;
381 idCmdFirst
+= curEntry
->NumIds
+ 0x10;
383 TRACE("curEntry %p hresult %x contextmenu %p cmdfirst %x num ids %x\n", curEntry
, hResult
, curEntry
->CMenu
, curEntry
->iIdCmdFirst
, curEntry
->NumIds
);
384 curEntry
= curEntry
->Next
;
387 This
->iIdSHELast
= idCmdFirst
;
388 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", This
->iIdSHEFirst
, This
->iIdSHELast
);
393 SH_AddStaticEntry(ItemCmImpl
* This
, HKEY hKey
, WCHAR
*szVerb
, WCHAR
* szClass
)
395 PStaticShellEntry curEntry
;
396 PStaticShellEntry lastEntry
= NULL
;
398 curEntry
= This
->head
;
402 if (!wcsicmp(curEntry
->szVerb
, szVerb
))
404 /* entry already exists */
407 lastEntry
= curEntry
;
408 curEntry
= curEntry
->Next
;
411 TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb
), debugstr_w(szClass
));
413 curEntry
= malloc(sizeof(StaticShellEntry
));
416 curEntry
->Next
= NULL
;
417 curEntry
->szVerb
= wcsdup(szVerb
);
418 curEntry
->szClass
= wcsdup(szClass
);
423 lastEntry
->Next
= curEntry
;
427 This
->head
= curEntry
;
432 SH_AddStaticEntryForKey(ItemCmImpl
* This
, HKEY hKey
, WCHAR
* szClass
)
443 dwName
= sizeof(szName
) / sizeof(WCHAR
);
444 result
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwName
, NULL
, NULL
, NULL
, NULL
);
446 if (result
== ERROR_SUCCESS
)
448 SH_AddStaticEntry(This
, hKey
, szName
, szClass
);
451 }while(result
== ERROR_SUCCESS
);
455 SH_AddStaticEntryForFileClass(ItemCmImpl
* This
, WCHAR
* szExt
)
462 TRACE("SH_AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt
));
464 wcscpy(szBuffer
, szExt
);
465 wcscat(szBuffer
, L
"\\shell");
466 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
467 if (result
== ERROR_SUCCESS
)
469 SH_AddStaticEntryForKey(This
, hKey
, szExt
);
473 dwBuffer
= sizeof(szBuffer
);
474 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, NULL
, RRF_RT_REG_SZ
, NULL
, (LPBYTE
)szBuffer
, &dwBuffer
);
475 if (result
== ERROR_SUCCESS
)
477 UINT length
= strlenW(szBuffer
);
478 wcscat(szBuffer
, L
"\\shell");
479 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
481 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
482 if (result
== ERROR_SUCCESS
)
484 szBuffer
[length
] = 0;
485 SH_AddStaticEntryForKey(This
, hKey
, szBuffer
);
490 strcpyW(szBuffer
, "SystemFileAssociations\\");
491 dwBuffer
= sizeof(szBuffer
) - strlenW(szBuffer
) * sizeof(WCHAR
);
492 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, L
"PerceivedType", RRF_RT_REG_SZ
, NULL
, (LPBYTE
)&szBuffer
[23], &dwBuffer
);
493 if (result
== ERROR_SUCCESS
)
495 UINT length
= strlenW(szBuffer
);
496 wcscat(szBuffer
, L
"\\shell");
497 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
499 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
500 if (result
== ERROR_SUCCESS
)
502 szBuffer
[length
] = 0;
503 SH_AddStaticEntryForKey(This
, hKey
, szBuffer
);
511 SH_AddStaticEntrySpecial(ItemCmImpl
* This
)
513 if (_ILIsFolder(This
->apidl
[0])) // && (This->rfg & SFGAO_BROWSABLE))
515 SH_AddStaticEntryForFileClass(This
, L
"Folder");
517 else if (_ILIsDrive(This
->apidl
[0]))
519 SH_AddStaticEntryForFileClass(This
, L
"Drive");
525 SH_AddStaticEntryToMenu(HMENU hMenu
, UINT indexMenu
, ItemCmImpl
* This
)
528 PStaticShellEntry curEntry
;
532 mii
.cbSize
= sizeof(mii
);
533 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
534 mii
.fType
= MFT_STRING
;
535 mii
.fState
= MFS_ENABLED
| MFS_DEFAULT
;
537 This
->iIdSCMFirst
= mii
.wID
;
539 curEntry
= This
->head
;
543 if (!wcsicmp(curEntry
->szVerb
, L
"open"))
544 idResource
= IDS_OPEN_VERB
;
545 else if (!wcsicmp(curEntry
->szVerb
, L
"runas"))
546 idResource
= IDS_RUNAS_VERB
;
547 else if (!wcsicmp(curEntry
->szVerb
, L
"edit"))
548 idResource
= IDS_EDIT_VERB
;
549 else if (!wcsicmp(curEntry
->szVerb
, L
"find"))
550 idResource
= IDS_FIND_VERB
;
551 else if (!wcsicmp(curEntry
->szVerb
, L
"print"))
552 idResource
= IDS_PRINT_VERB
;
553 else if (!wcsicmp(curEntry
->szVerb
, L
"play"))
554 idResource
= IDS_PLAY_VERB
;
555 else if (!wcsicmp(curEntry
->szVerb
, L
"preview"))
556 idResource
= IDS_PREVIEW_VERB
;
562 if (LoadStringW(shell32_hInstance
, idResource
, szVerb
, sizeof(szVerb
)/sizeof(WCHAR
)))
564 szVerb
[(sizeof(szVerb
)/sizeof(WCHAR
))-1] = L
'\0';
565 mii
.dwTypeData
= szVerb
;
569 WARN("unknown verb %s\n", debugstr_w(curEntry
->szVerb
));
570 mii
.dwTypeData
= curEntry
->szVerb
;
575 WARN("unknown verb %s\n", debugstr_w(curEntry
->szVerb
));
576 mii
.dwTypeData
= curEntry
->szVerb
;
579 mii
.cch
= strlenW(mii
.dwTypeData
);
580 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
581 mii
.fState
= MFS_ENABLED
;
583 curEntry
= curEntry
->Next
;
585 This
->iIdSCMLast
= mii
.wID
- 1;
589 const char * GetLocalizedString(HMENU hMenu
, UINT wID
, const char * sDefault
, char * sResult
)
597 mii
.cbSize
= sizeof(mii
);
598 mii
.fMask
= MIIM_TYPE
;
599 mii
.fType
= MFT_STRING
;
600 mii
.dwTypeData
= sResult
;
603 if (GetMenuItemInfoA(hMenu
, wID
, FALSE
, &mii
))
613 /**************************************************************************
614 * ISvItemCm_fnQueryContextMenu()
615 * FIXME: load menu MENU_SHV_FILE out of resources instead if creating
616 * each menu item by calling _InsertMenuItem()
618 static HRESULT WINAPI
ISvItemCm_fnQueryContextMenu(
619 IContextMenu2
*iface
,
626 IDataObject
* pDataObj
;
627 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
628 USHORT lastindex
= 0;
633 static const char sCopy
[] = { '&','C','o','p','y',0 };
634 static const char sCut
[] = { '&','C','u','t',0 };
635 static const char sDelete
[] = { '&','D','e','l','e','t','e',0 };
636 static const char sRename
[] = { '&','R','e','n','a','m','e',0 };
637 static const char sProperties
[] = { '&','P','r','o','p','e','r','t','i','e','s',0 };
638 static const WCHAR szSHVFile
[] = { 'M','E','N','U','_','S','H','V','_','F','I','L','E',0 };
641 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",This
, hmenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
643 hLocalMenu
= LoadMenuW(shell32_hInstance
, szSHVFile
);
645 if (_ILGetExtension(This
->apidl
[0], &sBuffer
[1], sizeof(sBuffer
)-1))
648 MultiByteToWideChar( CP_ACP
, 0, sBuffer
, -1, (LPWSTR
)szExt
, 10);
649 SH_AddStaticEntryForFileClass(This
, szExt
);
653 SH_AddStaticEntrySpecial(This
);
656 indexMenu
= SH_AddStaticEntryToMenu(hmenu
, indexMenu
, This
);
658 SetMenuDefaultItem(hmenu
, 0, MF_BYPOSITION
);
659 pDataObj
= IDataObject_Constructor(NULL
, This
->pidl
, (LPCITEMIDLIST
*)This
->apidl
, This
->cidl
);
662 indexMenu
= SH_LoadContextMenuHandlers(This
, pDataObj
, hmenu
, indexMenu
);
663 IDataObject_Release(pDataObj
);
666 if(!(CMF_DEFAULTONLY
& uFlags
) && This
->cidl
>0)
668 if(!(uFlags
& CMF_EXPLORE
))
669 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_OPEN
, MFT_STRING
, "&Select", MFS_ENABLED
);
671 TRACE("rfg %x\n", This
->rfg
);
674 if (This
->rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
))
676 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
677 if (This
->rfg
& SFGAO_CANCOPY
)
678 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, GetLocalizedString(hLocalMenu
, FCIDM_SHVIEW_COPY
, sCopy
, sBuffer
), MFS_ENABLED
);
679 if (This
->rfg
& SFGAO_CANMOVE
)
680 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, GetLocalizedString(hLocalMenu
, FCIDM_SHVIEW_CUT
, sCut
, sBuffer
), MFS_ENABLED
);
683 if (This
->rfg
& SFGAO_CANDELETE
)
685 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
686 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, GetLocalizedString(hLocalMenu
, FCIDM_SHVIEW_DELETE
, sDelete
, sBuffer
), MFS_ENABLED
);
689 if ((uFlags
& CMF_CANRENAME
) && (This
->rfg
& SFGAO_CANRENAME
))
690 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, GetLocalizedString(hLocalMenu
, FCIDM_SHVIEW_RENAME
, sRename
, sBuffer
), ISvItemCm_CanRenameItems(This
) ? MFS_ENABLED
: MFS_DISABLED
);
692 if (This
->rfg
& SFGAO_HASPROPSHEET
)
694 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
695 _InsertMenuItem(hmenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, GetLocalizedString(hLocalMenu
, FCIDM_SHVIEW_PROPERTIES
, sProperties
, sBuffer
), MFS_ENABLED
);
698 lastindex
= FCIDM_SHVIEWLAST
;
703 DestroyMenu(hLocalMenu
);
706 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, lastindex
);
709 /**************************************************************************
712 static void DoRename(
713 IContextMenu2
*iface
,
716 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
721 TRACE("(%p)->(wnd=%p)\n",This
, hwnd
);
723 /* get the active IShellView */
724 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(hwnd
, CWM_GETISHELLBROWSER
,0,0)))
726 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
728 TRACE("(sv=%p)\n",lpSV
);
729 IShellView_SelectItem(lpSV
, This
->apidl
[0],
730 SVSI_DESELECTOTHERS
|SVSI_EDIT
|SVSI_ENSUREVISIBLE
|SVSI_FOCUSED
|SVSI_SELECT
);
731 IShellView_Release(lpSV
);
736 /**************************************************************************
739 * deletes the currently selected items
741 static void DoDelete(IContextMenu2
*iface
, HWND hwnd
)
743 WCHAR szPath
[MAX_PATH
];
748 IPersistFolder2
* psf
;
751 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
753 if (IShellFolder2_QueryInterface(This
->pSFParent
, &IID_IPersistFolder2
, (LPVOID
*)&psf
) != S_OK
)
755 ERR("Failed to get interface IID_IPersistFolder2\n");
759 if (IPersistFolder2_GetCurFolder(psf
, &pidl
) != S_OK
)
761 ERR("IPersistFolder2_GetCurFolder failed\n");
762 IPersistFolder2_Release(psf
);
766 if (IShellFolder2_GetDisplayNameOf(This
->pSFParent
, pidl
, SHGDN_FORPARSING
, &strTemp
) != S_OK
)
768 ERR("IShellFolder_GetDisplayNameOf failed\n");
769 IPersistFolder2_Release(psf
);
772 szPath
[MAX_PATH
-1] = 0;
773 StrRetToBufW(&strTemp
, pidl
, szPath
, MAX_PATH
);
774 PathAddBackslashW(szPath
);
775 IPersistFolder2_Release(psf
);
777 szTarget
= build_paths_list(szPath
, This
->cidl
, (LPCITEMIDLIST
*)This
->apidl
);
781 if (SHGetPathFromIDListW(pidl
, szPath
))
783 ZeroMemory(&op
, sizeof(op
));
784 op
.hwnd
= GetActiveWindow();
785 op
.wFunc
= FO_DELETE
;
787 op
.fFlags
= FOF_ALLOWUNDO
;
788 SHFileOperationW(&op
);
793 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(hwnd
, CWM_GETISHELLBROWSER
,0,0)))
795 if (SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
797 IShellView_Refresh(lpSV
);
802 /**************************************************************************
805 * copies the currently selected items into the clipboard
807 static BOOL
DoCopyOrCut(
808 IContextMenu2
*iface
,
812 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
818 TRACE("(%p)->(wnd=%p,bCut=0x%08x)\n",This
, hwnd
, bCut
);
820 /* get the active IShellView */
821 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(hwnd
, CWM_GETISHELLBROWSER
,0,0)))
823 if (SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
825 if (SUCCEEDED(IShellView_GetItemObject(lpSV
, SVGIO_SELECTION
, &IID_IDataObject
, (LPVOID
*)&lpDo
)))
827 OleSetClipboard(lpDo
);
828 IDataObject_Release(lpDo
);
830 IShellView_Release(lpSV
);
835 static void DoProperties(
836 IContextMenu2
*iface
,
839 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
840 LPITEMIDLIST pidlFQ
= NULL
;
841 SHELLEXECUTEINFOA sei
;
846 * The IShellFolder interface GetUIObject should create the specific item and then query if it has an IContextMenu interface
847 * If yes return interface to it.
850 if (_ILIsMyComputer(This
->apidl
[0]))
852 ShellExecuteA(hwnd
, "open", "rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
855 else if (_ILIsDesktop(This
->apidl
[0]))
857 ShellExecuteA(hwnd
, "open", "rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
860 else if (_ILIsDrive(This
->apidl
[0]))
863 ILGetDisplayName(This
->apidl
[0], buffer
);
864 SH_ShowDriveProperties(buffer
);
867 else if (_ILIsNetHood(This
->apidl
[0]))
870 * implement nethood properties
872 FIXME("implement nethood property dialog\n");
875 else if (_ILIsBitBucket(This
->apidl
[0]))
879 SH_ShowRecycleBinProperties(szDrive
);
883 pidlFQ
= ILCombine(This
->pidl
, This
->apidl
[0]);
886 ZeroMemory(&sei
, sizeof(sei
));
887 sei
.cbSize
= sizeof(sei
);
888 sei
.fMask
= SEE_MASK_INVOKEIDLIST
;
889 sei
.lpIDList
= pidlFQ
;
891 sei
.nShow
= SW_SHOWNORMAL
;
892 sei
.lpVerb
= "properties";
894 TRACE("DoProperties before ShellExecuteEx\n");
895 ShellExecuteExA(&sei
);
896 TRACE("DoProperties after ShellExecuteEx\n");
904 DoStaticShellExtensions(ItemCmImpl
*This
, LPCMINVOKECOMMANDINFO lpcmi
)
907 PStaticShellEntry curEntry
;
909 UINT bFolderFound
= FALSE
;
910 SHELLEXECUTEINFOW sei
;
912 TRACE("DoStaticShellExtensions entered with lpVerb %x first %x last %x\n", LOWORD(lpcmi
->lpVerb
), This
->iIdSCMFirst
, This
->iIdSCMLast
);
914 i
= This
->iIdSCMFirst
;
915 curEntry
= This
->head
;
919 if (i
== LOWORD(lpcmi
->lpVerb
))
923 curEntry
= curEntry
->Next
;
932 for(i
= 0; i
<This
->cidl
; i
++)
934 if(!_ILIsValue(This
->apidl
[i
]))
941 if (bFolderFound
&& wcsicmp(curEntry
->szClass
, L
"Folder"))
943 /* when there is a folder with item selected
949 TRACE("curEntry %p verb %s szClass %s\n", curEntry
, debugstr_w(curEntry
->szVerb
), debugstr_w(curEntry
->szClass
));
951 pidl
= ILCombine(This
->pidl
, This
->apidl
[0]);
953 ZeroMemory(&sei
, sizeof(sei
));
954 sei
.cbSize
= sizeof(sei
);
955 sei
.fMask
= SEE_MASK_CLASSNAME
| SEE_MASK_IDLIST
;
957 sei
.lpClass
= curEntry
->szClass
;
958 sei
.hwnd
= lpcmi
->hwnd
;
959 sei
.nShow
= SW_SHOWNORMAL
;
960 sei
.lpVerb
= curEntry
->szVerb
;
961 ShellExecuteExW(&sei
);
967 DoDynamicShellExtensions(ItemCmImpl
*This
, LPCMINVOKECOMMANDINFO lpcmi
)
969 HRESULT hResult
= NOERROR
;
970 PDynamicShellEntry curEntry
;
973 curEntry
= This
->dhead
;
974 id
= LOWORD(lpcmi
->lpVerb
);
978 if (curEntry
->iIdCmdFirst
<= id
&& curEntry
->iIdCmdFirst
+ curEntry
->NumIds
>= id
)
981 curEntry
= curEntry
->Next
;
987 lpcmi
->lpVerb
-= curEntry
->iIdCmdFirst
;
989 hResult
= IContextMenu_InvokeCommand(curEntry
->CMenu
, lpcmi
);
991 TRACE("DoDynamicShellExtensions hResult %x verb %x first %x\n", hResult
, lpcmi
->lpVerb
, curEntry
->iIdCmdFirst
);
996 /**************************************************************************
997 * ISvItemCm_fnInvokeCommand()
999 static HRESULT WINAPI
ISvItemCm_fnInvokeCommand(
1000 IContextMenu2
*iface
,
1001 LPCMINVOKECOMMANDINFO lpcmi
)
1003 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
1005 if (lpcmi
->cbSize
!= sizeof(CMINVOKECOMMANDINFO
))
1006 FIXME("Is an EX structure\n");
1008 TRACE("ISvItemCm_fnInvokeCommand (%p)->(invcom=%p verb=%p wnd=%p)\n",This
,lpcmi
,lpcmi
->lpVerb
, lpcmi
->hwnd
);
1010 if( HIWORD(lpcmi
->lpVerb
)==0 && LOWORD(lpcmi
->lpVerb
) > FCIDM_SHVIEWLAST
)
1012 TRACE("Invalid Verb %x\n",LOWORD(lpcmi
->lpVerb
));
1013 return E_INVALIDARG
;
1016 if (HIWORD(lpcmi
->lpVerb
) == 0)
1018 switch(LOWORD(lpcmi
->lpVerb
))
1020 case FCIDM_SHVIEW_RENAME
:
1021 TRACE("Verb FCIDM_SHVIEW_RENAME\n");
1022 DoRename(iface
, lpcmi
->hwnd
);
1024 case FCIDM_SHVIEW_DELETE
:
1025 TRACE("Verb FCIDM_SHVIEW_DELETE\n");
1026 DoDelete(iface
, lpcmi
->hwnd
);
1028 case FCIDM_SHVIEW_COPY
:
1029 TRACE("Verb FCIDM_SHVIEW_COPY\n");
1030 DoCopyOrCut(iface
, lpcmi
->hwnd
, FALSE
);
1032 case FCIDM_SHVIEW_CUT
:
1033 TRACE("Verb FCIDM_SHVIEW_CUT\n");
1034 DoCopyOrCut(iface
, lpcmi
->hwnd
, TRUE
);
1036 case FCIDM_SHVIEW_PROPERTIES
:
1037 TRACE("Verb FCIDM_SHVIEW_PROPERTIES\n");
1038 DoProperties(iface
, lpcmi
->hwnd
);
1041 TRACE("iIdSHEFirst %x iIdSHELast %x iIdSCMFirst %x iIdSCMLast %x\n", This
->iIdSHEFirst
, This
->iIdSHELast
, This
->iIdSCMFirst
, This
->iIdSCMLast
);
1042 if (This
->iIdSHEFirst
&& This
->iIdSHELast
)
1044 if (LOWORD(lpcmi
->lpVerb
) >= This
->iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= This
->iIdSHELast
)
1046 return DoDynamicShellExtensions(This
, lpcmi
);
1049 if (This
->iIdSCMFirst
&& This
->iIdSCMLast
)
1051 if (LOWORD(lpcmi
->lpVerb
) >= This
->iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= This
->iIdSCMLast
)
1053 return DoStaticShellExtensions(This
, lpcmi
);
1056 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi
->lpVerb
));
1061 TRACE("Verb is %s\n",debugstr_a(lpcmi
->lpVerb
));
1062 if (strcmp(lpcmi
->lpVerb
,"delete")==0)
1063 DoDelete(iface
, lpcmi
->hwnd
);
1065 FIXME("Unhandled string verb %s\n",debugstr_a(lpcmi
->lpVerb
));
1070 /**************************************************************************
1071 * ISvItemCm_fnGetCommandString()
1073 static HRESULT WINAPI
ISvItemCm_fnGetCommandString(
1074 IContextMenu2
*iface
,
1081 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
1083 HRESULT hr
= E_INVALIDARG
;
1085 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This
, idCommand
, uFlags
, lpReserved
, lpszName
, uMaxNameLen
);
1097 case FCIDM_SHVIEW_RENAME
:
1098 strcpy((LPSTR
)lpszName
, "rename");
1104 /* NT 4.0 with IE 3.0x or no IE will always call This with GCS_VERBW. In This
1105 case, you need to do the lstrcpyW to the pointer passed.*/
1108 { case FCIDM_SHVIEW_RENAME
:
1109 MultiByteToWideChar( CP_ACP
, 0, "rename", -1, (LPWSTR
)lpszName
, uMaxNameLen
);
1120 TRACE("-- (%p)->(name=%s)\n",This
, lpszName
);
1124 /**************************************************************************
1125 * ISvItemCm_fnHandleMenuMsg()
1127 * should be only in IContextMenu2 and IContextMenu3
1128 * is nevertheless called from word95
1130 static HRESULT WINAPI
ISvItemCm_fnHandleMenuMsg(
1131 IContextMenu2
*iface
,
1136 ItemCmImpl
*This
= (ItemCmImpl
*)iface
;
1137 LPMEASUREITEMSTRUCT lpmis
= (LPMEASUREITEMSTRUCT
) lParam
;
1138 TRACE("(%p)->(msg=%x wp=%lx lp=%lx)\n",This
, uMsg
, wParam
, lParam
);
1142 case WM_MEASUREITEM
:
1144 if (lpmis
->itemID
>= This
->iIdSHEFirst
&& lpmis
->itemID
<= This
->iIdSHELast
)
1145 return DoCustomItemAction(This
, lParam
, uMsg
);
1153 static const IContextMenu2Vtbl cmvt
=
1155 ISvItemCm_fnQueryInterface
,
1157 ISvItemCm_fnRelease
,
1158 ISvItemCm_fnQueryContextMenu
,
1159 ISvItemCm_fnInvokeCommand
,
1160 ISvItemCm_fnGetCommandString
,
1161 ISvItemCm_fnHandleMenuMsg
1165 SH_LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
* szClass
, ItemCmImpl
*This
, IDataObject
* pDataObj
)
1168 IContextMenu
* cmobj
;
1169 IShellExtInit
*shext
;
1170 PDynamicShellEntry curEntry
;
1171 TRACE("SH_LoadDynamicContextMenuHandler entered with %s\n",wine_dbgstr_guid(szClass
));
1173 hr
= SHCoCreateInstance(NULL
, szClass
, NULL
, &IID_IContextMenu
, (void**)&cmobj
);
1176 TRACE("SHCoCreateInstance failed %x\n", GetLastError());
1179 hr
= cmobj
->lpVtbl
->QueryInterface(cmobj
, &IID_IShellExtInit
, (void**)&shext
);
1182 TRACE("Failed to query for interface IID_IShellExtInit\n");
1183 cmobj
->lpVtbl
->Release(cmobj
);
1186 hr
= shext
->lpVtbl
->Initialize(shext
, NULL
, pDataObj
, hKey
);
1189 TRACE("Failed to initialize shell extension error %x\n", hr
);
1190 shext
->lpVtbl
->Release(shext
);
1191 cmobj
->lpVtbl
->Release(cmobj
);
1194 curEntry
= malloc(sizeof(DynamicShellEntry
));
1197 return E_OUTOFMEMORY
;
1200 curEntry
->iIdCmdFirst
= 0;
1201 curEntry
->Next
= NULL
;
1202 curEntry
->NumIds
= 0;
1203 curEntry
->CMenu
= cmobj
;
1207 PDynamicShellEntry pEntry
= This
->dhead
;
1211 pEntry
= pEntry
->Next
;
1214 pEntry
->Next
= curEntry
;
1218 This
->dhead
= curEntry
;
1225 SH_EnumerateDynamicContextHandlerForKey(const LPWSTR szFileClass
, ItemCmImpl
*This
, IDataObject
* pDataObj
, DWORD bGroupPolicyActive
)
1228 WCHAR szKey
[MAX_PATH
] = {0};
1229 WCHAR szName
[MAX_PATH
] = {0};
1230 DWORD dwIndex
, dwName
;
1235 static const WCHAR szShellEx
[] = { '\\','s','h','e','l','l','e','x','\\','C','o','n','t','e','x','t','M','e','n','u','H','a','n','d','l','e','r','s',0 };
1237 wcscpy(szKey
, szFileClass
);
1238 wcscat(szKey
, szShellEx
);
1240 TRACE("SH_EnumerateDynamicContextHandlerForKey key %s\n", debugstr_w(szFileClass
));
1242 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szKey
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
1244 TRACE("RegOpenKeyExW failed for key %s\n", debugstr_w(szKey
));
1253 res
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwName
, NULL
, NULL
, NULL
, NULL
);
1254 if (res
== ERROR_SUCCESS
)
1256 hResult
= CLSIDFromString(szName
, &clsid
);
1257 if (hResult
!= S_OK
)
1260 if (RegGetValueW(hKey
, szName
, NULL
, RRF_RT_REG_SZ
, NULL
, szKey
, &dwName
) == ERROR_SUCCESS
)
1262 if (CLSIDFromString(szKey
, &clsid
) == S_OK
)
1264 if (bGroupPolicyActive
)
1266 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
1267 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1272 &dwName
) == ERROR_SUCCESS
)
1274 SH_LoadDynamicContextMenuHandler(hKey
, &clsid
, This
, pDataObj
);
1280 SH_LoadDynamicContextMenuHandler(hKey
, &clsid
, This
, pDataObj
);
1285 if (hResult
== S_OK
)
1287 if (bGroupPolicyActive
)
1289 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
1290 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
1295 &dwName
) == ERROR_SUCCESS
)
1297 SH_LoadDynamicContextMenuHandler(hKey
, &clsid
, This
, pDataObj
);
1302 SH_LoadDynamicContextMenuHandler(hKey
, &clsid
, This
, pDataObj
);
1307 }while(res
== ERROR_SUCCESS
);
1313 /*************************************************************************
1314 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1318 HRESULT WINAPI
SHCreateDefaultContextMenu(
1319 const DEFCONTEXTMENU
*pdcm
,
1324 IContextMenu2
* pcm
;
1327 pcm
= ISvItemCm_Constructor( pdcm
->psf
, pdcm
->pidlFolder
, pdcm
->apidl
, pdcm
->cidl
);
1329 pcm
= ISvBgCm_Constructor( pdcm
->psf
, TRUE
);
1337 /*************************************************************************
1338 * CDefFolderMenu_Create2 [SHELL32.701]
1344 CDefFolderMenu_Create2(
1345 LPCITEMIDLIST pidlFolder
,
1348 LPCITEMIDLIST
*apidl
,
1350 LPFNDFMCALLBACK lpfn
,
1353 IContextMenu
**ppcm
)
1355 DEFCONTEXTMENU pdcm
;
1359 pdcm
.pcmcb
= NULL
; //FIXME
1360 pdcm
.pidlFolder
= pidlFolder
;
1364 pdcm
.punkAssociationInfo
= NULL
;
1366 pdcm
.aKeys
= ahkeyClsKeys
;
1368 hr
= SHCreateDefaultContextMenu(&pdcm
, &IID_IContextMenu
, (void**)ppcm
);