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
);
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
"runas"))
648 idResource
= IDS_RUNAS_VERB
;
649 else if (!wcsicmp(curEntry
->szVerb
, L
"edit"))
650 idResource
= IDS_EDIT_VERB
;
651 else if (!wcsicmp(curEntry
->szVerb
, L
"find"))
652 idResource
= IDS_FIND_VERB
;
653 else if (!wcsicmp(curEntry
->szVerb
, L
"print"))
654 idResource
= IDS_PRINT_VERB
;
655 else if (!wcsicmp(curEntry
->szVerb
, L
"play"))
656 idResource
= IDS_PLAY_VERB
;
657 else if (!wcsicmp(curEntry
->szVerb
, L
"preview"))
658 idResource
= IDS_PREVIEW_VERB
;
664 if (LoadStringW(shell32_hInstance
, idResource
, szVerb
, sizeof(szVerb
)/sizeof(WCHAR
)))
666 /* use translated verb */
667 szVerb
[(sizeof(szVerb
)/sizeof(WCHAR
))-1] = L
'\0';
668 mii
.dwTypeData
= szVerb
;
673 Length
= wcslen(curEntry
->szClass
) + wcslen(curEntry
->szVerb
) + 8;
674 if (Length
< sizeof(szTemp
)/sizeof(WCHAR
))
676 wcscpy(szTemp
, curEntry
->szClass
);
677 wcscat(szTemp
, L
"\\shell\\");
678 wcscat(szTemp
, curEntry
->szVerb
);
679 dwSize
= sizeof(szVerb
);
681 if (RegGetValueW(HKEY_CLASSES_ROOT
, szTemp
, NULL
, RRF_RT_REG_SZ
, NULL
, szVerb
, &dwSize
) == ERROR_SUCCESS
)
683 /* use description for the menu entry */
684 mii
.dwTypeData
= szVerb
;
688 /* use verb for the menu entry */
689 mii
.dwTypeData
= curEntry
->szVerb
;
695 mii
.cch
= wcslen(mii
.dwTypeData
);
697 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
700 curEntry
= curEntry
->Next
;
702 This
->iIdSCMLast
= mii
.wID
- 1;
706 void WINAPI
_InsertMenuItemW (
718 ZeroMemory(&mii
, sizeof(mii
));
719 mii
.cbSize
= sizeof(mii
);
720 if (fType
== MFT_SEPARATOR
)
722 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
724 else if (fType
== MFT_STRING
)
726 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
727 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
729 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), szText
, sizeof(szText
)/sizeof(WCHAR
)))
731 szText
[(sizeof(szText
)/sizeof(WCHAR
))-1] = 0;
732 mii
.dwTypeData
= szText
;
736 TRACE("failed to load string %p\n", dwTypeData
);
742 mii
.dwTypeData
= (LPWSTR
) dwTypeData
;
749 InsertMenuItemW( hmenu
, indexMenu
, fByPosition
, &mii
);
753 BuildShellItemContextMenu(
754 IDefaultContextMenuImpl
* This
,
760 WCHAR szPath
[MAX_PATH
];
773 TRACE("BuildShellItemContextMenu entered\n");
775 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) == S_OK
)
777 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) == S_OK
)
779 pOffset
= wcsrchr(szPath
, L
'.');
782 /* enumerate dynamic/static for a given file class */
783 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pOffset
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
785 /* add static verbs */
786 SH_AddStaticEntryForFileClass(This
, pOffset
);
787 /* load dynamic extensions from file extension key */
788 EnumerateDynamicContextHandlerForKey(This
, hKey
);
791 dwSize
= sizeof(szTemp
);
792 if (RegGetValueW(HKEY_CLASSES_ROOT
, pOffset
, NULL
, RRF_RT_REG_SZ
, NULL
, szTemp
, &dwSize
) == ERROR_SUCCESS
)
794 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
796 /* add static verbs from progid key */
797 SH_AddStaticEntryForFileClass(This
, szTemp
);
798 /* load dynamic extensions from progid key */
799 EnumerateDynamicContextHandlerForKey(This
, hKey
);
804 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"*", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
806 /* load default extensions */
807 EnumerateDynamicContextHandlerForKey(This
, hKey
);
813 guid
= _ILGetGUIDPointer(This
->dcm
.apidl
[0]);
819 wcscpy(buffer
, L
"CLSID\\");
820 hr
= StringFromCLSID(guid
, &pwszCLSID
);
823 wcscpy(&buffer
[6], pwszCLSID
);
824 TRACE("buffer %s\n", debugstr_w(buffer
));
825 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
827 EnumerateDynamicContextHandlerForKey(This
, hKey
);
828 SH_AddStaticEntryForFileClass(This
, buffer
);
831 CoTaskMemFree(pwszCLSID
);
836 if (_ILIsDrive(This
->dcm
.apidl
[0]))
838 SH_AddStaticEntryForFileClass(This
, L
"Drive");
839 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Drive", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
841 EnumerateDynamicContextHandlerForKey(This
, hKey
);
847 /* add static actions */
848 rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
849 hr
= IShellFolder_GetAttributesOf(This
->dcm
.psf
, This
->dcm
.cidl
, This
->dcm
.apidl
, &rfg
);
853 if (rfg
& SFGAO_FOLDER
)
855 /* add the default verbs open / explore */
856 SH_AddStaticEntryForFileClass(This
, L
"Folder");
857 SH_AddStaticEntryForFileClass(This
, L
"Directory");
858 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Folder", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
860 EnumerateDynamicContextHandlerForKey(This
, hKey
);
863 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
865 EnumerateDynamicContextHandlerForKey(This
, hKey
);
871 if (rfg
& SFGAO_FILESYSTEM
)
873 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"AllFilesystemObjects", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
875 /* sendto service is registered here */
876 EnumerateDynamicContextHandlerForKey(This
, hKey
);
881 /* add static context menu handlers */
882 indexMenu
= AddStaticContextMenusToMenu(hMenu
, 0, This
);
883 /* now process dynamic context menu handlers */
884 indexMenu
= InsertMenuItemsOfDynamicContextMenuExtension(This
, hMenu
, indexMenu
, iIdCmdFirst
, iIdCmdLast
);
885 TRACE("indexMenu %d\n", indexMenu
);
887 if (_ILIsDrive(This
->dcm
.apidl
[0]))
889 /* The 'Format' option must be always available,
890 * thus it is not registered as a static shell extension
892 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
893 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0x7ABC, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
897 bClipboardData
= (HasClipboardData() && (rfg
& SFGAO_FILESYSTEM
));
898 if (rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
) || bClipboardData
)
900 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
901 if (rfg
& SFGAO_CANMOVE
)
902 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CUT
), MFS_ENABLED
);
903 if (rfg
& SFGAO_CANCOPY
)
904 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, MAKEINTRESOURCEW(IDS_COPY
), MFS_ENABLED
);
906 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_INSERT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_INSERT
), MFS_ENABLED
);
912 if (rfg
& SFGAO_CANLINK
)
915 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
916 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CREATELINK
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CREATELINK
), MFS_ENABLED
);
920 if (rfg
& SFGAO_CANDELETE
)
925 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
927 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DELETE
), MFS_ENABLED
);
930 if (rfg
& SFGAO_CANRENAME
)
934 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
936 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, MAKEINTRESOURCEW(IDS_RENAME
), MFS_ENABLED
);
940 if (rfg
& SFGAO_HASPROPSHEET
)
942 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
943 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
952 IDefaultContextMenu_fnQueryContextMenu(
953 IContextMenu2
*iface
,
960 IDefaultContextMenuImpl
* This
= impl_from_IContextMenu(iface
);
963 idCmdFirst
= BuildShellItemContextMenu(This
, hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
967 idCmdFirst
= BuildBackgroundContextMenu(This
, hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
975 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
)
978 LPSHELLVIEW lpSV
= NULL
;
981 if((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
983 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
985 IShellView_GetWindow(lpSV
, &hwndSV
);
989 if (LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_REFRESH
|| bRefresh
)
992 IShellView_Refresh(lpSV
);
997 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(LOWORD(lpcmi
->lpVerb
), 0), 0);
1005 IDefaultContextMenuImpl
*This
,
1006 LPCMINVOKECOMMANDINFO lpcmi
)
1010 FORMATETC formatetc
;
1011 LPITEMIDLIST
* apidl
;
1013 IShellFolder
*psfFrom
= NULL
, *psfDesktop
, *psfTarget
= NULL
;
1015 ISFHelper
*psfhlpdst
, *psfhlpsrc
;
1018 if (OleGetClipboard(&pda
) != S_OK
)
1021 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
1022 hr
= IDataObject_GetData(pda
,&formatetc
,&medium
);
1026 IDataObject_Release(pda
);
1030 /* lock the handle */
1031 lpcida
= GlobalLock(medium
.u
.hGlobal
);
1034 ReleaseStgMedium(&medium
);
1035 IDataObject_Release(pda
);
1039 /* convert the data into pidl */
1040 apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1045 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
1048 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1049 ReleaseStgMedium(&medium
);
1050 IDataObject_Release(pda
);
1054 if (_ILIsDesktop(pidl
))
1056 /* use desktop shellfolder */
1057 psfFrom
= psfDesktop
;
1059 else if (FAILED(IShellFolder_BindToObject(psfDesktop
, pidl
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfFrom
)))
1061 ERR("no IShellFolder\n");
1063 IShellFolder_Release(psfDesktop
);
1065 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1066 ReleaseStgMedium(&medium
);
1067 IDataObject_Release(pda
);
1074 IShellFolder_Release(psfDesktop
);
1075 hr
= IShellFolder_BindToObject(This
->dcm
.psf
, This
->dcm
.apidl
[0], NULL
, &IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1079 IPersistFolder2
*ppf2
= NULL
;
1082 /* cidl is zero due to explorer view */
1083 hr
= IShellFolder_QueryInterface (This
->dcm
.psf
, &IID_IPersistFolder2
, (LPVOID
*) &ppf2
);
1086 hr
= IPersistFolder2_GetCurFolder (ppf2
, &pidl
);
1087 IPersistFolder2_Release(ppf2
);
1090 if (_ILIsDesktop(pidl
))
1092 /* use desktop shellfolder */
1093 psfTarget
= psfDesktop
;
1097 /* retrieve target desktop folder */
1098 hr
= IShellFolder_BindToObject(psfDesktop
, pidl
, NULL
, &IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1100 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
, _ILIsDesktop(pidl
));
1108 ERR("no IShellFolder\n");
1110 IShellFolder_Release(psfFrom
);
1112 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1113 ReleaseStgMedium(&medium
);
1114 IDataObject_Release(pda
);
1120 /* get source and destination shellfolder */
1121 if (FAILED(IShellFolder_QueryInterface(psfTarget
, &IID_ISFHelper
, (LPVOID
*)&psfhlpdst
)))
1123 ERR("no IID_ISFHelper for destination\n");
1125 IShellFolder_Release(psfFrom
);
1126 IShellFolder_Release(psfTarget
);
1128 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1129 ReleaseStgMedium(&medium
);
1130 IDataObject_Release(pda
);
1135 if (FAILED(IShellFolder_QueryInterface(psfFrom
, &IID_ISFHelper
, (LPVOID
*)&psfhlpsrc
)))
1137 ERR("no IID_ISFHelper for source\n");
1139 ISFHelper_Release(psfhlpdst
);
1140 IShellFolder_Release(psfFrom
);
1141 IShellFolder_Release(psfTarget
);
1143 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1144 ReleaseStgMedium(&medium
);
1145 IDataObject_Release(pda
);
1150 * do we want to perform a copy or move ???
1152 hr
= ISFHelper_CopyItems(psfhlpdst
, psfFrom
, lpcida
->cidl
, (LPCITEMIDLIST
*)apidl
);
1154 ISFHelper_Release(psfhlpdst
);
1155 ISFHelper_Release(psfhlpsrc
);
1156 IShellFolder_Release(psfFrom
);
1157 IShellFolder_Release(psfTarget
);
1159 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1160 ReleaseStgMedium(&medium
);
1161 IDataObject_Release(pda
);
1162 TRACE("CP result %x\n",hr
);
1169 IDefaultContextMenuImpl
*iface
,
1170 LPCMINVOKECOMMANDINFO lpcmi
)
1178 GetUniqueFileName(LPWSTR szBasePath
, LPWSTR szExt
, LPWSTR szTarget
, BOOL bShortcut
)
1180 UINT RetryCount
= 0, Length
;
1186 Length
= LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, szLnk
, sizeof(szLnk
)/sizeof(WCHAR
));
1194 swprintf(szTarget
, L
"%s%s(%u).%s", szLnk
, szBasePath
, RetryCount
, szExt
);
1196 swprintf(szTarget
, L
"%s%s.%s", szLnk
, szBasePath
, szExt
);
1201 swprintf(szTarget
, L
"%s(%u).%s", szBasePath
, RetryCount
, szExt
);
1203 swprintf(szTarget
, L
"%s.%s", szBasePath
, szExt
);
1206 hFile
= CreateFileW(szTarget
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1207 if (hFile
!= INVALID_HANDLE_VALUE
)
1213 }while(RetryCount
++ < 100);
1222 IDefaultContextMenuImpl
*This
,
1223 LPCMINVOKECOMMANDINFO lpcmi
)
1225 WCHAR szPath
[MAX_PATH
];
1226 WCHAR szTarget
[MAX_PATH
] = {0};
1227 WCHAR szDirPath
[MAX_PATH
];
1232 IShellLinkW
* nLink
;
1234 static WCHAR szLnk
[] = L
"lnk";
1236 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1238 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1242 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1245 pszExt
= wcsrchr(szPath
, L
'.');
1247 if (pszExt
&& !wcsicmp(pszExt
+ 1, szLnk
))
1249 if (!GetUniqueFileName(szPath
, pszExt
+ 1, szTarget
, TRUE
))
1252 hr
= IShellLink_ConstructFromFile(NULL
, &IID_IPersistFile
, This
->dcm
.apidl
[0], (LPVOID
*)&ipf
);
1257 hr
= IPersistFile_Save(ipf
, szTarget
, FALSE
);
1258 IPersistFile_Release(ipf
);
1259 NotifyShellViewWindow(lpcmi
, TRUE
);
1264 if (!GetUniqueFileName(szPath
, szLnk
, szTarget
, TRUE
))
1267 hr
= IShellLink_Constructor(NULL
, &IID_IShellLinkW
, (LPVOID
*)&nLink
);
1273 GetFullPathName(szPath
, MAX_PATH
, szDirPath
, &pszFile
);
1274 if (pszFile
) pszFile
[0] = 0;
1276 if (SUCCEEDED(IShellLinkW_SetPath(nLink
, szPath
)) &&
1277 SUCCEEDED(IShellLinkW_SetWorkingDirectory(nLink
, szDirPath
)))
1279 if (SUCCEEDED(IShellLinkW_QueryInterface(nLink
, &IID_IPersistFile
, (LPVOID
*)&ipf
)))
1281 hr
= IPersistFile_Save(ipf
, szTarget
, TRUE
);
1282 IPersistFile_Release(ipf
);
1285 IShellLinkW_Release(nLink
);
1286 NotifyShellViewWindow(lpcmi
, TRUE
);
1294 IDefaultContextMenuImpl
*This
,
1295 LPCMINVOKECOMMANDINFO lpcmi
)
1299 WCHAR szPath
[MAX_PATH
];
1302 LPSHELLBROWSER lpSB
;
1306 hr
= IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1309 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1312 ZeroMemory(szPath
, sizeof(szPath
));
1313 hr
= StrRetToBufW(&strTemp
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
);
1316 ERR("StrRetToBufW failed with %x\n", hr
);
1320 * implement deletion with multiple files
1323 ZeroMemory(&op
, sizeof(op
));
1324 op
.hwnd
= GetActiveWindow();
1325 op
.wFunc
= FO_DELETE
;
1327 op
.fFlags
= FOF_ALLOWUNDO
;
1328 ret
= SHFileOperationW(&op
);
1332 TRACE("SHFileOperation failed with %0x%x", GetLastError());
1336 /* get the active IShellView */
1337 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
1339 /* is the treeview focused */
1340 if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB
, FCW_TREE
, &hwnd
)))
1342 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1345 (void)TreeView_DeleteItem(hwnd
, hItem
);
1349 NotifyShellViewWindow(lpcmi
, TRUE
);
1358 IDefaultContextMenuImpl
*iface
,
1359 LPCMINVOKECOMMANDINFO lpcmi
,
1362 LPSHELLBROWSER lpSB
;
1364 LPDATAOBJECT pDataObj
;
1367 if (SUCCEEDED(SHCreateDataObject(iface
->dcm
.pidlFolder
, iface
->dcm
.cidl
, iface
->dcm
.apidl
, NULL
, &IID_IDataObject
, (void**)&pDataObj
)))
1369 hr
= OleSetClipboard(pDataObj
);
1370 IDataObject_Release(pDataObj
);
1374 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0);
1377 TRACE("failed to get shellbrowser\n");
1381 hr
= IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
);
1384 TRACE("failed to query the active shellview\n");
1388 hr
= IShellView_GetItemObject(lpSV
, SVGIO_SELECTION
, &IID_IDataObject
, (LPVOID
*)&pDataObj
);
1391 TRACE("failed to get item object\n");
1395 hr
= OleSetClipboard(pDataObj
);
1398 WARN("OleSetClipboard failed");
1400 IDataObject_Release(pDataObj
);
1401 IShellView_Release(lpSV
);
1408 IDefaultContextMenuImpl
*This
,
1409 LPCMINVOKECOMMANDINFO lpcmi
)
1411 LPSHELLBROWSER lpSB
;
1415 /* get the active IShellView */
1416 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
,0,0)))
1418 /* is the treeview focused */
1419 if (SUCCEEDED(IShellBrowser_GetControlWindow(lpSB
, FCW_TREE
, &hwnd
)))
1421 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1424 (void)TreeView_EditLabel(hwnd
, hItem
);
1428 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB
, &lpSV
)))
1430 IShellView_SelectItem(lpSV
, This
->dcm
.apidl
[0],
1431 SVSI_DESELECTOTHERS
|SVSI_EDIT
|SVSI_ENSUREVISIBLE
|SVSI_FOCUSED
|SVSI_SELECT
);
1432 IShellView_Release(lpSV
);
1442 IDefaultContextMenuImpl
*This
,
1443 LPCMINVOKECOMMANDINFO lpcmi
)
1445 WCHAR szDrive
[MAX_PATH
];
1448 if (This
->dcm
.cidl
&&_ILIsMyComputer(This
->dcm
.apidl
[0]))
1450 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1453 else if (This
->dcm
.cidl
== 0 && _ILIsDesktop(This
->dcm
.pidlFolder
))
1455 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1458 else if (_ILIsDrive(This
->dcm
.apidl
[0]))
1460 ILGetDisplayName(This
->dcm
.apidl
[0], szDrive
);
1461 SH_ShowDriveProperties(szDrive
, This
->dcm
.pidlFolder
, This
->dcm
.apidl
);
1464 else if (_ILIsNetHood(This
->dcm
.apidl
[0]))
1467 ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1468 L
"/n,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1469 NULL
, SW_SHOWDEFAULT
);
1472 else if (_ILIsBitBucket(This
->dcm
.apidl
[0]))
1475 * detect the drive path of bitbucket if appropiate
1478 SH_ShowRecycleBinProperties(L
'C');
1482 if (This
->dcm
.cidl
> 1)
1483 WARN("SHMultiFileProperties is not yet implemented\n");
1485 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1487 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1491 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szDrive
, MAX_PATH
) != S_OK
)
1494 return SH_ShowPropertiesDialog(szDrive
, This
->dcm
.pidlFolder
, This
->dcm
.apidl
);
1500 IDefaultContextMenuImpl
*This
,
1501 LPCMINVOKECOMMANDINFO lpcmi
)
1503 char sDrive
[5] = {0};
1505 if (!_ILGetDrive(This
->dcm
.apidl
[0], sDrive
, sizeof(sDrive
)))
1507 ERR("pidl is not a drive\n");
1511 SHFormatDrive(lpcmi
->hwnd
, sDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1517 DoDynamicShellExtensions(
1518 IDefaultContextMenuImpl
*This
,
1519 LPCMINVOKECOMMANDINFO lpcmi
)
1521 UINT verb
= LOWORD(lpcmi
->lpVerb
);
1522 PDynamicShellEntry pCurrent
= This
->dhead
;
1524 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, This
->iIdSHEFirst
, This
->iIdSHELast
);
1526 while(pCurrent
&& verb
> pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1527 pCurrent
= pCurrent
->Next
;
1532 if (verb
>= pCurrent
->iIdCmdFirst
&& verb
<= pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1534 /* invoke the dynamic context menu */
1535 lpcmi
->lpVerb
= MAKEINTRESOURCEA(verb
- pCurrent
->iIdCmdFirst
);
1536 return IContextMenu_InvokeCommand(pCurrent
->CMenu
, lpcmi
);
1545 DoStaticShellExtensions(
1546 IDefaultContextMenuImpl
*This
,
1547 LPCMINVOKECOMMANDINFO lpcmi
)
1550 WCHAR szPath
[MAX_PATH
];
1551 WCHAR szDir
[MAX_PATH
];
1552 SHELLEXECUTEINFOW sei
;
1553 PStaticShellEntry pCurrent
= This
->shead
;
1554 int verb
= LOWORD(lpcmi
->lpVerb
) - This
->iIdSCMFirst
;
1557 while(pCurrent
&& verb
-- > 0)
1558 pCurrent
= pCurrent
->Next
;
1564 if (IShellFolder2_GetDisplayNameOf(This
->dcm
.psf
, This
->dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1566 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1570 if (StrRetToBufW(&strFile
, This
->dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1573 wcscpy(szDir
, szPath
);
1574 PathRemoveFileSpec(szDir
);
1576 ZeroMemory(&sei
, sizeof(sei
));
1577 sei
.cbSize
= sizeof(sei
);
1578 sei
.fMask
= SEE_MASK_CLASSNAME
;
1579 sei
.lpClass
= pCurrent
->szClass
;
1580 sei
.hwnd
= lpcmi
->hwnd
;
1581 sei
.nShow
= SW_SHOWNORMAL
;
1582 sei
.lpVerb
= pCurrent
->szVerb
;
1583 sei
.lpFile
= szPath
;
1584 sei
.lpDirectory
= szDir
;
1585 ShellExecuteExW(&sei
);
1593 IDefaultContextMenu_fnInvokeCommand(
1594 IContextMenu2
*iface
,
1595 LPCMINVOKECOMMANDINFO lpcmi
)
1597 IDefaultContextMenuImpl
* This
= impl_from_IContextMenu(iface
);
1599 switch(LOWORD(lpcmi
->lpVerb
))
1601 case FCIDM_SHVIEW_BIGICON
:
1602 case FCIDM_SHVIEW_SMALLICON
:
1603 case FCIDM_SHVIEW_LISTVIEW
:
1604 case FCIDM_SHVIEW_REPORTVIEW
:
1605 case 0x30: /* FIX IDS in resource files */
1609 case FCIDM_SHVIEW_AUTOARRANGE
:
1610 case FCIDM_SHVIEW_SNAPTOGRID
:
1611 case FCIDM_SHVIEW_REFRESH
:
1612 return NotifyShellViewWindow(lpcmi
, FALSE
);
1613 case FCIDM_SHVIEW_INSERT
:
1614 case FCIDM_SHVIEW_INSERTLINK
:
1615 return DoPaste(This
, lpcmi
);
1616 case FCIDM_SHVIEW_OPEN
:
1617 case FCIDM_SHVIEW_EXPLORE
:
1618 return DoOpenOrExplore(This
, lpcmi
);
1619 case FCIDM_SHVIEW_COPY
:
1620 case FCIDM_SHVIEW_CUT
:
1621 return DoCopyOrCut(This
, lpcmi
, LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_COPY
);
1622 case FCIDM_SHVIEW_CREATELINK
:
1623 return DoCreateLink(This
, lpcmi
);
1624 case FCIDM_SHVIEW_DELETE
:
1625 return DoDelete(This
, lpcmi
);
1626 case FCIDM_SHVIEW_RENAME
:
1627 return DoRename(This
, lpcmi
);
1628 case FCIDM_SHVIEW_PROPERTIES
:
1629 return DoProperties(This
, lpcmi
);
1631 return DoFormat(This
, lpcmi
);
1634 if (This
->iIdSHEFirst
&& This
->iIdSHELast
)
1636 if (LOWORD(lpcmi
->lpVerb
) >= This
->iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= This
->iIdSHELast
)
1638 return DoDynamicShellExtensions(This
, lpcmi
);
1642 if (This
->iIdSCMFirst
&& This
->iIdSCMLast
)
1644 if (LOWORD(lpcmi
->lpVerb
) >= This
->iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= This
->iIdSCMLast
)
1646 return DoStaticShellExtensions(This
, lpcmi
);
1650 FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi
->lpVerb
));
1651 return E_UNEXPECTED
;
1657 IDefaultContextMenu_fnGetCommandString(
1658 IContextMenu2
*iface
,
1672 IDefaultContextMenu_fnHandleMenuMsg(
1673 IContextMenu2
*iface
,
1682 static const IContextMenu2Vtbl cmvt
=
1684 IDefaultContextMenu_fnQueryInterface
,
1685 IDefaultContextMenu_fnAddRef
,
1686 IDefaultContextMenu_fnRelease
,
1687 IDefaultContextMenu_fnQueryContextMenu
,
1688 IDefaultContextMenu_fnInvokeCommand
,
1689 IDefaultContextMenu_fnGetCommandString
,
1690 IDefaultContextMenu_fnHandleMenuMsg
1694 IDefaultContextMenu_Constructor(
1695 const DEFCONTEXTMENU
*pdcm
,
1699 IDefaultContextMenuImpl
* This
;
1700 HRESULT hr
= E_FAIL
;
1701 IDataObject
* pDataObj
;
1703 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IDefaultContextMenuImpl
));
1706 This
->lpVtbl
= &cmvt
;
1708 TRACE("cidl %u\n", This
->dcm
.cidl
);
1709 if (SUCCEEDED(SHCreateDataObject(pdcm
->pidlFolder
, pdcm
->cidl
, pdcm
->apidl
, NULL
, &IID_IDataObject
, (void**)&pDataObj
)))
1711 This
->pDataObj
= pDataObj
;
1713 CopyMemory(&This
->dcm
, pdcm
, sizeof(DEFCONTEXTMENU
));
1714 hr
= IDefaultContextMenu_fnQueryInterface((IContextMenu2
*)This
, riid
, ppv
);
1716 IContextMenu_Release((IContextMenu2
*)This
);
1719 TRACE("This(%p)(%x) cidl %u\n",This
, hr
, This
->dcm
.cidl
);
1723 /*************************************************************************
1724 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1730 SHCreateDefaultContextMenu(
1731 const DEFCONTEXTMENU
*pdcm
,
1735 HRESULT hr
= E_FAIL
;
1738 hr
= IDefaultContextMenu_Constructor( pdcm
, riid
, ppv
);
1740 TRACE("pcm %p hr %x\n", pdcm
, hr
);
1744 /*************************************************************************
1745 * CDefFolderMenu_Create2 [SHELL32.701]
1751 CDefFolderMenu_Create2(
1752 LPCITEMIDLIST pidlFolder
,
1755 LPCITEMIDLIST
*apidl
,
1757 LPFNDFMCALLBACK lpfn
,
1759 const HKEY
*ahkeyClsKeys
,
1760 IContextMenu
**ppcm
)
1762 DEFCONTEXTMENU pdcm
;
1767 pdcm
.pidlFolder
= pidlFolder
;
1771 pdcm
.punkAssociationInfo
= NULL
;
1773 pdcm
.aKeys
= ahkeyClsKeys
;
1775 hr
= SHCreateDefaultContextMenu(&pdcm
, &IID_IContextMenu
, (void**)ppcm
);