Respuesta corta
Prueba el ShellBrowser Components de JAM Software. Tienen un componente que te permitirá mostrar el menú contextual del Explorer con tus propios comandos mezclados desde un TPopupMenu.
Respuesta larga
Conseguir el menú del explorador, la consulta de todas sus propiedades, y los acoge en su propio menú es posible, pero que realmente debe ser cómoda la lectura/escritura de bajo nivel de código de Win32 y un conocimiento práctico de C ayudará. También tendrá que tener cuidado con algunos problemas (que se detallan a continuación). Recomiendo leer la serie How to host an IContextMenu de Raymond Chen para obtener muchos detalles técnicos.
El enfoque más fácil es una consulta de la interfaz de IContextMenu, entonces el HMENU, a continuación, utilizar TrackPopupMenu para dejar que Windows muestre el menú, a continuación, llamar InvokeCommand al final.
Algunos de los códigos siguientes no han sido probados o han sido modificados con respecto a lo que estamos utilizando, por lo tanto, proceda bajo su propia responsabilidad.
Así es como se obtiene la IContextMenu, para un grupo de archivos dentro de una carpeta de base:
function GetExplorerMenu(AHandle: HWND; const APath: string;
AFilenames: TStrings): IContextMenu;
var
Desktop, Parent: IShellFolder;
FolderPidl: PItemIDList;
FilePidls: array of PItemIDList;
PathW: WideString;
i: Integer;
begin
// Retrieve the Desktop's IShellFolder interface
OleCheck(SHGetDesktopFolder(Desktop));
// Retrieve the parent folder's PItemIDList and then it's IShellFolder interface
PathW := WideString(IncludeTrailingPathDelimiter(APath));
OleCheck(Desktop.ParseDisplayName(AHandle, nil, PWideChar(PathW),
Cardinal(nil^), FolderPidl, Cardinal(nil^)));
try
OleCheck(Desktop.BindToObject(FolderPidl, nil, IID_IShellFolder, Parent));
finally
SHFree(FolderPidl);
end;
// Retrieve PIDLs for each file, relative the the parent folder
SetLength(FilePidls, AFilenames.Count);
try
FillChar(FilePidls[0], SizeOf(PItemIDList) * AFilenames.Count, 0);
for i := 0 to AFilenames.Count-1 do begin
PathW := WideString(AFilenames[i]);
OleCheck(Parent.ParseDisplayName(AHandle, nil, PWideChar(PathW),
Cardinal(nil^), FilePidls[i], Cardinal(nil^)));
end;
// Get the context menu for the files from the parent's IShellFolder
OleCheck(Parent.GetUIObjectOf(AHandle, AFilenames.Count, FilePidls[0],
IID_IContextMenu, nil, Result));
finally
for i := 0 to Length(FilePidls) - 1 do
SHFree(FilePidls[i]);
end;
end;
para obtener los elementos de menú real que necesita para llamar IContextMenu.QueryContextMenu. Puede destruir el HMENU devuelto usando DestroyMenu.
function GetExplorerHMenu(const AContextMenu: IContextMenu): HMENU;
const
MENUID_FIRST = 1;
MENUID_LAST = $7FFF;
var
OldMode: UINT;
begin
OldMode := SetErrorMode(SEM_FAILCRITICALERRORS or SEM_NOOPENFILEERRORBOX);
try
Result := CreatePopupMenu;
AContextMenu.QueryContextMenu(Result, 0, MENUID_FIRST, MENUID_LAST, CMF_NORMAL);
finally
SetErrorMode(OldMode);
end;
end;
Así es como en realidad se llama el comando que el usuario ha seleccionado en el menú:
procedure InvokeCommand(const AContextMenu: IContextMenu; AVerb: PChar);
const
CMIC_MASK_SHIFT_DOWN = $10000000;
CMIC_MASK_CONTROL_DOWN = $20000000;
var
CI: TCMInvokeCommandInfoEx;
begin
FillChar(CI, SizeOf(TCMInvokeCommandInfoEx), 0);
CI.cbSize := SizeOf(TCMInvokeCommandInfo);
CI.hwnd := GetOwnerHandle(Owner);
CI.lpVerb := AVerb;
CI.nShow := SW_SHOWNORMAL;
// Ignore return value for InvokeCommand. Some shell extensions return errors
// from it even if the command worked.
try
AContextMenu.InvokeCommand(PCMInvokeCommandInfo(@CI)^)
except on E: Exception do
MessageDlg(Owner, E.Message, mtError, [mbOk], 0);
end;
end;
procedure InvokeCommand(const AContextMenu: IContextMenu; ACommandID: UINT);
begin
InvokeCommand(AContextMenu, MakeIntResource(Word(ACommandID)));
end;
Ahora puede utilizar la función GetMenuItemInfo para obtener el título, mapa de bits, etc., sino una mucho más fácil El enfoque es llamar al TrackPopupMenu y dejar que Windows muestre el menú emergente. Eso sería algo como esto:
procedure ShowExplorerMenu(AForm: TForm; AMousePos: TPoint;
const APath: string; AFilenames: TStrings;);
var
ShellMenu: IContextMenu;
Menu: HMENU;
MenuID: LongInt;
begin
ShellMenu := GetExplorerMenu(AForm.Handle, APath, AFilenames);
Menu := GetExplorerHMenu(ShellMenu);
try
MenuID := TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_TOPALIGN or TPM_RETURNCMD,
AMousePos.X, AMousePos.Y, 0, AForm.Handle, nil);
InvokeCommand(ShellMenu, MenuID - MENUID_FIRST);
finally
DestroyMenu(Menu);
end;
end;
Si realmente se desea extraer los elementos del menú/subtítulos y añadirlos a su propio menú emergente (usamos la barra 2000 y hacemos exactamente eso), aquí están los otros grandes problemas se encontrará con:
- El "Enviar a" del menú, y cualesquiera otras que se construyen bajo demanda no funcionarán a menos que resuelva los mensajes y pasarlos a las interfaces IContextMenu2/IContextMenu3.
- Los mapas de bits del menú están en un par de formatos diferentes. Delphi no maneja los colores altos de Vista sin persuasión, y los más antiguos se combinan en el color de fondo con un XOR.
- Algunos elementos del menú son dibujados por el propietario, por lo que debe capturar los mensajes de pintura y hacer que pinten en su propio lienzo.
- Las cadenas de sugerencias no funcionarán a menos que las consulte manualmente.
- Necesitará administrar la vida útil de IContextMenu y HMENU y solo liberarlos una vez que se haya cerrado el menú emergente.
¿quieres crear propios elementos del menú contextual o manipular elementos de menú existentes? – Liton
@Liton, no creando mis propios elementos de menú de contexto de shell, sino para manipular elementos de menú existentes incorporados o de 3ª parte. –