2011-03-12 50 views

Respuesta

8

Kermia Compruebe la unidad JclShell de la biblioteca JEDI JCL, dentro de esta unidad existe una función llamada DisplayContextMenu que muestra el menú contextual asociado a un archivo. esta función encapsula las llamadas a la interfaz IContextMenu y hace que su trabajo sea más fácil.

function DisplayContextMenu(const Handle: HWND; const FileName: string; 
    Pos: TPoint): Boolean; 
+0

+1 ¿Qué pasa como el parámetro Handle? ¿Para qué se usa esto? –

+0

@David puede pasar el control de su formulario, este identificador se utiliza en el 'IContextMenu.InvokeCommand' que recibe una estructura' CMINVOKECOMMANDINFO' http://msdn.microsoft.com/en-us/library/bb773215%28v= vs.85% 29.aspx. – RRUZ

+0

¿Hay alguna versión más reciente de esta unidad? (para Delphi 2010) – Kermia

2

Recomendaría mirar algo como tpShellShock cuando quiera mostrar controles tipo caparazón en su aplicación Delphi. Ofrece vistas en árbol, listas de vistas, etc. que se pueden conectar de manera similar a Windows Explorer. Mostrará los íconos apropiados para los archivos. Estoy seguro de que ofrece las instalaciones de las que también hablas.

Puede que necesite algún trabajo de transferencia si está en un Unicode Delphi moderno, pero cuando lo he hecho, resultó ser relativamente sencillo.

Sin duda hay otras bibliotecas que ofrecen controles de shell, este es el único con el que estoy familiarizado.

De lo contrario, si desea seguir con su solución actual, es más fácil implementar sus propias acciones de menú. Abrir y Propiedades son simples llamadas a ShellExecute con el verbo apropiado. Eliminar es una llamada a DeleteFile y Rename es una llamada a MoveFile.

5

Compruebe la interfaz IContextMenu. Pero tenga en cuenta que el shell de Windows no identifica sus objetos por nombre de archivo, en realidad no podrían ser archivos. Utiliza una concatenación de identificadores, y es posible que necesite obtener la lista de identificación de elementos que se le asigna a un archivo antes de invocar algunas funciones de shell en él.

+0

Parece que le permite enumerar lo que el shell considera que está en el menú contextual. A medida que lo lea, igual necesitará llenar el menú usted mismo, y luego invocar comandos a través de esta interfaz en respuesta a los eventos Delphi OnClick. ¿Es eso correcto? –

+0

+1 Sin duda parece una buena forma de implementar los controladores OnClick. –

+0

Sí, tienes que crear el menú (al menos te permite usar cualquier tipo de menú que prefieras), de todos modos te da el comando que cada elemento admite y te permite invocar el comando correcto como lo define el intérprete de comandos. Tampoco funciona en archivos, aunque eso va más allá de la pregunta del usuario. –

3

Aquí es un ejemplo de implementación utilizando caso de un cuadro de lista, que se rellena con nombres de archivo en el directorio del proyecto del 'OnContextPopup', para poner en marcha el menú contextual de un archivo cuando se hace clic derecho en su nombre:

type 
    TForm1 = class(TForm) 
    ListBox1: TListBox; 
    procedure FormCreate(Sender: TObject); 
    procedure ListBox1ContextPopup(Sender: TObject; MousePos: TPoint; 
     var Handled: Boolean); 
    private 
    protected 
    procedure WndProc(var Msg: TMessage); override; 
    public 
    end; 

var 
    Form1: TForm1; 

implementation 

uses 
    shlobj, comobj; 

{$R *.dfm} 

procedure TForm1.FormCreate(Sender: TObject); 
var 
    SearchRec: TSearchRec; 
begin 
    ListBox1.Clear; 

    // populate list box with files in the project folder 
    if FindFirst(ExtractFilePath(Application.ExeName) + '*.*', 
       0, SearchRec) = 0 then 
    repeat 
     ListBox1.Items.Add(SearchRec.Name); 
    until FindNext(SearchRec) <> 0; 
    FindClose(SearchRec); 
