3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/shell32/shv_item_new.c
5 * PURPOSE: provides default context menu implementation
6 * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org)
11 WINE_DEFAULT_DEBUG_CHANNEL(dmenu
);
13 typedef struct _DynamicShellEntry_
19 struct _DynamicShellEntry_
* Next
;
20 }DynamicShellEntry
, *PDynamicShellEntry
;
22 typedef struct _StaticShellEntry_
26 struct _StaticShellEntry_
* Next
;
27 }StaticShellEntry
, *PStaticShellEntry
;
32 const IContextMenu2Vtbl
*lpVtbl
;
35 IDataObject
* pDataObj
;
36 DWORD bGroupPolicyActive
;
37 PDynamicShellEntry dhead
; /* first dynamic shell extension entry */
38 UINT iIdSHEFirst
; /* first used id */
39 UINT iIdSHELast
; /* last used id */
40 PStaticShellEntry shead
; /* first static shell extension entry */
41 UINT iIdSCMFirst
; /* first static used id */
42 UINT iIdSCMLast
; /* last static used id */
43 }IDefaultContextMenuImpl
, *LPIDefaultContextMenuImpl
;
45 static LPIDefaultContextMenuImpl __inline
impl_from_IContextMenu( IContextMenu2
*iface
)
47 return (LPIDefaultContextMenuImpl
)((char*)iface
- FIELD_OFFSET(IDefaultContextMenuImpl
, lpVtbl
));
50 VOID
INewItem_SetCurrentShellFolder(IShellFolder
* psfParent
); // HACK
56 IDefaultContextMenu_fnQueryInterface(
61 IDefaultContextMenuImpl
*This
= (IDefaultContextMenuImpl
*)iface
;
63 TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This
,debugstr_guid(riid
),ppvObj
);
67 if(IsEqualIID(riid
, &IID_IUnknown
) ||
68 IsEqualIID(riid
, &IID_IContextMenu
) ||
69 IsEqualIID(riid
, &IID_IContextMenu2
))
76 IUnknown_AddRef((IUnknown
*)*ppvObj
);
77 TRACE("-- Interface: (%p)->(%p)\n",ppvObj
,*ppvObj
);
80 TRACE("-- Interface: E_NOINTERFACE\n");
88 IDefaultContextMenu_fnAddRef(
91 IDefaultContextMenuImpl
*This
= (IDefaultContextMenuImpl
*)iface
;
92 ULONG refCount
= InterlockedIncrement(&This
->ref
);
94 TRACE("(%p)->(count=%u)\n", This
, refCount
- 1);
102 IDefaultContextMenu_fnRelease(
103 IContextMenu2
*iface
)
105 PDynamicShellEntry dEntry
, dNext
;
106 PStaticShellEntry sEntry
, sNext
;
107 IDefaultContextMenuImpl
*This
= (IDefaultContextMenuImpl
*)iface
;
108 ULONG refCount
= InterlockedDecrement(&This
->ref
);
110 TRACE("(%p)->(count=%u)\n", This
, refCount
+ 1);
113 /* free dynamic shell extension entries */
114 dEntry
= This
->dhead
;
117 dNext
= dEntry
->Next
;
118 IContextMenu_Release(dEntry
->CMenu
);
119 HeapFree(GetProcessHeap(), 0, dEntry
);
122 /* free static shell extension entries */
123 sEntry
= This
->shead
;
126 sNext
= sEntry
->Next
;
127 HeapFree(GetProcessHeap(), 0, sEntry
->szClass
);
128 HeapFree(GetProcessHeap(), 0, sEntry
->szVerb
);
129 HeapFree(GetProcessHeap(), 0, sEntry
);
132 HeapFree(GetProcessHeap(),0,This
);
140 SH_AddStaticEntry(IDefaultContextMenuImpl
* This
, WCHAR
*szVerb
, WCHAR
* szClass
)
142 PStaticShellEntry curEntry
;
143 PStaticShellEntry lastEntry
= NULL
;
145 curEntry
= This
->shead
;
148 if (!wcsicmp(curEntry
->szVerb
, szVerb
))
150 /* entry already exists */
153 lastEntry
= curEntry
;
154 curEntry
= curEntry
->Next
;
157 TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb
), debugstr_w(szClass
));
159 curEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry
));
162 curEntry
->Next
= NULL
;
163 curEntry
->szVerb
= HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb
)+1) * sizeof(WCHAR
));
164 if (curEntry
->szVerb
)
165 wcscpy(curEntry
->szVerb
, szVerb
);
166 curEntry
->szClass
= HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass
)+1) * sizeof(WCHAR
));
167 if (curEntry
->szClass
)
168 wcscpy(curEntry
->szClass
, szClass
);
171 if (!wcsicmp(szVerb
, L
"open"))
173 /* open verb is always inserted in front */
174 curEntry
->Next
= This
->shead
;
175 This
->shead
= curEntry
;
183 lastEntry
->Next
= curEntry
;
187 This
->shead
= curEntry
;
193 SH_AddStaticEntryForKey(IDefaultContextMenuImpl
* This
, HKEY hKey
, WCHAR
* szClass
)
204 dwName
= sizeof(szName
) / sizeof(WCHAR
);
205 result
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwName
, NULL
, NULL
, NULL
, NULL
);
206 szName
[(sizeof(szName
)/sizeof(WCHAR
))-1] = 0;
207 if (result
== ERROR_SUCCESS
)
209 SH_AddStaticEntry(This
, szName
, szClass
);
212 }while(result
== ERROR_SUCCESS
);
217 SH_AddStaticEntryForFileClass(IDefaultContextMenuImpl
* This
, WCHAR
* szExt
)
224 static WCHAR szShell
[] = L
"\\shell";
225 static WCHAR szShellAssoc
[] = L
"SystemFileAssociations\\";
227 TRACE("SH_AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt
));
229 Length
= wcslen(szExt
);
230 if (Length
+ (sizeof(szShell
)/sizeof(WCHAR
)) + 1 < sizeof(szBuffer
)/sizeof(WCHAR
))
232 wcscpy(szBuffer
, szExt
);
233 wcscpy(&szBuffer
[Length
], szShell
);
234 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
235 if (result
== ERROR_SUCCESS
)
237 szBuffer
[Length
] = 0;
238 SH_AddStaticEntryForKey(This
, hKey
, szExt
);
243 dwBuffer
= sizeof(szBuffer
);
244 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, NULL
, RRF_RT_REG_SZ
, NULL
, (LPBYTE
)szBuffer
, &dwBuffer
);
245 if (result
== ERROR_SUCCESS
)
247 Length
= wcslen(szBuffer
);
248 if (Length
+ (sizeof(szShell
)/sizeof(WCHAR
)) + 1 < sizeof(szBuffer
)/sizeof(WCHAR
))
250 wcscpy(&szBuffer
[Length
], szShell
);
251 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
253 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
254 if (result
== ERROR_SUCCESS
)
256 szBuffer
[Length
] = 0;
257 SH_AddStaticEntryForKey(This
, hKey
, szBuffer
);
263 wcscpy(szBuffer
, szShellAssoc
);
264 dwBuffer
= sizeof(szBuffer
) - sizeof(szShellAssoc
) - sizeof(WCHAR
);
265 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, L
"PerceivedType", RRF_RT_REG_SZ
, NULL
, (LPBYTE
)&szBuffer
[(sizeof(szShellAssoc
)/sizeof(WCHAR
))], &dwBuffer
);
266 if (result
== ERROR_SUCCESS
)
268 Length
= wcslen(&szBuffer
[(sizeof(szShellAssoc
)/sizeof(WCHAR
))]) + (sizeof(szShellAssoc
)/sizeof(WCHAR
));
269 wcscat(&szBuffer
[(sizeof(szShellAssoc
)/sizeof(WCHAR
))], szShell
);
270 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
272 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
273 if (result
== ERROR_SUCCESS
)
275 szBuffer
[Length
] = 0;
276 SH_AddStaticEntryForKey(This
, hKey
, szBuffer
);
290 if(SUCCEEDED(OleGetClipboard(&pda
)))
295 TRACE("pda=%p\n", pda
);
297 /* Set the FORMATETC structure*/
298 InitFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
299 if(SUCCEEDED(IDataObject_GetData(pda
,&formatetc
,&medium
)))
302 ReleaseStgMedium(&medium
);
305 IDataObject_Release(pda
);
312 DisablePasteOptions(HMENU hMenu
)
316 mii
.cbSize
= sizeof(mii
);
317 mii
.fMask
= MIIM_STATE
;
318 mii
.fState
= MFS_DISABLED
;
320 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERT
, FALSE
, &mii
));
321 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERTLINK
, FALSE
, &mii
));
325 IsShellExtensionAlreadyLoaded(IDefaultContextMenuImpl
* This
, const CLSID
* szClass
)
327 PDynamicShellEntry curEntry
= This
->dhead
;
331 if (!memcmp(&curEntry
->ClassID
, szClass
, sizeof(CLSID
)))
333 curEntry
= curEntry
->Next
;
341 SH_LoadDynamicContextMenuHandler(IDefaultContextMenuImpl
* This
, HKEY hKey
, const CLSID
* szClass
, BOOL bExternalInit
)
344 IContextMenu
* cmobj
;
345 IShellExtInit
*shext
;
346 PDynamicShellEntry curEntry
;
350 StringFromCLSID(szClass
, &pstr
);
352 TRACE("SH_LoadDynamicContextMenuHandler entered with This %p hKey %p szClass %s bExternalInit %u\n",This
, hKey
, wine_dbgstr_guid(szClass
), bExternalInit
);
353 //swprintf(szTemp, L"This %p hKey %p szClass %s bExternalInit %u", This, hKey, pstr, bExternalInit);
354 //MessageBoxW(NULL, szTemp, NULL, MB_OK);
356 if (IsShellExtensionAlreadyLoaded(This
, szClass
))
359 hr
= SHCoCreateInstance(NULL
, szClass
, NULL
, &IID_IContextMenu
, (void**)&cmobj
);
362 TRACE("SHCoCreateInstance failed %x\n", GetLastError());
368 hr
= IContextMenu_QueryInterface(cmobj
, &IID_IShellExtInit
, (void**)&shext
);
371 TRACE("Failed to query for interface IID_IShellExtInit\n");
372 IContextMenu_Release(cmobj
);
375 hr
= IShellExtInit_Initialize(shext
, NULL
, This
->pDataObj
, hKey
);
376 IShellExtInit_Release(shext
);
379 TRACE("Failed to initialize shell extension error %x\n", hr
);
380 IContextMenu_Release(cmobj
);
385 curEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry
));
388 IContextMenu_Release(cmobj
);
389 return E_OUTOFMEMORY
;
392 curEntry
->iIdCmdFirst
= 0;
393 curEntry
->Next
= NULL
;
394 curEntry
->NumIds
= 0;
395 curEntry
->CMenu
= cmobj
;
396 memcpy(&curEntry
->ClassID
, szClass
, sizeof(CLSID
));
400 PDynamicShellEntry pEntry
= This
->dhead
;
404 pEntry
= pEntry
->Next
;
407 pEntry
->Next
= curEntry
;
411 This
->dhead
= curEntry
;
415 if (!memcmp(szClass
, &CLSID_NewMenu
, sizeof(CLSID
)))
417 /* A REAL UGLY HACK */
418 INewItem_SetCurrentShellFolder(This
->dcm
.psf
);
427 EnumerateDynamicContextHandlerForKey(IDefaultContextMenuImpl
*This
, HKEY hRootKey
)
429 WCHAR szKey
[MAX_PATH
] = {0};
430 WCHAR szName
[MAX_PATH
] = {0};
431 DWORD dwIndex
, dwName
;
438 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 };
440 if (RegOpenKeyExW(hRootKey
, szShellEx
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
442 TRACE("RegOpenKeyExW failed for key %s\n", debugstr_w(szKey
));
451 res
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwName
, NULL
, NULL
, NULL
, NULL
);
452 if (res
== ERROR_SUCCESS
)
454 hResult
= CLSIDFromString(szName
, &clsid
);
458 if (RegGetValueW(hKey
, szName
, NULL
, RRF_RT_REG_SZ
, NULL
, szKey
, &dwName
) == ERROR_SUCCESS
)
460 hResult
= CLSIDFromString(szKey
, &clsid
);
463 if (SUCCEEDED(hResult
))
465 if (This
->bGroupPolicyActive
)
467 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
468 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
473 &dwName
) == ERROR_SUCCESS
)
475 SH_LoadDynamicContextMenuHandler(This
, hKey
, &clsid
, TRUE
);
480 SH_LoadDynamicContextMenuHandler(This
, hKey
, &clsid
, TRUE
);
485 }while(res
== ERROR_SUCCESS
);
494 InsertMenuItemsOfDynamicContextMenuExtension(IDefaultContextMenuImpl
* This
, HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
)
496 PDynamicShellEntry curEntry
;
501 This
->iIdSHEFirst
= 0;
502 This
->iIdSHELast
= 0;
506 curEntry
= This
->dhead
;
509 This
->iIdSHEFirst
= idCmdFirst
;
512 hResult
= IContextMenu_QueryContextMenu(curEntry
->CMenu
, hMenu
, indexMenu
++, idCmdFirst
, idCmdLast
, CMF_NORMAL
);
513 if (SUCCEEDED(hResult
))
515 curEntry
->iIdCmdFirst
= idCmdFirst
;
516 curEntry
->NumIds
= LOWORD(hResult
);
517 indexMenu
+= curEntry
->NumIds
;
518 idCmdFirst
+= curEntry
->NumIds
+ 0x10;
520 TRACE("curEntry %p hresult %x contextmenu %p cmdfirst %x num ids %x\n", curEntry
, hResult
, curEntry
->CMenu
, curEntry
->iIdCmdFirst
, curEntry
->NumIds
);
521 curEntry
= curEntry
->Next
;
524 This
->iIdSHELast
= idCmdFirst
;
525 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", This
->iIdSHEFirst
, This
->iIdSHELast
);
530 BuildBackgroundContextMenu(
531 IDefaultContextMenuImpl
* This
,
538 WCHAR szBuffer
[MAX_PATH
];
543 ZeroMemory(&mii
, sizeof(mii
));
545 TRACE("BuildBackgroundContextMenu entered\n");
547 if (!_ILIsDesktop(This
->dcm
.pidlFolder
))
549 /* view option is only available in browsing mode */
550 hSubMenu
= LoadMenuA(shell32_hInstance
, "MENU_001");
554 LoadStringW(shell32_hInstance
, FCIDM_SHVIEW_VIEW
, szBuffer
, MAX_PATH
);
555 szBuffer
[MAX_PATH
-1] = 0;
557 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
559 mii
.cbSize
= sizeof(mii
);
560 mii
.fMask
= MIIM_TYPE
| MIIM_STATE
| MIIM_SUBMENU
| MIIM_ID
;
561 mii
.fType
= MFT_STRING
;
562 mii
.wID
= iIdCmdFirst
++;
563 mii
.dwTypeData
= szBuffer
;
564 mii
.cch
= wcslen( mii
.dwTypeData
);
565 mii
.fState
= MFS_ENABLED
;
566 mii
.hSubMenu
= hSubMenu
;
567 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
568 DestroyMenu(hSubMenu
);
571 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
574 /* merge general background context menu in */
575 iIdCmdFirst
= Shell_MergeMenus(hMenu
, GetSubMenu(hSubMenu
, 0), indexMenu
, 0, 0xFFFF, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
) + 1;
576 DestroyMenu(hSubMenu
);
579 if (!HasClipboardData())
581 TRACE("disabling paste options\n");
582 DisablePasteOptions(hMenu
);
584 /* load extensions from HKCR\* key */
585 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
,
589 &hKey
) == ERROR_SUCCESS
)
591 EnumerateDynamicContextHandlerForKey(This
, hKey
);
595 /* load create new shell extension */
596 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
,
597 L
"CLSID\\{D969A300-E7FF-11d0-A93B-00A0C90F2719}",
600 &hKey
) == ERROR_SUCCESS
)
602 SH_LoadDynamicContextMenuHandler(This
, hKey
, &CLSID_NewMenu
, TRUE
);
606 if (InsertMenuItemsOfDynamicContextMenuExtension(This
, hMenu
, GetMenuItemCount(hMenu
)-1, iIdCmdFirst
, iIdCmdLast
))
608 /* seperate dynamic context menu items */
609 _InsertMenuItemW(hMenu
, GetMenuItemCount(hMenu
)-1, TRUE
, -1, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
617 AddStaticContextMenusToMenu(
620 IDefaultContextMenuImpl
* This
)
624 PStaticShellEntry curEntry
;
631 mii
.cbSize
= sizeof(mii
);
632 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
633 mii
.fType
= MFT_STRING
;
634 mii
.fState
= MFS_ENABLED
;
636 This
->iIdSCMFirst
= mii
.wID
;
638 curEntry
= This
->shead
;
642 fState
= MFS_ENABLED
;
643 if (!wcsicmp(curEntry
->szVerb
, L
"open"))
645 fState
|= MFS_DEFAULT
;
646 idResource
= IDS_OPEN_VERB
;
648 else if (!wcsicmp(curEntry
->szVerb
, L
"runas"))
649 idResource
= IDS_RUNAS_VERB
;
650 else if (!wcsicmp(curEntry
->szVerb
, L
"edit"))
651 idResource
= IDS_EDIT_VERB
;
652 else if (!wcsicmp(curEntry
->szVerb
, L
"find"))
653 idResource
= IDS_FIND_VERB
;
654 else if (!wcsicmp(curEntry
->szVerb
, L
"print"))
655 idResource
= IDS_PRINT_VERB
;
656 else if (!wcsicmp(curEntry
->szVerb
, L
"play"))
657 idResource
= IDS_PLAY_VERB
;
658 else if (!wcsicmp(curEntry
->szVerb
, L
"preview"))
659 idResource
= IDS_PREVIEW_VERB
;
665 if (LoadStringW(shell32_hInstance
, idResource
, szVerb
, sizeof(szVerb
)/sizeof(WCHAR
)))
667 /* use translated verb */
668 szVerb
[(sizeof(szVerb
)/sizeof(WCHAR
))-1] = L
'\0';
669 mii
.dwTypeData
= szVerb
;
674 Length
= wcslen(curEntry
->szClass
) + wcslen(curEntry
->szVerb
) + 8;
675 if (Length
< sizeof(szTemp
)/sizeof(WCHAR
))
677 wcscpy(szTemp
, curEntry
->szClass
);
678 wcscat(szTemp
, L
"\\shell\\");
679 wcscat(szTemp
, curEntry
->szVerb
);
680 dwSize
= sizeof(szVerb
);
682 if (RegGetValueW(HKEY_CLASSES_ROOT
, szTemp
, NULL
, RRF_RT_REG_SZ
, NULL
, szVerb
, &dwSize
) == ERROR_SUCCESS
)
684 /* use description for the menu entry */
685 mii
.dwTypeData
= szVerb
;
689 /* use verb for the menu entry */
690 mii
.dwTypeData
= curEntry
->szVerb
;
696 mii
.cch
= wcslen(mii
.dwTypeData
);
698 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
701 curEntry
= curEntry
->Next
;
703 This
->iIdSCMLast
= mii
.wID
- 1;
707 void WINAPI
_InsertMenuItemW (
719 ZeroMemory(&mii
, sizeof(mii
));
720 mii
.cbSize
= sizeof(mii
);
721 if (fType
== MFT_SEPARATOR
)
723 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
725 else if (fType
== MFT_STRING
)
727 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
728 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
730 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), szText
, sizeof(szText
)/sizeof(WCHAR
)))
732 szText
[(sizeof(szText
)/sizeof(WCHAR
))-1] = 0;
733 mii
.dwTypeData
= szText
;
737 TRACE("failed to load string %p\n", dwTypeData
);
743 mii
.dwTypeData
= (LPWSTR
) dwTypeData
;
750 InsertMenuItemW( hmenu
, indexMenu
, fByPosition
, &mii
);
754 BuildShellItemContextMenu(
755 IDefaultContextMenuImpl
* This
,
761 WCHAR szPath
[MAX_PATH
];
774 TRACE("BuildShellItemContextMenu entered\n");
776 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) == S_OK
)
778 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) == S_OK
)
780 pOffset
= wcsrchr(szPath
, L
'.');
783 /* enumerate dynamic/static for a given file class */
784 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pOffset
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
786 /* add static verbs */
787 SH_AddStaticEntryForFileClass(This
, pOffset
);
788 /* load dynamic extensions from file extension key */
789 EnumerateDynamicContextHandlerForKey(This
, hKey
);
792 dwSize
= sizeof(szTemp
);
793 if (RegGetValueW(HKEY_CLASSES_ROOT
, pOffset
, NULL
, RRF_RT_REG_SZ
, NULL
, szTemp
, &dwSize
) == ERROR_SUCCESS
)
795 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
797 /* add static verbs from progid key */
798 SH_AddStaticEntryForFileClass(This
, szTemp
);
799 /* load dynamic extensions from progid key */
800 EnumerateDynamicContextHandlerForKey(This
, hKey
);
805 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"*", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
807 /* load default extensions */
808 EnumerateDynamicContextHandlerForKey(This
, hKey
);
814 guid
= _ILGetGUIDPointer(This
->dcm
.apidl
[0]);
820 wcscpy(buffer
, L
"CLSID\\");
821 hr
= StringFromCLSID(guid
, &pwszCLSID
);
824 wcscpy(&buffer
[6], pwszCLSID
);
825 TRACE("buffer %s\n", debugstr_w(buffer
));
826 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
828 EnumerateDynamicContextHandlerForKey(This
, hKey
);
829 SH_AddStaticEntryForFileClass(This
, buffer
);
832 CoTaskMemFree(pwszCLSID
);
837 if (_ILIsDrive(This
->dcm
.apidl
[0]))
839 SH_AddStaticEntryForFileClass(This
, L
"Drive");
840 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Drive", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
842 EnumerateDynamicContextHandlerForKey(This
, hKey
);
848 /* add static actions */
849 rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
850 hr
= IShellFolder_GetAttributesOf(This
->dcm
.psf
, This
->dcm
.cidl
, This
->dcm
.apidl
, &rfg
);
854 if (rfg
& SFGAO_FOLDER
)
856 /* add the default verbs open / explore */
857 SH_AddStaticEntryForFileClass(This
, L
"Folder");
858 SH_AddStaticEntryForFileClass(This
, L
"Directory");
859 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Folder", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
861 EnumerateDynamicContextHandlerForKey(This
, hKey
);
864 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
866 EnumerateDynamicContextHandlerForKey(This
, hKey
);
872 if (rfg
& SFGAO_FILESYSTEM
)
874 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"AllFilesystemObjects", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
876 /* sendto service is registered here */
877 EnumerateDynamicContextHandlerForKey(This
, hKey
);
882 /* add static context menu handlers */
883 indexMenu
= AddStaticContextMenusToMenu(hMenu
, 0, This
);
884 /* now process dynamic context menu handlers */
885 indexMenu
= InsertMenuItemsOfDynamicContextMenuExtension(This
, hMenu
, indexMenu
, iIdCmdFirst
, iIdCmdLast
);
886 TRACE("indexMenu %d\n", indexMenu
);
888 if (_ILIsDrive(This
->dcm
.apidl
[0]))
890 /* The 'Format' option must be always available,
891 * thus it is not registered as a static shell extension
893 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
894 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0x7ABC, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
898 bClipboardData
= (HasClipboardData() && (rfg
& SFGAO_FILESYSTEM
));
899 if (rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
) || bClipboardData
)
901 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
902 if (rfg
& SFGAO_CANMOVE
)
903 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CUT
), MFS_ENABLED
);
904 if (rfg
& SFGAO_CANCOPY
)
905 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, MAKEINTRESOURCEW(IDS_COPY
), MFS_ENABLED
);
907 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_INSERT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_INSERT
), MFS_ENABLED
);
913 if (rfg
& SFGAO_CANLINK
)
916 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
917 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CREATELINK
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CREATELINK
), MFS_ENABLED
);
921 if (rfg
& SFGAO_CANDELETE
)
926 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
928 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DELETE
), MFS_ENABLED
);
931 if (rfg
& SFGAO_CANRENAME
)
935 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
937 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, MAKEINTRESOURCEW(IDS_RENAME
), MFS_ENABLED
);
941 if (rfg
& SFGAO_HASPROPSHEET
)
943 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
944 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
953 IDefaultContextMenu_fnQueryContextMenu(
954 IContextMenu2
*iface
,
961 IDefaultContextMenuImpl
* This
= impl_from_IContextMenu(iface
);
964 idCmdFirst
= BuildShellItemContextMenu(This
, hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
968 idCmdFirst
= BuildBackgroundContextMenu(This
, hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
976 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
)
979 LPSHELLVIEW lpSV
= NULL
;
982 if((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
984 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
986 IShellView_GetWindow(lpSV
, &hwndSV
);
990 if (LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_REFRESH
|| bRefresh
)
993 IShellView_Refresh(lpSV
);
998 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(LOWORD(lpcmi
->lpVerb
), 0), 0);
1006 IDefaultContextMenuImpl
*This
,
1007 LPCMINVOKECOMMANDINFO lpcmi
)
1011 FORMATETC formatetc
;
1012 LPITEMIDLIST
* apidl
;
1014 IShellFolder
*psfFrom
= NULL
, *psfDesktop
, *psfTarget
= NULL
;
1016 ISFHelper
*psfhlpdst
, *psfhlpsrc
;
1019 if (OleGetClipboard(&pda
) != S_OK
)
1022 InitFormatEtc(formatetc
, RegisterClipboardFormatA(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
1023 hr
= IDataObject_GetData(pda
,&formatetc
,&medium
);
1027 IDataObject_Release(pda
);
1031 /* lock the handle */
1032 lpcida
= GlobalLock(medium
.u
.hGlobal
);
1035 ReleaseStgMedium(&medium
);
1036 IDataObject_Release(pda
);
1040 /* convert the data into pidl */
1041 apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1046 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
1049 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1050 ReleaseStgMedium(&medium
);
1051 IDataObject_Release(pda
);
1055 if (FAILED(IShellFolder_BindToObject(psfDesktop
, pidl
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfFrom
)))
1057 ERR("no IShellFolder\n");
1059 IShellFolder_Release(psfDesktop
);
1061 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1062 ReleaseStgMedium(&medium
);
1063 IDataObject_Release(pda
);
1070 IShellFolder_Release(psfDesktop
);
1071 hr
= IShellFolder_BindToObject(This
->dcm
.psf
, This
->dcm
.apidl
[0], NULL
, &IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1075 IPersistFolder2
*ppf2
= NULL
;
1078 /* cidl is zero due to explorer view */
1079 hr
= IShellFolder_QueryInterface (This
->dcm
.psf
, &IID_IPersistFolder2
, (LPVOID
*) &ppf2
);
1082 hr
= IPersistFolder2_GetCurFolder (ppf2
, &pidl
);
1083 IPersistFolder2_Release(ppf2
);
1086 if (_ILIsDesktop(pidl
))
1088 /* use desktop shellfolder */
1089 psfTarget
= psfDesktop
;
1093 /* retrieve target desktop folder */
1094 hr
= IShellFolder_BindToObject(psfDesktop
, pidl
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1096 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
, _ILIsDesktop(pidl
));
1104 ERR("no IShellFolder\n");
1106 IShellFolder_Release(psfFrom
);
1108 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1109 ReleaseStgMedium(&medium
);
1110 IDataObject_Release(pda
);
1116 /* get source and destination shellfolder */
1117 if (FAILED(IShellFolder_QueryInterface(psfTarget
, &IID_ISFHelper
, (LPVOID
*)&psfhlpdst
)))
1119 ERR("no IID_ISFHelper for destination\n");
1121 IShellFolder_Release(psfFrom
);
1122 IShellFolder_Release(psfTarget
);
1124 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1125 ReleaseStgMedium(&medium
);
1126 IDataObject_Release(pda
);
1131 if (FAILED(IShellFolder_QueryInterface(psfFrom
, &IID_ISFHelper
, (LPVOID
*)&psfhlpsrc
)))
1133 ERR("no IID_ISFHelper for source\n");
1135 ISFHelper_Release(psfhlpdst
);
1136 IShellFolder_Release(psfFrom
);
1137 IShellFolder_Release(psfTarget
);
1139 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1140 ReleaseStgMedium(&medium
);
1141 IDataObject_Release(pda
);
1146 * do we want to perform a copy or move ???
1148 hr
= ISFHelper_CopyItems(psfhlpdst
, psfFrom
, lpcida
->cidl
, (LPCITEMIDLIST
*)apidl
);
1150 ISFHelper_Release(psfhlpdst
);
1151 ISFHelper_Release(psfhlpsrc
);
1152 IShellFolder_Release(psfFrom
);
1153 IShellFolder_Release(psfTarget
);
1155 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1156 ReleaseStgMedium(&medium
);
1157 IDataObject_Release(pda
);
1158 TRACE("CP result %x\n",hr
);
1165 IDefaultContextMenuImpl
*iface
,
1166 LPCMINVOKECOMMANDINFO lpcmi
)
1174 GetUniqueFileName(LPWSTR szBasePath
, LPWSTR szExt
, LPWSTR szTarget
, BOOL bShortcut
)
1176 UINT RetryCount
= 0, Length
;
1182 Length
= LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, szLnk
, sizeof(szLnk
)/sizeof(WCHAR
));
1190 swprintf(szTarget
, L
"%s%s(%u).%s", szLnk
, szBasePath
, RetryCount
, szExt
);
1192 swprintf(szTarget
, L
"%s%s.%s", szLnk
, szBasePath
, szExt
);
1197 swprintf(szTarget
, L
"%s(%u).%s", szBasePath
, RetryCount
, szExt
);
1199 swprintf(szTarget
, L
"%s.%s", szBasePath
, szExt
);
1202 hFile
= CreateFileW(szTarget
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1203 if (hFile
!= INVALID_HANDLE_VALUE
)
1209 }while(RetryCount
++ < 100);
1218 IDefaultContextMenuImpl
*This
,
1219 LPCMINVOKECOMMANDINFO lpcmi
)
1221 WCHAR szPath
[MAX_PATH
];
1222 WCHAR szTarget
[MAX_PATH
] = {0};
1223 WCHAR szDirPath
[MAX_PATH
];
1228 IShellLinkW
* nLink
;
1230 static WCHAR szLnk
[] = L
"lnk";
1232 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1234 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1238 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1241 pszExt
= wcsrchr(szPath
, L
'.');
1243 if (pszExt
&& !wcsicmp(pszExt
+ 1, szLnk
))
1245 if (!GetUniqueFileName(szPath
, pszExt
+ 1, szTarget
, TRUE
))
1248 hr
= IShellLink_ConstructFromFile(NULL
, &IID_IPersistFile
, This
->dcm
.apidl
[0], (LPVOID
*)&ipf
);
1253 hr
= IPersistFile_Save(ipf
, szTarget
, FALSE
);
1254 IPersistFile_Release(ipf
);
1255 NotifyShellViewWindow(lpcmi
, TRUE
);
1260 if (!GetUniqueFileName(szPath
, szLnk
, szTarget
, TRUE
))
1263 hr
= IShellLink_Constructor(NULL
, &IID_IShellLinkW
, (LPVOID
*)&nLink
);
1269 GetFullPathName(szPath
, MAX_PATH
, szDirPath
, &pszFile
);
1270 if (pszFile
) pszFile
[0] = 0;
1272 if (SUCCEEDED(IShellLinkW_SetPath(nLink
, szPath
)) &&
1273 SUCCEEDED(IShellLinkW_SetWorkingDirectory(nLink
, szDirPath
)))
1275 if (SUCCEEDED(IShellLinkW_QueryInterface(nLink
, &IID_IPersistFile
, (LPVOID
*)&ipf
)))
1277 hr
= IPersistFile_Save(ipf
, szTarget
, TRUE
);
1278 IPersistFile_Release(ipf
);
1281 IShellLinkW_Release(nLink
);
1282 NotifyShellViewWindow(lpcmi
, TRUE
);
1290 IDefaultContextMenuImpl
*This
,
1291 LPCMINVOKECOMMANDINFO lpcmi
)
1295 WCHAR szPath
[MAX_PATH
];
1298 LPSHELLBROWSER lpSB
;
1302 hr
= IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1305 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1308 ZeroMemory(szPath
, sizeof(szPath
));
1309 hr
= StrRetToBufW(&strTemp
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
);
1312 ERR("StrRetToBufW failed with %x\n", hr
);
1316 * implement deletion with multiple files
1319 ZeroMemory(&op
, sizeof(op
));
1320 op
.hwnd
= GetActiveWindow();
1321 op
.wFunc
= FO_DELETE
;
1323 op
.fFlags
= FOF_ALLOWUNDO
;
1324 ret
= SHFileOperationW(&op
);
1328 TRACE("SHFileOperation failed with %0x%x", GetLastError());
1332 /* get the active IShellView */
1333 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
1335 /* is the treeview focused */
1336 if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB
, FCW_TREE
, &hwnd
)))
1338 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1341 (void)TreeView_DeleteItem(hwnd
, hItem
);
1345 NotifyShellViewWindow(lpcmi
, TRUE
);
1354 IDefaultContextMenuImpl
*iface
,
1355 LPCMINVOKECOMMANDINFO lpcmi
,
1358 LPSHELLBROWSER lpSB
;
1360 LPDATAOBJECT pDataObj
;
1363 if (SUCCEEDED(SHCreateDataObject(iface
->dcm
.pidlFolder
, iface
->dcm
.cidl
, iface
->dcm
.apidl
, NULL
, &IID_IDataObject
, (void**)&pDataObj
)))
1365 hr
= OleSetClipboard(pDataObj
);
1366 IDataObject_Release(pDataObj
);
1370 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0);
1373 TRACE("failed to get shellbrowser\n");
1377 hr
= IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
);
1380 TRACE("failed to query the active shellview\n");
1384 hr
= IShellView_GetItemObject(lpSV
, SVGIO_SELECTION
, &IID_IDataObject
, (LPVOID
*)&pDataObj
);
1387 TRACE("failed to get item object\n");
1391 hr
= OleSetClipboard(pDataObj
);
1394 WARN("OleSetClipboard failed");
1396 IDataObject_Release(pDataObj
);
1397 IShellView_Release(lpSV
);
1404 IDefaultContextMenuImpl
*This
,
1405 LPCMINVOKECOMMANDINFO lpcmi
)
1407 LPSHELLBROWSER lpSB
;
1411 /* get the active IShellView */
1412 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
1414 /* is the treeview focused */
1415 if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB
, FCW_TREE
, &hwnd
)))
1417 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1420 (void)TreeView_EditLabel(hwnd
, hItem
);
1424 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
1426 IShellView_SelectItem(lpSV
, This
->dcm
.apidl
[0],
1427 SVSI_DESELECTOTHERS
|SVSI_EDIT
|SVSI_ENSUREVISIBLE
|SVSI_FOCUSED
|SVSI_SELECT
);
1428 IShellView_Release(lpSV
);
1438 IDefaultContextMenuImpl
*This
,
1439 LPCMINVOKECOMMANDINFO lpcmi
)
1441 WCHAR szDrive
[MAX_PATH
];
1444 if (This
->dcm
.cidl
&&_ILIsMyComputer(This
->dcm
.apidl
[0]))
1446 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1449 else if (This
->dcm
.cidl
== 0 && _ILIsDesktop(This
->dcm
.pidlFolder
))
1451 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1454 else if (_ILIsDrive(This
->dcm
.apidl
[0]))
1456 ILGetDisplayName(This
->dcm
.apidl
[0], szDrive
);
1457 SH_ShowDriveProperties(szDrive
, This
->dcm
.pidlFolder
, This
->dcm
.apidl
);
1460 else if (_ILIsNetHood(This
->dcm
.apidl
[0]))
1463 ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1464 L
"/n,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1465 NULL
, SW_SHOWDEFAULT
);
1468 else if (_ILIsBitBucket(This
->dcm
.apidl
[0]))
1471 * detect the drive path of bitbucket if appropiate
1474 SH_ShowRecycleBinProperties(L
'C');
1478 if (This
->dcm
.cidl
> 1)
1479 WARN("SHMultiFileProperties is not yet implemented\n");
1481 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1483 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1487 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szDrive
, MAX_PATH
) != S_OK
)
1490 return SH_ShowPropertiesDialog(szDrive
, This
->dcm
.pidlFolder
, This
->dcm
.apidl
);
1496 IDefaultContextMenuImpl
*This
,
1497 LPCMINVOKECOMMANDINFO lpcmi
)
1499 char sDrive
[5] = {0};
1501 if (!_ILGetDrive(This
->dcm
.apidl
[0], sDrive
, sizeof(sDrive
)))
1503 ERR("pidl is not a drive\n");
1507 SHFormatDrive(lpcmi
->hwnd
, sDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1513 DoDynamicShellExtensions(
1514 IDefaultContextMenuImpl
*This
,
1515 LPCMINVOKECOMMANDINFO lpcmi
)
1517 UINT verb
= LOWORD(lpcmi
->lpVerb
);
1518 PDynamicShellEntry pCurrent
= This
->dhead
;
1520 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, This
->iIdSHEFirst
, This
->iIdSHELast
);
1522 while(pCurrent
&& verb
> pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1523 pCurrent
= pCurrent
->Next
;
1528 if (verb
>= pCurrent
->iIdCmdFirst
&& verb
<= pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1530 /* invoke the dynamic context menu */
1531 lpcmi
->lpVerb
= MAKEINTRESOURCEA(verb
- pCurrent
->iIdCmdFirst
);
1532 return IContextMenu_InvokeCommand(pCurrent
->CMenu
, lpcmi
);
1541 DoStaticShellExtensions(
1542 IDefaultContextMenuImpl
*This
,
1543 LPCMINVOKECOMMANDINFO lpcmi
)
1546 WCHAR szPath
[MAX_PATH
];
1547 WCHAR szDir
[MAX_PATH
];
1548 SHELLEXECUTEINFOW sei
;
1549 PStaticShellEntry pCurrent
= This
->shead
;
1550 int verb
= LOWORD(lpcmi
->lpVerb
) - This
->iIdSCMFirst
;
1553 while(pCurrent
&& verb
-- > 0)
1554 pCurrent
= pCurrent
->Next
;
1560 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1562 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1566 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1569 wcscpy(szDir
, szPath
);
1570 PathRemoveFileSpec(szDir
);
1572 ZeroMemory(&sei
, sizeof(sei
));
1573 sei
.cbSize
= sizeof(sei
);
1574 sei
.fMask
= SEE_MASK_CLASSNAME
;
1575 sei
.lpClass
= pCurrent
->szClass
;
1576 sei
.hwnd
= lpcmi
->hwnd
;
1577 sei
.nShow
= SW_SHOWNORMAL
;
1578 sei
.lpVerb
= pCurrent
->szVerb
;
1579 sei
.lpFile
= szPath
;
1580 sei
.lpDirectory
= szDir
;
1581 ShellExecuteExW(&sei
);
1589 IDefaultContextMenu_fnInvokeCommand(
1590 IContextMenu2
*iface
,
1591 LPCMINVOKECOMMANDINFO lpcmi
)
1593 IDefaultContextMenuImpl
* This
= impl_from_IContextMenu(iface
);
1595 switch(LOWORD(lpcmi
->lpVerb
))
1597 case FCIDM_SHVIEW_BIGICON
:
1598 case FCIDM_SHVIEW_SMALLICON
:
1599 case FCIDM_SHVIEW_LISTVIEW
:
1600 case FCIDM_SHVIEW_REPORTVIEW
:
1601 case 0x30: /* FIX IDS in resource files */
1605 case FCIDM_SHVIEW_AUTOARRANGE
:
1606 case FCIDM_SHVIEW_SNAPTOGRID
:
1607 case FCIDM_SHVIEW_REFRESH
:
1608 return NotifyShellViewWindow(lpcmi
, FALSE
);
1609 case FCIDM_SHVIEW_INSERT
:
1610 case FCIDM_SHVIEW_INSERTLINK
:
1611 return DoPaste(This
, lpcmi
);
1612 case FCIDM_SHVIEW_OPEN
:
1613 case FCIDM_SHVIEW_EXPLORE
:
1614 return DoOpenOrExplore(This
, lpcmi
);
1615 case FCIDM_SHVIEW_COPY
:
1616 case FCIDM_SHVIEW_CUT
:
1617 return DoCopyOrCut(This
, lpcmi
, LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_COPY
);
1618 case FCIDM_SHVIEW_CREATELINK
:
1619 return DoCreateLink(This
, lpcmi
);
1620 case FCIDM_SHVIEW_DELETE
:
1621 return DoDelete(This
, lpcmi
);
1622 case FCIDM_SHVIEW_RENAME
:
1623 return DoRename(This
, lpcmi
);
1624 case FCIDM_SHVIEW_PROPERTIES
:
1625 return DoProperties(This
, lpcmi
);
1627 return DoFormat(This
, lpcmi
);
1630 if (This
->iIdSHEFirst
&& This
->iIdSHELast
)
1632 if (LOWORD(lpcmi
->lpVerb
) >= This
->iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= This
->iIdSHELast
)
1634 return DoDynamicShellExtensions(This
, lpcmi
);
1638 if (This
->iIdSCMFirst
&& This
->iIdSCMLast
)
1640 if (LOWORD(lpcmi
->lpVerb
) >= This
->iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= This
->iIdSCMLast
)
1642 return DoStaticShellExtensions(This
, lpcmi
);
1646 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi
->lpVerb
));
1647 return E_UNEXPECTED
;
1653 IDefaultContextMenu_fnGetCommandString(
1654 IContextMenu2
*iface
,
1668 IDefaultContextMenu_fnHandleMenuMsg(
1669 IContextMenu2
*iface
,
1678 static const IContextMenu2Vtbl cmvt
=
1680 IDefaultContextMenu_fnQueryInterface
,
1681 IDefaultContextMenu_fnAddRef
,
1682 IDefaultContextMenu_fnRelease
,
1683 IDefaultContextMenu_fnQueryContextMenu
,
1684 IDefaultContextMenu_fnInvokeCommand
,
1685 IDefaultContextMenu_fnGetCommandString
,
1686 IDefaultContextMenu_fnHandleMenuMsg
1690 IDefaultContextMenu_Constructor(
1691 const DEFCONTEXTMENU
*pdcm
,
1695 IDefaultContextMenuImpl
* This
;
1696 HRESULT hr
= E_FAIL
;
1697 IDataObject
* pDataObj
;
1699 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IDefaultContextMenuImpl
));
1702 This
->lpVtbl
= &cmvt
;
1704 TRACE("cidl %u\n", This
->dcm
.cidl
);
1705 if (SUCCEEDED(SHCreateDataObject(pdcm
->pidlFolder
, pdcm
->cidl
, pdcm
->apidl
, NULL
, &IID_IDataObject
, (void**)&pDataObj
)))
1707 This
->pDataObj
= pDataObj
;
1709 CopyMemory(&This
->dcm
, pdcm
, sizeof(DEFCONTEXTMENU
));
1710 hr
= IDefaultContextMenu_fnQueryInterface((IContextMenu2
*)This
, riid
, ppv
);
1712 IContextMenu_Release((IContextMenu2
*)This
);
1715 TRACE("This(%p)(%x) cidl %u\n",This
, hr
, This
->dcm
.cidl
);
1719 /*************************************************************************
1720 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1726 SHCreateDefaultContextMenu(
1727 const DEFCONTEXTMENU
*pdcm
,
1731 HRESULT hr
= E_FAIL
;
1734 hr
= IDefaultContextMenu_Constructor( pdcm
, riid
, ppv
);
1736 TRACE("pcm %p hr %x\n", pdcm
, hr
);
1740 /*************************************************************************
1741 * CDefFolderMenu_Create2 [SHELL32.701]
1747 CDefFolderMenu_Create2(
1748 LPCITEMIDLIST pidlFolder
,
1751 LPCITEMIDLIST
*apidl
,
1753 LPFNDFMCALLBACK lpfn
,
1755 const HKEY
*ahkeyClsKeys
,
1756 IContextMenu
**ppcm
)
1758 DEFCONTEXTMENU pdcm
;
1763 pdcm
.pidlFolder
= pidlFolder
;
1767 pdcm
.punkAssociationInfo
= NULL
;
1769 pdcm
.aKeys
= ahkeyClsKeys
;
1771 hr
= SHCreateDefaultContextMenu(&pdcm
, &IID_IContextMenu
, (void**)ppcm
);