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
51 WCHAR
*build_paths_list(LPCWSTR wszBasePath
, int cidl
, LPCITEMIDLIST
*pidls
);
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
);
289 if(SUCCEEDED(OleGetClipboard(&pda
)))
294 TRACE("pda=%p\n", pda
);
296 /* Set the FORMATETC structure*/
297 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
298 if(SUCCEEDED(IDataObject_GetData(pda
,&formatetc
,&medium
)))
301 ReleaseStgMedium(&medium
);
304 IDataObject_Release(pda
);
311 DisablePasteOptions(HMENU hMenu
)
315 mii
.cbSize
= sizeof(mii
);
316 mii
.fMask
= MIIM_STATE
;
317 mii
.fState
= MFS_DISABLED
;
319 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERT
, FALSE
, &mii
));
320 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERTLINK
, FALSE
, &mii
));
324 IsShellExtensionAlreadyLoaded(IDefaultContextMenuImpl
* This
, const CLSID
* szClass
)
326 PDynamicShellEntry curEntry
= This
->dhead
;
330 if (!memcmp(&curEntry
->ClassID
, szClass
, sizeof(CLSID
)))
332 curEntry
= curEntry
->Next
;
340 SH_LoadDynamicContextMenuHandler(IDefaultContextMenuImpl
* This
, HKEY hKey
, const CLSID
* szClass
, BOOL bExternalInit
)
343 IContextMenu
* cmobj
;
344 IShellExtInit
*shext
;
345 PDynamicShellEntry curEntry
;
349 StringFromCLSID(szClass
, &pstr
);
351 TRACE("SH_LoadDynamicContextMenuHandler entered with This %p hKey %p szClass %s bExternalInit %u\n",This
, hKey
, wine_dbgstr_guid(szClass
), bExternalInit
);
352 //swprintf(szTemp, L"This %p hKey %p szClass %s bExternalInit %u", This, hKey, pstr, bExternalInit);
353 //MessageBoxW(NULL, szTemp, NULL, MB_OK);
355 if (IsShellExtensionAlreadyLoaded(This
, szClass
))
358 hr
= SHCoCreateInstance(NULL
, szClass
, NULL
, &IID_IContextMenu
, (void**)&cmobj
);
361 TRACE("SHCoCreateInstance failed %x\n", GetLastError());
367 hr
= IContextMenu_QueryInterface(cmobj
, &IID_IShellExtInit
, (void**)&shext
);
370 TRACE("Failed to query for interface IID_IShellExtInit\n");
371 IContextMenu_Release(cmobj
);
374 hr
= IShellExtInit_Initialize(shext
, NULL
, This
->pDataObj
, hKey
);
375 IShellExtInit_Release(shext
);
378 TRACE("Failed to initialize shell extension error %x\n", hr
);
379 IContextMenu_Release(cmobj
);
384 curEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry
));
387 IContextMenu_Release(cmobj
);
388 return E_OUTOFMEMORY
;
391 curEntry
->iIdCmdFirst
= 0;
392 curEntry
->Next
= NULL
;
393 curEntry
->NumIds
= 0;
394 curEntry
->CMenu
= cmobj
;
395 memcpy(&curEntry
->ClassID
, szClass
, sizeof(CLSID
));
399 PDynamicShellEntry pEntry
= This
->dhead
;
403 pEntry
= pEntry
->Next
;
406 pEntry
->Next
= curEntry
;
410 This
->dhead
= curEntry
;
414 if (!memcmp(szClass
, &CLSID_NewMenu
, sizeof(CLSID
)))
416 /* A REAL UGLY HACK */
417 INewItem_SetCurrentShellFolder(This
->dcm
.psf
);
426 EnumerateDynamicContextHandlerForKey(IDefaultContextMenuImpl
*This
, HKEY hRootKey
)
428 WCHAR szKey
[MAX_PATH
] = {0};
429 WCHAR szName
[MAX_PATH
] = {0};
430 DWORD dwIndex
, dwName
;
437 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 };
439 if (RegOpenKeyExW(hRootKey
, szShellEx
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
441 TRACE("RegOpenKeyExW failed for key %s\n", debugstr_w(szKey
));
450 res
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwName
, NULL
, NULL
, NULL
, NULL
);
451 if (res
== ERROR_SUCCESS
)
453 hResult
= CLSIDFromString(szName
, &clsid
);
457 if (RegGetValueW(hKey
, szName
, NULL
, RRF_RT_REG_SZ
, NULL
, szKey
, &dwName
) == ERROR_SUCCESS
)
459 hResult
= CLSIDFromString(szKey
, &clsid
);
462 if (SUCCEEDED(hResult
))
464 if (This
->bGroupPolicyActive
)
466 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
467 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
472 &dwName
) == ERROR_SUCCESS
)
474 SH_LoadDynamicContextMenuHandler(This
, hKey
, &clsid
, TRUE
);
479 SH_LoadDynamicContextMenuHandler(This
, hKey
, &clsid
, TRUE
);
484 }while(res
== ERROR_SUCCESS
);
493 InsertMenuItemsOfDynamicContextMenuExtension(IDefaultContextMenuImpl
* This
, HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
)
495 PDynamicShellEntry curEntry
;
500 This
->iIdSHEFirst
= 0;
501 This
->iIdSHELast
= 0;
505 curEntry
= This
->dhead
;
508 This
->iIdSHEFirst
= idCmdFirst
;
511 hResult
= IContextMenu_QueryContextMenu(curEntry
->CMenu
, hMenu
, indexMenu
++, idCmdFirst
, idCmdLast
, CMF_NORMAL
);
512 if (SUCCEEDED(hResult
))
514 curEntry
->iIdCmdFirst
= idCmdFirst
;
515 curEntry
->NumIds
= LOWORD(hResult
);
516 indexMenu
+= curEntry
->NumIds
;
517 idCmdFirst
+= curEntry
->NumIds
+ 0x10;
519 TRACE("curEntry %p hresult %x contextmenu %p cmdfirst %x num ids %x\n", curEntry
, hResult
, curEntry
->CMenu
, curEntry
->iIdCmdFirst
, curEntry
->NumIds
);
520 curEntry
= curEntry
->Next
;
523 This
->iIdSHELast
= idCmdFirst
;
524 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", This
->iIdSHEFirst
, This
->iIdSHELast
);
529 BuildBackgroundContextMenu(
530 IDefaultContextMenuImpl
* This
,
537 WCHAR szBuffer
[MAX_PATH
];
542 ZeroMemory(&mii
, sizeof(mii
));
544 TRACE("BuildBackgroundContextMenu entered\n");
546 if (!_ILIsDesktop(This
->dcm
.pidlFolder
))
548 /* view option is only available in browsing mode */
549 hSubMenu
= LoadMenuA(shell32_hInstance
, "MENU_001");
553 LoadStringW(shell32_hInstance
, FCIDM_SHVIEW_VIEW
, szBuffer
, MAX_PATH
);
554 szBuffer
[MAX_PATH
-1] = 0;
556 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
558 mii
.cbSize
= sizeof(mii
);
559 mii
.fMask
= MIIM_TYPE
| MIIM_STATE
| MIIM_SUBMENU
| MIIM_ID
;
560 mii
.fType
= MFT_STRING
;
561 mii
.wID
= iIdCmdFirst
++;
562 mii
.dwTypeData
= szBuffer
;
563 mii
.cch
= wcslen( mii
.dwTypeData
);
564 mii
.fState
= MFS_ENABLED
;
565 mii
.hSubMenu
= hSubMenu
;
566 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
567 DestroyMenu(hSubMenu
);
570 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
573 /* merge general background context menu in */
574 iIdCmdFirst
= Shell_MergeMenus(hMenu
, GetSubMenu(hSubMenu
, 0), indexMenu
, 0, 0xFFFF, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
) + 1;
575 DestroyMenu(hSubMenu
);
578 if (!HasClipboardData())
580 TRACE("disabling paste options\n");
581 DisablePasteOptions(hMenu
);
583 /* load extensions from HKCR\* key */
584 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
,
588 &hKey
) == ERROR_SUCCESS
)
590 EnumerateDynamicContextHandlerForKey(This
, hKey
);
594 /* load create new shell extension */
595 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
,
596 L
"CLSID\\{D969A300-E7FF-11d0-A93B-00A0C90F2719}",
599 &hKey
) == ERROR_SUCCESS
)
601 SH_LoadDynamicContextMenuHandler(This
, hKey
, &CLSID_NewMenu
, TRUE
);
605 if (InsertMenuItemsOfDynamicContextMenuExtension(This
, hMenu
, GetMenuItemCount(hMenu
)-1, iIdCmdFirst
, iIdCmdLast
))
607 /* seperate dynamic context menu items */
608 _InsertMenuItemW(hMenu
, GetMenuItemCount(hMenu
)-1, TRUE
, -1, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
616 AddStaticContextMenusToMenu(
619 IDefaultContextMenuImpl
* This
)
623 PStaticShellEntry curEntry
;
630 mii
.cbSize
= sizeof(mii
);
631 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
632 mii
.fType
= MFT_STRING
;
633 mii
.fState
= MFS_ENABLED
;
635 This
->iIdSCMFirst
= mii
.wID
;
637 curEntry
= This
->shead
;
641 fState
= MFS_ENABLED
;
642 if (!wcsicmp(curEntry
->szVerb
, L
"open"))
644 fState
|= MFS_DEFAULT
;
645 idResource
= IDS_OPEN_VERB
;
647 else if (!wcsicmp(curEntry
->szVerb
, L
"explore"))
648 idResource
= IDS_EXPLORE_VERB
;
649 else if (!wcsicmp(curEntry
->szVerb
, L
"runas"))
650 idResource
= IDS_RUNAS_VERB
;
651 else if (!wcsicmp(curEntry
->szVerb
, L
"edit"))
652 idResource
= IDS_EDIT_VERB
;
653 else if (!wcsicmp(curEntry
->szVerb
, L
"find"))
654 idResource
= IDS_FIND_VERB
;
655 else if (!wcsicmp(curEntry
->szVerb
, L
"print"))
656 idResource
= IDS_PRINT_VERB
;
662 if (LoadStringW(shell32_hInstance
, idResource
, szVerb
, sizeof(szVerb
)/sizeof(WCHAR
)))
664 /* use translated verb */
665 szVerb
[(sizeof(szVerb
)/sizeof(WCHAR
))-1] = L
'\0';
666 mii
.dwTypeData
= szVerb
;
671 Length
= wcslen(curEntry
->szClass
) + wcslen(curEntry
->szVerb
) + 8;
672 if (Length
< sizeof(szTemp
)/sizeof(WCHAR
))
674 wcscpy(szTemp
, curEntry
->szClass
);
675 wcscat(szTemp
, L
"\\shell\\");
676 wcscat(szTemp
, curEntry
->szVerb
);
677 dwSize
= sizeof(szVerb
);
679 if (RegGetValueW(HKEY_CLASSES_ROOT
, szTemp
, NULL
, RRF_RT_REG_SZ
, NULL
, szVerb
, &dwSize
) == ERROR_SUCCESS
)
681 /* use description for the menu entry */
682 mii
.dwTypeData
= szVerb
;
686 /* use verb for the menu entry */
687 mii
.dwTypeData
= curEntry
->szVerb
;
693 mii
.cch
= wcslen(mii
.dwTypeData
);
695 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
698 curEntry
= curEntry
->Next
;
700 This
->iIdSCMLast
= mii
.wID
- 1;
704 void WINAPI
_InsertMenuItemW (
716 ZeroMemory(&mii
, sizeof(mii
));
717 mii
.cbSize
= sizeof(mii
);
718 if (fType
== MFT_SEPARATOR
)
720 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
722 else if (fType
== MFT_STRING
)
724 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
725 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
727 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), szText
, sizeof(szText
)/sizeof(WCHAR
)))
729 szText
[(sizeof(szText
)/sizeof(WCHAR
))-1] = 0;
730 mii
.dwTypeData
= szText
;
734 TRACE("failed to load string %p\n", dwTypeData
);
740 mii
.dwTypeData
= (LPWSTR
) dwTypeData
;
747 InsertMenuItemW( hmenu
, indexMenu
, fByPosition
, &mii
);
751 BuildShellItemContextMenu(
752 IDefaultContextMenuImpl
* This
,
758 WCHAR szPath
[MAX_PATH
];
771 TRACE("BuildShellItemContextMenu entered\n");
773 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) == S_OK
)
775 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) == S_OK
)
777 pOffset
= wcsrchr(szPath
, L
'.');
780 /* enumerate dynamic/static for a given file class */
781 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pOffset
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
783 /* add static verbs */
784 SH_AddStaticEntryForFileClass(This
, pOffset
);
785 /* load dynamic extensions from file extension key */
786 EnumerateDynamicContextHandlerForKey(This
, hKey
);
789 dwSize
= sizeof(szTemp
);
790 if (RegGetValueW(HKEY_CLASSES_ROOT
, pOffset
, NULL
, RRF_RT_REG_SZ
, NULL
, szTemp
, &dwSize
) == ERROR_SUCCESS
)
792 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
794 /* add static verbs from progid key */
795 SH_AddStaticEntryForFileClass(This
, szTemp
);
796 /* load dynamic extensions from progid key */
797 EnumerateDynamicContextHandlerForKey(This
, hKey
);
802 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"*", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
804 /* load default extensions */
805 EnumerateDynamicContextHandlerForKey(This
, hKey
);
811 guid
= _ILGetGUIDPointer(This
->dcm
.apidl
[0]);
817 wcscpy(buffer
, L
"CLSID\\");
818 hr
= StringFromCLSID(guid
, &pwszCLSID
);
821 wcscpy(&buffer
[6], pwszCLSID
);
822 TRACE("buffer %s\n", debugstr_w(buffer
));
823 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
825 EnumerateDynamicContextHandlerForKey(This
, hKey
);
826 SH_AddStaticEntryForFileClass(This
, buffer
);
829 CoTaskMemFree(pwszCLSID
);
834 if (_ILIsDrive(This
->dcm
.apidl
[0]))
836 SH_AddStaticEntryForFileClass(This
, L
"Drive");
837 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Drive", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
839 EnumerateDynamicContextHandlerForKey(This
, hKey
);
845 /* add static actions */
846 rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
847 hr
= IShellFolder_GetAttributesOf(This
->dcm
.psf
, This
->dcm
.cidl
, This
->dcm
.apidl
, &rfg
);
851 if (rfg
& SFGAO_FOLDER
)
853 /* add the default verbs open / explore */
854 SH_AddStaticEntryForFileClass(This
, L
"Folder");
855 SH_AddStaticEntryForFileClass(This
, L
"Directory");
856 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Folder", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
858 EnumerateDynamicContextHandlerForKey(This
, hKey
);
861 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
863 EnumerateDynamicContextHandlerForKey(This
, hKey
);
869 if (rfg
& SFGAO_FILESYSTEM
)
871 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"AllFilesystemObjects", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
873 /* sendto service is registered here */
874 EnumerateDynamicContextHandlerForKey(This
, hKey
);
879 /* add static context menu handlers */
880 indexMenu
= AddStaticContextMenusToMenu(hMenu
, 0, This
);
881 /* now process dynamic context menu handlers */
882 indexMenu
= InsertMenuItemsOfDynamicContextMenuExtension(This
, hMenu
, indexMenu
, iIdCmdFirst
, iIdCmdLast
);
883 TRACE("indexMenu %d\n", indexMenu
);
885 if (_ILIsDrive(This
->dcm
.apidl
[0]))
887 /* The 'Format' option must be always available,
888 * thus it is not registered as a static shell extension
890 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
891 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0x7ABC, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
895 bClipboardData
= (HasClipboardData() && (rfg
& SFGAO_FILESYSTEM
));
896 if (rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
) || bClipboardData
)
898 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
899 if (rfg
& SFGAO_CANMOVE
)
900 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CUT
), MFS_ENABLED
);
901 if (rfg
& SFGAO_CANCOPY
)
902 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, MAKEINTRESOURCEW(IDS_COPY
), MFS_ENABLED
);
904 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_INSERT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_INSERT
), MFS_ENABLED
);
910 if (rfg
& SFGAO_CANLINK
)
913 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
914 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CREATELINK
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CREATELINK
), MFS_ENABLED
);
918 if (rfg
& SFGAO_CANDELETE
)
923 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
925 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DELETE
), MFS_ENABLED
);
928 if (rfg
& SFGAO_CANRENAME
)
932 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
934 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, MAKEINTRESOURCEW(IDS_RENAME
), MFS_ENABLED
);
938 if (rfg
& SFGAO_HASPROPSHEET
)
940 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
941 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
950 IDefaultContextMenu_fnQueryContextMenu(
951 IContextMenu2
*iface
,
958 IDefaultContextMenuImpl
* This
= impl_from_IContextMenu(iface
);
961 idCmdFirst
= BuildShellItemContextMenu(This
, hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
965 idCmdFirst
= BuildBackgroundContextMenu(This
, hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
973 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
)
976 LPSHELLVIEW lpSV
= NULL
;
979 if((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
981 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
983 IShellView_GetWindow(lpSV
, &hwndSV
);
987 if (LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_REFRESH
|| bRefresh
)
990 IShellView_Refresh(lpSV
);
995 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(LOWORD(lpcmi
->lpVerb
), 0), 0);
1003 IDefaultContextMenuImpl
*This
,
1004 LPCMINVOKECOMMANDINFO lpcmi
)
1008 FORMATETC formatetc
;
1009 LPITEMIDLIST
* apidl
;
1011 IShellFolder
*psfFrom
= NULL
, *psfDesktop
, *psfTarget
= NULL
;
1013 ISFHelper
*psfhlpdst
, *psfhlpsrc
;
1016 if (OleGetClipboard(&pda
) != S_OK
)
1019 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
1020 hr
= IDataObject_GetData(pda
,&formatetc
,&medium
);
1024 IDataObject_Release(pda
);
1028 /* lock the handle */
1029 lpcida
= GlobalLock(medium
.u
.hGlobal
);
1032 ReleaseStgMedium(&medium
);
1033 IDataObject_Release(pda
);
1037 /* convert the data into pidl */
1038 apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1043 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
1046 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1047 ReleaseStgMedium(&medium
);
1048 IDataObject_Release(pda
);
1052 if (_ILIsDesktop(pidl
))
1054 /* use desktop shellfolder */
1055 psfFrom
= psfDesktop
;
1057 else if (FAILED(IShellFolder_BindToObject(psfDesktop
, pidl
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfFrom
)))
1059 ERR("no IShellFolder\n");
1061 IShellFolder_Release(psfDesktop
);
1063 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1064 ReleaseStgMedium(&medium
);
1065 IDataObject_Release(pda
);
1072 IShellFolder_Release(psfDesktop
);
1073 hr
= IShellFolder_BindToObject(This
->dcm
.psf
, This
->dcm
.apidl
[0], NULL
, &IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1077 IPersistFolder2
*ppf2
= NULL
;
1080 /* cidl is zero due to explorer view */
1081 hr
= IShellFolder_QueryInterface (This
->dcm
.psf
, &IID_IPersistFolder2
, (LPVOID
*) &ppf2
);
1084 hr
= IPersistFolder2_GetCurFolder (ppf2
, &pidl
);
1085 IPersistFolder2_Release(ppf2
);
1088 if (_ILIsDesktop(pidl
))
1090 /* use desktop shellfolder */
1091 psfTarget
= psfDesktop
;
1095 /* retrieve target desktop folder */
1096 hr
= IShellFolder_BindToObject(psfDesktop
, pidl
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1098 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
, _ILIsDesktop(pidl
));
1106 ERR("no IShellFolder\n");
1108 IShellFolder_Release(psfFrom
);
1110 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1111 ReleaseStgMedium(&medium
);
1112 IDataObject_Release(pda
);
1118 /* get source and destination shellfolder */
1119 if (FAILED(IShellFolder_QueryInterface(psfTarget
, &IID_ISFHelper
, (LPVOID
*)&psfhlpdst
)))
1121 ERR("no IID_ISFHelper for destination\n");
1123 IShellFolder_Release(psfFrom
);
1124 IShellFolder_Release(psfTarget
);
1126 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1127 ReleaseStgMedium(&medium
);
1128 IDataObject_Release(pda
);
1133 if (FAILED(IShellFolder_QueryInterface(psfFrom
, &IID_ISFHelper
, (LPVOID
*)&psfhlpsrc
)))
1135 ERR("no IID_ISFHelper for source\n");
1137 ISFHelper_Release(psfhlpdst
);
1138 IShellFolder_Release(psfFrom
);
1139 IShellFolder_Release(psfTarget
);
1141 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1142 ReleaseStgMedium(&medium
);
1143 IDataObject_Release(pda
);
1148 * do we want to perform a copy or move ???
1150 hr
= ISFHelper_CopyItems(psfhlpdst
, psfFrom
, lpcida
->cidl
, (LPCITEMIDLIST
*)apidl
);
1152 ISFHelper_Release(psfhlpdst
);
1153 ISFHelper_Release(psfhlpsrc
);
1154 IShellFolder_Release(psfFrom
);
1155 IShellFolder_Release(psfTarget
);
1157 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1158 ReleaseStgMedium(&medium
);
1159 IDataObject_Release(pda
);
1160 TRACE("CP result %x\n",hr
);
1167 IDefaultContextMenuImpl
*iface
,
1168 LPCMINVOKECOMMANDINFO lpcmi
)
1176 GetUniqueFileName(LPWSTR szBasePath
, LPWSTR szExt
, LPWSTR szTarget
, BOOL bShortcut
)
1178 UINT RetryCount
= 0, Length
;
1184 Length
= LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, szLnk
, sizeof(szLnk
)/sizeof(WCHAR
));
1192 swprintf(szTarget
, L
"%s%s(%u).%s", szLnk
, szBasePath
, RetryCount
, szExt
);
1194 swprintf(szTarget
, L
"%s%s.%s", szLnk
, szBasePath
, szExt
);
1199 swprintf(szTarget
, L
"%s(%u).%s", szBasePath
, RetryCount
, szExt
);
1201 swprintf(szTarget
, L
"%s.%s", szBasePath
, szExt
);
1204 hFile
= CreateFileW(szTarget
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1205 if (hFile
!= INVALID_HANDLE_VALUE
)
1211 }while(RetryCount
++ < 100);
1220 IDefaultContextMenuImpl
*This
,
1221 LPCMINVOKECOMMANDINFO lpcmi
)
1223 WCHAR szPath
[MAX_PATH
];
1224 WCHAR szTarget
[MAX_PATH
] = {0};
1225 WCHAR szDirPath
[MAX_PATH
];
1230 IShellLinkW
* nLink
;
1232 static WCHAR szLnk
[] = L
"lnk";
1234 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1236 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1240 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1243 pszExt
= wcsrchr(szPath
, L
'.');
1245 if (pszExt
&& !wcsicmp(pszExt
+ 1, szLnk
))
1247 if (!GetUniqueFileName(szPath
, pszExt
+ 1, szTarget
, TRUE
))
1250 hr
= IShellLink_ConstructFromFile(NULL
, &IID_IPersistFile
, This
->dcm
.apidl
[0], (LPVOID
*)&ipf
);
1255 hr
= IPersistFile_Save(ipf
, szTarget
, FALSE
);
1256 IPersistFile_Release(ipf
);
1257 NotifyShellViewWindow(lpcmi
, TRUE
);
1262 if (!GetUniqueFileName(szPath
, szLnk
, szTarget
, TRUE
))
1265 hr
= IShellLink_Constructor(NULL
, &IID_IShellLinkW
, (LPVOID
*)&nLink
);
1271 GetFullPathName(szPath
, MAX_PATH
, szDirPath
, &pszFile
);
1272 if (pszFile
) pszFile
[0] = 0;
1274 if (SUCCEEDED(IShellLinkW_SetPath(nLink
, szPath
)) &&
1275 SUCCEEDED(IShellLinkW_SetWorkingDirectory(nLink
, szDirPath
)))
1277 if (SUCCEEDED(IShellLinkW_QueryInterface(nLink
, &IID_IPersistFile
, (LPVOID
*)&ipf
)))
1279 hr
= IPersistFile_Save(ipf
, szTarget
, TRUE
);
1280 IPersistFile_Release(ipf
);
1283 IShellLinkW_Release(nLink
);
1284 NotifyShellViewWindow(lpcmi
, TRUE
);
1292 IDefaultContextMenuImpl
*This
,
1293 LPCMINVOKECOMMANDINFO lpcmi
)
1297 WCHAR szPath
[MAX_PATH
];
1298 LPWSTR wszPath
, wszPos
;
1301 LPSHELLBROWSER lpSB
;
1304 hr
= IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1307 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1310 ZeroMemory(szPath
, sizeof(szPath
));
1311 hr
= StrRetToBufW(&strTemp
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
);
1314 ERR("StrRetToBufW failed with %x\n", hr
);
1318 /* Only keep the base path */
1319 wszPos
= strrchrW(szPath
, '\\');
1322 *(wszPos
+ 1) = '\0';
1325 wszPath
= build_paths_list(szPath
, This
->dcm
.cidl
, This
->dcm
.apidl
);
1327 ZeroMemory(&op
, sizeof(op
));
1328 op
.hwnd
= GetActiveWindow();
1329 op
.wFunc
= FO_DELETE
;
1331 op
.fFlags
= FOF_ALLOWUNDO
;
1332 ret
= SHFileOperationW(&op
);
1336 ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(wszPath
));
1340 /* get the active IShellView */
1341 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
1343 /* is the treeview focused */
1344 if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB
, FCW_TREE
, &hwnd
)))
1346 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1349 (void)TreeView_DeleteItem(hwnd
, hItem
);
1353 NotifyShellViewWindow(lpcmi
, TRUE
);
1355 HeapFree(GetProcessHeap(), 0, wszPath
);
1363 IDefaultContextMenuImpl
*iface
,
1364 LPCMINVOKECOMMANDINFO lpcmi
,
1367 LPSHELLBROWSER lpSB
;
1369 LPDATAOBJECT pDataObj
;
1372 if (SUCCEEDED(SHCreateDataObject(iface
->dcm
.pidlFolder
, iface
->dcm
.cidl
, iface
->dcm
.apidl
, NULL
, &IID_IDataObject
, (void**)&pDataObj
)))
1374 hr
= OleSetClipboard(pDataObj
);
1375 IDataObject_Release(pDataObj
);
1379 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0);
1382 TRACE("failed to get shellbrowser\n");
1386 hr
= IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
);
1389 TRACE("failed to query the active shellview\n");
1393 hr
= IShellView_GetItemObject(lpSV
, SVGIO_SELECTION
, &IID_IDataObject
, (LPVOID
*)&pDataObj
);
1396 TRACE("failed to get item object\n");
1400 hr
= OleSetClipboard(pDataObj
);
1403 WARN("OleSetClipboard failed");
1405 IDataObject_Release(pDataObj
);
1406 IShellView_Release(lpSV
);
1413 IDefaultContextMenuImpl
*This
,
1414 LPCMINVOKECOMMANDINFO lpcmi
)
1416 LPSHELLBROWSER lpSB
;
1420 /* get the active IShellView */
1421 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
1423 /* is the treeview focused */
1424 if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB
, FCW_TREE
, &hwnd
)))
1426 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1429 (void)TreeView_EditLabel(hwnd
, hItem
);
1433 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
1435 IShellView_SelectItem(lpSV
, This
->dcm
.apidl
[0],
1436 SVSI_DESELECTOTHERS
|SVSI_EDIT
|SVSI_ENSUREVISIBLE
|SVSI_FOCUSED
|SVSI_SELECT
);
1437 IShellView_Release(lpSV
);
1447 IDefaultContextMenuImpl
*This
,
1448 LPCMINVOKECOMMANDINFO lpcmi
)
1450 WCHAR szDrive
[MAX_PATH
];
1453 if (This
->dcm
.cidl
&&_ILIsMyComputer(This
->dcm
.apidl
[0]))
1455 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1458 else if (This
->dcm
.cidl
== 0 && _ILIsDesktop(This
->dcm
.pidlFolder
))
1460 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1463 else if (_ILIsDrive(This
->dcm
.apidl
[0]))
1465 ILGetDisplayName(This
->dcm
.apidl
[0], szDrive
);
1466 SH_ShowDriveProperties(szDrive
, This
->dcm
.pidlFolder
, This
->dcm
.apidl
);
1469 else if (_ILIsNetHood(This
->dcm
.apidl
[0]))
1472 ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1473 L
"/n,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1474 NULL
, SW_SHOWDEFAULT
);
1477 else if (_ILIsBitBucket(This
->dcm
.apidl
[0]))
1480 * detect the drive path of bitbucket if appropiate
1483 SH_ShowRecycleBinProperties(L
'C');
1487 if (This
->dcm
.cidl
> 1)
1488 WARN("SHMultiFileProperties is not yet implemented\n");
1490 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1492 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1496 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szDrive
, MAX_PATH
) != S_OK
)
1499 return SH_ShowPropertiesDialog(szDrive
, This
->dcm
.pidlFolder
, This
->dcm
.apidl
);
1505 IDefaultContextMenuImpl
*This
,
1506 LPCMINVOKECOMMANDINFO lpcmi
)
1508 char sDrive
[5] = {0};
1510 if (!_ILGetDrive(This
->dcm
.apidl
[0], sDrive
, sizeof(sDrive
)))
1512 ERR("pidl is not a drive\n");
1516 SHFormatDrive(lpcmi
->hwnd
, sDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1522 DoDynamicShellExtensions(
1523 IDefaultContextMenuImpl
*This
,
1524 LPCMINVOKECOMMANDINFO lpcmi
)
1526 UINT verb
= LOWORD(lpcmi
->lpVerb
);
1527 PDynamicShellEntry pCurrent
= This
->dhead
;
1529 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, This
->iIdSHEFirst
, This
->iIdSHELast
);
1531 while(pCurrent
&& verb
> pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1532 pCurrent
= pCurrent
->Next
;
1537 if (verb
>= pCurrent
->iIdCmdFirst
&& verb
<= pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1539 /* invoke the dynamic context menu */
1540 lpcmi
->lpVerb
= MAKEINTRESOURCEA(verb
- pCurrent
->iIdCmdFirst
);
1541 return IContextMenu_InvokeCommand(pCurrent
->CMenu
, lpcmi
);
1550 DoStaticShellExtensions(
1551 IDefaultContextMenuImpl
*This
,
1552 LPCMINVOKECOMMANDINFO lpcmi
)
1555 WCHAR szPath
[MAX_PATH
];
1556 WCHAR szDir
[MAX_PATH
];
1557 SHELLEXECUTEINFOW sei
;
1558 PStaticShellEntry pCurrent
= This
->shead
;
1559 int verb
= LOWORD(lpcmi
->lpVerb
) - This
->iIdSCMFirst
;
1562 while(pCurrent
&& verb
-- > 0)
1563 pCurrent
= pCurrent
->Next
;
1569 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1571 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1575 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1578 wcscpy(szDir
, szPath
);
1579 PathRemoveFileSpec(szDir
);
1581 ZeroMemory(&sei
, sizeof(sei
));
1582 sei
.cbSize
= sizeof(sei
);
1583 sei
.fMask
= SEE_MASK_CLASSNAME
;
1584 sei
.lpClass
= pCurrent
->szClass
;
1585 sei
.hwnd
= lpcmi
->hwnd
;
1586 sei
.nShow
= SW_SHOWNORMAL
;
1587 sei
.lpVerb
= pCurrent
->szVerb
;
1588 sei
.lpFile
= szPath
;
1589 sei
.lpDirectory
= szDir
;
1590 ShellExecuteExW(&sei
);
1598 IDefaultContextMenu_fnInvokeCommand(
1599 IContextMenu2
*iface
,
1600 LPCMINVOKECOMMANDINFO lpcmi
)
1602 IDefaultContextMenuImpl
* This
= impl_from_IContextMenu(iface
);
1604 switch(LOWORD(lpcmi
->lpVerb
))
1606 case FCIDM_SHVIEW_BIGICON
:
1607 case FCIDM_SHVIEW_SMALLICON
:
1608 case FCIDM_SHVIEW_LISTVIEW
:
1609 case FCIDM_SHVIEW_REPORTVIEW
:
1610 case 0x30: /* FIX IDS in resource files */
1614 case FCIDM_SHVIEW_AUTOARRANGE
:
1615 case FCIDM_SHVIEW_SNAPTOGRID
:
1616 case FCIDM_SHVIEW_REFRESH
:
1617 return NotifyShellViewWindow(lpcmi
, FALSE
);
1618 case FCIDM_SHVIEW_INSERT
:
1619 case FCIDM_SHVIEW_INSERTLINK
:
1620 return DoPaste(This
, lpcmi
);
1621 case FCIDM_SHVIEW_OPEN
:
1622 case FCIDM_SHVIEW_EXPLORE
:
1623 return DoOpenOrExplore(This
, lpcmi
);
1624 case FCIDM_SHVIEW_COPY
:
1625 case FCIDM_SHVIEW_CUT
:
1626 return DoCopyOrCut(This
, lpcmi
, LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_COPY
);
1627 case FCIDM_SHVIEW_CREATELINK
:
1628 return DoCreateLink(This
, lpcmi
);
1629 case FCIDM_SHVIEW_DELETE
:
1630 return DoDelete(This
, lpcmi
);
1631 case FCIDM_SHVIEW_RENAME
:
1632 return DoRename(This
, lpcmi
);
1633 case FCIDM_SHVIEW_PROPERTIES
:
1634 return DoProperties(This
, lpcmi
);
1636 return DoFormat(This
, lpcmi
);
1639 if (This
->iIdSHEFirst
&& This
->iIdSHELast
)
1641 if (LOWORD(lpcmi
->lpVerb
) >= This
->iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= This
->iIdSHELast
)
1643 return DoDynamicShellExtensions(This
, lpcmi
);
1647 if (This
->iIdSCMFirst
&& This
->iIdSCMLast
)
1649 if (LOWORD(lpcmi
->lpVerb
) >= This
->iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= This
->iIdSCMLast
)
1651 return DoStaticShellExtensions(This
, lpcmi
);
1655 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi
->lpVerb
));
1656 return E_UNEXPECTED
;
1662 IDefaultContextMenu_fnGetCommandString(
1663 IContextMenu2
*iface
,
1677 IDefaultContextMenu_fnHandleMenuMsg(
1678 IContextMenu2
*iface
,
1687 static const IContextMenu2Vtbl cmvt
=
1689 IDefaultContextMenu_fnQueryInterface
,
1690 IDefaultContextMenu_fnAddRef
,
1691 IDefaultContextMenu_fnRelease
,
1692 IDefaultContextMenu_fnQueryContextMenu
,
1693 IDefaultContextMenu_fnInvokeCommand
,
1694 IDefaultContextMenu_fnGetCommandString
,
1695 IDefaultContextMenu_fnHandleMenuMsg
1699 IDefaultContextMenu_Constructor(
1700 const DEFCONTEXTMENU
*pdcm
,
1704 IDefaultContextMenuImpl
* This
;
1705 HRESULT hr
= E_FAIL
;
1706 IDataObject
* pDataObj
;
1708 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IDefaultContextMenuImpl
));
1711 This
->lpVtbl
= &cmvt
;
1713 TRACE("cidl %u\n", This
->dcm
.cidl
);
1714 if (SUCCEEDED(SHCreateDataObject(pdcm
->pidlFolder
, pdcm
->cidl
, pdcm
->apidl
, NULL
, &IID_IDataObject
, (void**)&pDataObj
)))
1716 This
->pDataObj
= pDataObj
;
1718 CopyMemory(&This
->dcm
, pdcm
, sizeof(DEFCONTEXTMENU
));
1719 hr
= IDefaultContextMenu_fnQueryInterface((IContextMenu2
*)This
, riid
, ppv
);
1721 IContextMenu_Release((IContextMenu2
*)This
);
1724 TRACE("This(%p)(%x) cidl %u\n",This
, hr
, This
->dcm
.cidl
);
1728 /*************************************************************************
1729 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1735 SHCreateDefaultContextMenu(
1736 const DEFCONTEXTMENU
*pdcm
,
1740 HRESULT hr
= E_FAIL
;
1743 hr
= IDefaultContextMenu_Constructor( pdcm
, riid
, ppv
);
1745 TRACE("pcm %p hr %x\n", pdcm
, hr
);
1749 /*************************************************************************
1750 * CDefFolderMenu_Create2 [SHELL32.701]
1756 CDefFolderMenu_Create2(
1757 LPCITEMIDLIST pidlFolder
,
1760 LPCITEMIDLIST
*apidl
,
1762 LPFNDFMCALLBACK lpfn
,
1764 const HKEY
*ahkeyClsKeys
,
1765 IContextMenu
**ppcm
)
1767 DEFCONTEXTMENU pdcm
;
1772 pdcm
.pidlFolder
= pidlFolder
;
1776 pdcm
.punkAssociationInfo
= NULL
;
1778 pdcm
.aKeys
= ahkeyClsKeys
;
1780 hr
= SHCreateDefaultContextMenu(&pdcm
, &IID_IContextMenu
, (void**)ppcm
);