end; 

var 
    // Required to handle messages for owner drawn items, as in 'SendTo' menu. 
    // Also used as a flag in WndProc to know if we're tracking a shortcut menu. 
    ContextMenu2: IContextMenu2 = nil; 

procedure TForm1.ListBox1ContextPopup(Sender: TObject; MousePos: TPoint; 
    var Handled: Boolean); 
var 
    Item: Integer; 
    DeskFolder, Folder: IShellFolder; 
    Eaten, Attributes: ULONG; 
    pIdl, FolderpIdl: PItemIDList; 
    ContextMenu: IContextMenu; 
    Menu: HMENU; 
    Pos: TPoint; 
    Cmd: DWORD; 
    CommandInfo: TCMInvokeCommandInfo; 
begin 
    Item := (Sender as TListBox).ItemAtPos(MousePos, True); 
    Handled := Item <> -1; 
    if not Handled then 
    Exit; 
    TListBox(Sender).ItemIndex := Item; 

    // IShellFolder for Desktop folder (root) 
    OleCheck(SHGetDesktopFolder(DeskFolder)); 

    // Item ID List for the folder that the file is in 
    Attributes := 0; 
    OleCheck(DeskFolder.ParseDisplayName(Handle, nil, 
        PWideChar(WideString(ExtractFilePath(Application.ExeName))), 
        Eaten, FolderpIdl, Attributes)); 

    // IShellFolder for the folder the file is in 
    OleCheck(DeskFolder.BindToObject(FolderpIdl, nil, IID_IShellFolder, Folder)); 
    CoTaskMemFree(FolderpIdl); 

    // Item ID List for the file, relative to the folder it is in 
    Attributes := 0; 
    OleCheck(Folder.ParseDisplayName(Handle, nil, 
      PWideChar(WideString(ExtractFileName(TListBox(Sender).Items[Item]))), 
      Eaten, pIdl, Attributes)); 

    // IContextMenu for the relative Item ID List 
    OleCheck(Folder.GetUIObjectOf(Handle, 1, pIdl, IID_IContextMenu, 
            nil, ContextMenu)); 
    CoTaskMemFree(pIdl); 

    Menu := CreatePopupMenu; 
    try 
    // Populate our menu with shortcut items 
    OleCheck(ContextMenu.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE)); 

    // ContextMenu2 used in WndProc 
    ContextMenu.QueryInterface(IID_IContextMenu2, ContextMenu2); 
    try 
     Pos := TWinControl(Sender).ClientToScreen(MousePos); 
     // launch the menu 
     Bool(Cmd) := TrackPopupMenu(Menu, 
          TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, 
          Pos.X, Pos.Y, 0, Handle, nil); 
    finally 
     // clear so that we don't intervene every owner drawn menu item message in 
     // WndProc 
     ContextMenu2 := nil; 
    end; 

    // Invoke command if we have one 
    if Bool(Cmd) then begin 
     FillChar(CommandInfo, SizeOf(CommandInfo), 0); 
     CommandInfo.cbSize := SizeOf(CommandInfo); 
     CommandInfo.hwnd := Handle; 
     CommandInfo.lpVerb := MakeIntResource(Cmd - 1); 
     CommandInfo.nShow := SW_SHOWNORMAL; 

     OleCheck(ContextMenu.InvokeCommand(CommandInfo)); 
    end; 

    finally 
    DestroyMenu(Menu); 
    end; 
end; 

procedure TForm1.WndProc(var Msg: TMessage); 
begin 
    if ((Msg.Msg = WM_INITMENUPOPUP) or (Msg.Msg = WM_DRAWITEM) 
       or (Msg.Msg = WM_MEASUREITEM)) and Assigned(ContextMenu2) then 
    ContextMenu2.HandleMenuMsg(Msg.Msg, Msg.WParam, Msg.LParam) 
    else 
    inherited; 
end; 
Cuestiones relacionadas