How to open the Windows context menu for a given file using Delphi?

I want to write the following procedure / function:

procedure ShowSysPopup(aFile: string; x, y: integer); 

The right-click menu that you see in Windows Explorer for this file will be built and shown (in x and y coordinates). I'm not interested in some of the โ€œimpressions,โ€ but more than how you can build such a menu.

+7
winapi delphi registry
source share
3 answers

I made a quick decision for you. add these units to the Usage section:

 ... ShlObj, ActiveX, ComObj 

and here is your procedure, I just add a new parameter "HND" to transfer the TWinControl handle, which you will use to display the context menu.

 procedure ShowSysPopup(aFile: string; x, y: integer; HND: HWND); var Root: IShellFolder; ShellParentFolder: IShellFolder; chEaten,dwAttributes: ULONG; FilePIDL,ParentFolderPIDL: PItemIDList; CM: IContextMenu; Menu: HMenu; Command: LongBool; ICM2: IContextMenu2; ICI: TCMInvokeCommandInfo; ICmd: integer; P: TPoint; Begin OleCheck(SHGetDesktopFolder(Root));//Get the Desktop IShellFolder interface OleCheck(Root.ParseDisplayName(HND, nil, PWideChar(WideString(ExtractFilePath(aFile))), chEaten, ParentFolderPIDL, dwAttributes)); // Get the PItemIDList of the parent folder OleCheck(Root.BindToObject(ParentFolderPIDL, nil, IShellFolder, ShellParentFolder)); // Get the IShellFolder Interface of the Parent Folder OleCheck(ShellParentFolder.ParseDisplayName(HND, nil, PWideChar(WideString(ExtractFileName(aFile))), chEaten, FilePIDL, dwAttributes)); // Get the relative PItemIDList of the File ShellParentFolder.GetUIObjectOf(HND, 1, FilePIDL, IID_IContextMenu, nil, CM); // get the IContextMenu Interace for the file if CM = nil then Exit; PX := X; PY := Y; Windows.ClientToScreen(HND, P); Menu := CreatePopupMenu; try CM.QueryContextMenu(Menu, 0, 1, $7FFF, CMF_EXPLORE or CMF_CANRENAME); CM.QueryInterface(IID_IContextMenu2, ICM2); //To handle submenus. try Command := TrackPopupMenu(Menu, TPM_LEFTALIGN or TPM_LEFTBUTTON or TPM_RIGHTBUTTON or TPM_RETURNCMD, pX, pY, 0, HND, nil); finally ICM2 := nil; end; if Command then begin ICmd := LongInt(Command) - 1; FillChar(ICI, SizeOf(ICI), #0); with ICI do begin cbSize := SizeOf(ICI); hWND := 0; lpVerb := MakeIntResourceA(ICmd); nShow := SW_SHOWNORMAL; end; CM.InvokeCommand(ICI); end; finally DestroyMenu(Menu) end; End; 

change / add initialization section, completion like this

 initialization OleInitialize(nil); finalization OleUninitialize; 

and here, how you can use this procedure:

 procedure TForm2.Button1Click(Sender: TObject); begin ShowSysPopup(Edit1.Text,Edit1.Left,Edit1.Top, Handle); end; 

I hope this works for you.

Hi,

Edit: if you want to show a context menu for more than one file, mark this article on your blog

+16
source share

Are you sure you want to do? Because if you do this, you really have to reproduce all the code in the Windows shell and all this behavior and interactions with a number of codes.

The context menu is mainly built using "shell extensions". These are COM DLLs registered in the system. When the context menu is invoked, the shell follows a set of rules that determine where it should look (in the registry) for extension libraries.

I found this a useful guide for these rules .

But searching for extension DLLs is not even half the story. For each DLL, the shell then creates an instance of the COM objects registered by this DLL and calls the objects that the DLL responds to, either by tuning or by invoking menu commands.

The shell itself does not create a menu, nor does the information necessary to create an accessible menu that can be requested or read directly from anywhere - the menu is built completely dynamically using shell extensions.

The shell passes a menu descriptor to each extension along with some information telling the extension which command identifier it should use for any items that it adds to this menu. An extension can add almost everything that it likes to a menu descriptor, including a submenu, etc., And, perhaps, it will add different elements depending on the properties of the current file selection, and not just file extensions (for example, the Tortoise client SVN adds various menu items depending on what is related to the current SVN status of these files).

So, if you want to create such a menu yourself, as I said, you will have to replicate the entire shell extension shell (or at least those parts of it that initialize the menu, if for some reason you do not want to or need call the menu commands yourself) in your own code.

Perhaps this will help if you explain why you want to do this and what you are trying to achieve. There may be an easier way to do this.

+2
source share

Although I agree with Deltics that this is a lot of work, the information needed for most (if not all) elements is freely available in the registry. The manual listed in Deltics looks good and will give you most of the items. Much can be found in the base entries in the registry, while others need calls for COM objects.

0
source share

All Articles