Show the default right-click menu - Delphi

后端 未结 4 1614
你的背包
你的背包 2020-12-30 12:25

I have a Listbox which contain a list of files . can i access the Windows right-click menu in the listbox to access the open , properties , delete and rename items ?

相关标签:
4条回答
  • 2020-12-30 13:09

    I'd recommend looking at something like tpShellShock when you want to show shell like controls in your Delphi app. It offers tree views, list views etc. that can be connected together much like an Explorer Windows. It will display the appropriate icons for the files. I'm sure it offers the facilities you talk about too.

    It might need some porting work if you are on a modern Unicode Delphi, but when I have done that it proved relatively straightforward.

    No doubt there are other libraries that offer shell controls, this is just the one I am familiar with.

    Otherwise if you want to stick with your current solution it's easiest to implement your own menu actions. Open and Properties are just simple calls to ShellExecute with the appropriate verb. Delete is a call to DeleteFile and Rename is a call to MoveFile.

    0 讨论(0)
  • 2020-12-30 13:12

    Kermia check the JclShell unit from the JEDI JCL library, inside of this unit exist a function called DisplayContextMenu which show the context menu associated to a file. this function encapsulate the calls to the IContextMenu interface and makes your work more easy.

    function DisplayContextMenu(const Handle: HWND; const FileName: string;
      Pos: TPoint): Boolean;
    
    0 讨论(0)
  • 2020-12-30 13:14

    Here is an implementation example using the 'OnContextPopup' event of a list box, which is populated with file names in the project directory, to launch the shortcut menu of a file when right-clicked on its name:

    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;
    
    0 讨论(0)
  • 2020-12-30 13:15

    Check the IContextMenu interface. But be aware that Windows shell doesn't identify its objects by filename - actually they could not be files. It uses a concatenation of ids, and you may need to get what item id list a file is assigend to before invoking some shell functions on it.

    0 讨论(0)
提交回复
热议问题