(C #) Windows Shell programming Series 3-context menu (iContextMenu) (1) Right-click menu

Source: Internet
Author: User

(This series of articles is original from lemon (lc_mtt). Please indicate the source for reprinting. Thank you ~)

Here we will explain how to get the name in the previous section.

GetDisplayNameOf
Definition:

Void GetDisplayNameOf (
IntPtr pidl,
SHGNO uFlags,
IntPtr lpName );

This method is used to convert PIDL to a name string that can be displayed. PIDL must be relative to the parent directory of the object. In other words, it must contain a non-empty SHITEMID structure. Because there are multiple naming methods, the resource manager defines a combination of SHGNO identifiers in the uFlags parameter to represent the name type. SHGDN_NORMAL or SHGDN_INFOLDER will be used to specify whether the name is relative to the folder or to the desktop. The other three values SHGDN_FOREDITING, SHGDN_FORADDRESSBAR, and SHGDN_FORPARSING can be used to specify the purpose of the name. The name must be returned in STRRET format. If the SHGDN_FOREDITING, SHGDN_FORADDRESSBAR, and SHGDN_FORPARSING parameters are not set, the display name of the shell object is returned.
Implementation Method:

/** // <Summary>
/// Obtain the display name
/// </Summary>
Public static string GetNameByIShell (IShellFolder Root, IntPtr pidlSub)
{
IntPtr strr = Marshal. AllocCoTaskMem (MAX_PATH * 2 + 4 );
Marshal. WriteInt32 (strr, 0, 0 );
StringBuilder buf = new StringBuilder (MAX_PATH );
Root. GetDisplayNameOf (pidlSub, SHGNO. INFOLDER, strr );
API. StrRetToBuf (strr, pidlSub, buf, MAX_PATH );
Marshal. FreeCoTaskMem (strr );
Return buf. ToString ();
}

SHGNO
Public enum SHGNO
{
NORMAL = 0x0,
INFOLDER = 0x1,
FOREDITING = 0x1000,
FORADDRESSBAR = 0x4000,
Forparsinging = 0x8000,
}

In fact, you only need to modify SHGNO to obtain its absolute path:

/** // <Summary>
/// Obtain IShellFolder and PIDL by path
/// </Summary>
Public static IShellFolder GetShellFolder (IShellFolder desktop, string path, out IntPtr Pidl)
{
IShellFolder IFolder;
Uint I, j = 0;
Desktop. ParseDisplayName (IntPtr. Zero, IntPtr. Zero, path, out I, out Pidl, ref j );
Desktop. BindToObject (Pidl, IntPtr. Zero, ref Guids. IID_IShellFolder, out IFolder );
Return IFolder;
}

However, we are still concerned about how to obtain absolute paths for common folders and special objects like "desktop" and "My Documents". Here we will use the SHGetSpecialFolderPath API.

[DllImport ("Shell32.Dll")]
Private static extern bool SHGetSpecialFolderPath (
IntPtr hwndOwner,
StringBuilder lpszPath,
ShellSpecialFolders nFolder,
Bool fCreate );

ShellSpecialFolders
Public enum ShellSpecialFolders
{
DESKTOP = 0x0000, // <desktop>
INTERNET = 0x0001,
PROGRAMS = 0x0002, // Start Menu \ Programs
CONTROLS = 0x0003, // My Computer \ Control Panel
PRINTERS = 0x0004, // My Computer \ Printers
PERSONAL = 0x0005, // My Documents
FAVORITES = 0x0006, // <user name> \ Favorites
STARTUP = 0x0007, // Start Menu \ Programs \ Startup
RECENT = 0x0008, // <user name> \ Recent
SENDTO = 0x0009, // <user name> \ SendTo
BITBUCKET = 0x000a, // <desktop> \ Recycle Bin
STARTMENU = 0x000b, // <user name> \ Start Menu
MYDOCUMENTS = 0x000c, // logical "My Documents" desktop icon
MYMUSIC = 0x000d, // "My Music" folder
MYVIDEO = 0x000e, // "My Videos" folder
Export topdirectory = 0x0010, // <user name> \ Desktop
DRIVES = 0x0011, // My Computer
NETWORK = 0x0012, // Network Neighborhood (My Network Places)
NETHOOD = 0x0013, // <user name> \ nethood
FONTS = 0x0014, // windows \ fonts
TEMPLATES = 0x0015,
COMMON_STARTMENU = 0x0016, // All Users \ Start Menu
COMMON_PROGRAMS = 0X0017, // All Users \ Start Menu \ Programs
COMMON_STARTUP = 0x0018, // All Users \ Startup
Common_shorttopdirectory = 0x0019, // All Users \ Desktop
APPDATA = 0x001a, // <user name> \ Application Data
PRINTHOOD = 0x001b, // <user name> \ PrintHood
LOCAL_APPDATA = 0x001c, // <user name> \ Local Settings \ Applicaiton Data (non roaming)
ALTSTARTUP = 0x001d, // non localized startup
COMMON_ALTSTARTUP = 0x001e, // non localized common startup
COMMON_FAVORITES = 0x001f,
INTERNET_CACHE = 0x0020,
COOKIES = 0x0021,
HISTORY = 0x0022,
COMMON_APPDATA = 0x0023, // All Users \ Application Data
WINDOWS = 0x0024, // GetWindowsDirectory ()
SYSTEM = 0x0025, // GetSystemDirectory ()
PROGRAM_FILES = 0x0026, // C: \ Program Files
MYPICTURES = 0x0027, // C: \ Program Files \ My Pictures
PROFILE = 0x0028, // USERPROFILE
SYSTEMX86 = 0x0029, // x86 system directory on RISC
PROGRAM_FILESX86 = 0x002a, // x86 C: \ Program Files on RISC
PROGRAM_FILES_COMMON = 0x002b, // C: \ Program Files \ Common
PROGRAM_FILES_COMMONX86 = 0x002c, // x86 Program Files \ Common on RISC
COMMON_TEMPLATES = 0x002d, // All Users \ Templates
COMMON_DOCUMENTS = 0x002e, // All Users \ Documents
COMMON_ADMINTOOLS = 0x002f, // All Users \ Start Menu \ Programs \ Administrative Tools
ADMINTOOLS = 0x0030, // <user name> \ Start Menu \ Programs \ Administrative Tools
CONNECTIONS = 0x0031, // Network and Dial-up Connections
COMMON_MUSIC = 0x0035, // All Users \ My Music
COMMON_PICTURES = 0x0036, // All Users \ My Pictures
COMMON_VIDEO = 0x0037, // All Users \ My Video
RESOURCES = 0x0038, // Resource Direcotry
RESOURCES_LOCALIZED = 0x0039, // Localized Resource Direcotry
COMMON_OLINKS = 0x003a, // Links to All Users OEM specific apps
CDBURN_AREA = 0x003b, // USERPROFILE \ Local Settings \ Application Data \ Microsoft \ CD Burning
COMPUTERSNEARME = 0x003d, // Computers Near Me (computered from Workgroup membership)
FLAG_CREATE = 0x8000, // combine with value to force folder creation in SHGetFolderPath ()
FLAG_DONT_VERIFY = 0x4000, // combine with value to return an unverified folder path
FLAG_NO_ALIAS = 0x1000, // combine with value to insure non-alias versions of the pidl
FLAG_PER_USER_INIT = 0x0800, // combine with value to indicate per-user init (eg. upgrade)
FLAG_MASK = 0xFF00, // mask for all possible flag values
}

/** // <Summary>
/// Obtain the path of the special folder
/// </Summary>
Public static string GetSpecialFolderPath (IntPtr hwnd, ShellSpecialFolders nFolder)
{
StringBuilder sb = new StringBuilder (MAX_PATH );
SHGetSpecialFolderPath (hwnd, sb, nFolder, false );
Return sb. ToString ();
}

Context Menu
The Interface related to the context menu of an object is IContextMenu, which can be obtained through the IShellFolder. GetUIObjectOf method of the parent folder of the object. After obtaining this interface, you can use the IContextMenu. QueryContextMenu method to generate the context menu items, and use IContextMenu. InvokeCommand to call the corresponding commands.
Well, let's implement the context menu pop-up of the IShellFolder object step by step.
First, assume that we have obtained the pidl of an IShellFolder object and its superior IShellFolder object:

IntPtr PIDL;
IShellFolder IParent;

Then we define an array to store PIDL:

IntPtr [] pidls = new IntPtr [1];
Pidls [0] = PIDL;

Yes, we do need to use PIDL arrays. You can understand that you have selected multiple files/folders in the resource manager and right-click them. The context menu will be different. You can put multiple PIDL at the same level into the array as needed to achieve this effect. The menu is displayed in the tree in example 2, so only the PIDL of one node is saved.
The IContextMenu interface is defined as follows:

IContextMenu. cs
Using System;
Using System. Collections. Generic;
Using System. Text;
Using System. Runtime. InteropServices;

Namespace WinShell
{
[ComImport (), InterfaceType (ComInterfaceType. InterfaceIsIUnknown), GuidAttribute ("000214e4-0000-0000-c000-000000000046")]
Public interface IContextMenu
{
[PreserveSig ()]
Int32 QueryContextMenu (
IntPtr hmenu,
Uint iMenu,
Uint id1_first,
Uint idCmdLast,
CMF uFlags );

[PreserveSig ()]
Int32 InvokeCommand (
Ref CMINVOKECOMMANDINFOEX info );

[PreserveSig ()]
Void GetCommandString (
Int idcmd,
GetCommandStringInformations uflags,
Int reserved,
StringBuilder commandstring,
Int cch );
}
}

Then, through the GetUIObjectOf method of IParent, we can obtain the IContextMenu interface of one or more specified child nodes of this node:

GetUIObjectOf
IntPtr GetUIObjectOf (
IntPtr hwndOwner,
Uint cidl,
[Financialas (UnmanagedType. LPArray)] IntPtr [] apidl,
[In ()] ref Guid riid,
Out IntPtr rgfReserved );

// Obtain the IContextMenu Interface
IntPtr iContextMenuPtr = IntPtr. Zero;
IContextMenuPtr = IParent. GetUIObjectOf (IntPtr. Zero, (uint) pidls. Length,
Pidls, ref Guids. IID_IContextMenu, out iContextMenuPtr );
IContextMenu iContextMenu = (IContextMenu) Marshal. GetObjectForIUnknown (iContextMenuPtr );

After obtaining the IContextMenu, we need to provide a handle to the pop-up menu and pass it to IContextMenu. QueryContextMenu. If this method is successfully executed, corresponding menu items will be added to our menu.

// Provide a handle for the pop-up menu
IntPtr contextMenu = API. CreatePopupMenu ();
IContextMenu. QueryContextMenu (contextMenu, 0,
API. Sort _first, API. Sort _last, CMF. NORMAL | CMF. Sort E );

With the menu item, we can bring up the menu. We use the TPM_RETURNCMD flag to specify that TrackPopupMenu must return the ID of the menu item selected by the user, so that the menu command can be executed later through IContextMenu. InvokeCommand:

// Pop-up menu
Uint cmd = API. TrackPopupMenuEx (contextMenu, TPM. RETURNCMD,
MousePosition. X, MousePosition. Y, this. Handle, IntPtr. Zero );

// Obtain the command serial number and execute the menu command
If (cmd> = API. CMD_FIRST)
{
CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX ();
Invoke. cbSize = Marshal. SizeOf (typeof (CMINVOKECOMMANDINFOEX ));
Invoke. lpVerb = (IntPtr) (cmd-1 );
Invoke. lpDirectory = string. Empty;
Invoke. fMask = 0;
Invoke. ptInvoke = new POINT (MousePosition. X, MousePosition. Y );
Invoke. nShow = 1;
IContextMenu. InvokeCommand (ref invoke );
}

Reference and source code:

Source code:/Files/lemony/WinShell3.rar

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.