设为首页 收藏本站
查看: 1469|回复: 0

(C#)Windows Shell 外壳编程系列3

[复制链接]

尚未签到

发表于 2015-4-28 11:40:29 | 显示全部楼层 |阅读模式
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢~)

接上一节:(C#)Windows Shell 外壳编程系列2 - 解释,从“桌面”开始展开

这里解释上一节中获取名称的方法

GetDisplayNameOf
定义:


DSC0000.gif void GetDisplayNameOf(
            IntPtr pidl,
            SHGNO uFlags,
            IntPtr lpName);  该方法是用来转换PIDL成为可显示的名称字符串。PIDL必须是相对于对象的父目录的。换句话说,它必须包含一个非空的SHITEMID 结构。因为有多种命名对象的方式,资源管理器通过在uFlags参数中定义SHGNO标识的组合来表示名称类型。SHGDN_NORMAL或SHGDN_INFOLDER将被用来指定名称是相对于文件夹的还是相对于桌面的。其他三个值SHGDN_FOREDITING、SHGDN_FORADDRESSBAR和SHGDN_FORPARSING可以用来指定名称的用途。 名称必须按STRRET的结构形式返回,如果SHGDN_FOREDITING、SHGDN_FORADDRESSBAR和 SHGDN_FORPARSING没有设定,就返回外壳对象的显示名称。

具体实现方法:

DSC0001.gif DSC0002.gif /**////
DSC0003.gif         /// 获取显示名称
DSC0004.gif         ///
        public static string GetNameByIShell(IShellFolder Root, IntPtr pidlSub)
         DSC0005.gif {
            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,
        FORPARSING = 0x8000,
    }  事实上,只要修改 SHGNO ,就可以获取其绝对路径:

/**////
        /// 根据路径获取 IShellFolder 和 PIDL
        ///
        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;
        }  但我们还关心类似“桌面”、“我的文档”这种既是普通文件夹又是特殊对象的绝对路径如何获得,这里就要用到 SHGetSpecialFolderPath API 了。



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

  

ShellSpecialFolders
public enum ShellSpecialFolders
    {
        DESKTOP = 0x0000,         //
        INTERNET = 0x0001,
        PROGRAMS = 0x0002,        // Start Menu\Programs
        CONTROLS = 0x0003,        // My Computer\Control Panel
        PRINTERS = 0x0004,        // My Computer\Printers
        PERSONAL = 0x0005,        // My Documents
        FAVORITES = 0x0006,        // \Favorites
        STARTUP = 0x0007,        // Start Menu\Programs\Startup
        RECENT = 0x0008,        // \Recent
        SENDTO = 0x0009,        // \SendTo
        BITBUCKET = 0x000a,        // \Recycle Bin
        STARTMENU = 0x000b,        // \Start Menu
        MYDOCUMENTS = 0x000c,        // logical "My Documents" desktop icon
        MYMUSIC = 0x000d,        // "My Music" folder
        MYVIDEO = 0x000e,        // "My Videos" folder
        DESKTOPDIRECTORY = 0x0010,        // \Desktop
        DRIVES = 0x0011,        // My Computer
        NETWORK = 0x0012,        // Network Neighborhood (My Network Places)
        NETHOOD = 0x0013,        // \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_DESKTOPDIRECTORY = 0x0019,        // All Users\Desktop
        APPDATA = 0x001a,        // \Application Data
        PRINTHOOD = 0x001b,        // \PrintHood
        LOCAL_APPDATA = 0x001c,        // \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,        // \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
    }  

/**////
        /// 获取特殊文件夹的路径
        ///
        public static string GetSpecialFolderPath(IntPtr hwnd, ShellSpecialFolders nFolder)
        {
            StringBuilder sb = new StringBuilder(MAX_PATH);
            SHGetSpecialFolderPath(hwnd, sb, nFolder, false);
            return sb.ToString();
        }  上下文菜单

对象的上下文菜单相关的接口是IContextMenu,通过对象的父文件夹的IShellFolder.GetUIObjectOf方法可得到该接口。得到该接口后,可以用IContextMenu.QueryContextMenu方法来生成上下文菜单的菜单项,用IContextMenu.InvokeCommand调用相应的命令。

好,让我们一步一步来实现 IShellFolder 对象的上下文菜单弹出。

首先假设我们已经获得某个 IShellFolder 对象的 PIDL 和其上级 IShellFolder 对象:

IntPtr PIDL;
IShellFolder IParent;  然后我们定义一个存放 PIDL 的数组:

IntPtr[] pidls = new IntPtr[1];
pidls[0] = PIDL;  没错,我们的确要用到 PIDL 数组。可以理解,你在资源管理器中选择了多个文件/文件夹,再点击右键,弹出的上下文菜单将有所不同。你可以根据需要,把同一级的多个 PIDL 放到数组里面,实现这个效果。由于我们在例2的树中弹出菜单,所以只存放一个节点的 PIDL。

IContextMenu 是一个接口,我们这样定义:

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
DSC0006.gif DSC0007.gif     {
        [PreserveSig()]
        Int32 QueryContextMenu(
            IntPtr hmenu,
            uint iMenu,
            uint idCmdFirst,
            uint idCmdLast,
            CMF uFlags);

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

        [PreserveSig()]
        void GetCommandString(
            int idcmd,
            GetCommandStringInformations uflags,
            int reserved,
            StringBuilder commandstring,
            int cch);
DSC0008.gif     }
}
  然后,通过 IParent 的 GetUIObjectOf 方法我们可以得到该节点的一个或多个指定子节点的 IContextMenu 接口:

GetUIObjectOf
IntPtr GetUIObjectOf(
            IntPtr hwndOwner,
            uint cidl,
            [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
            [In()] ref Guid riid,
            out IntPtr rgfReserved);

//得到 IContextMenu 接口
                    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);  得到 IContextMenu 后我们需要提供一个弹出式菜单的句柄,并把他传给 IContextMenu.QueryContextMenu,如果该方法执行成功的话,会在我们的菜单里加入相应的菜单项。

//提供一个弹出式菜单的句柄
IntPtr contextMenu = API.CreatePopupMenu();
iContextMenu.QueryContextMenu(contextMenu, 0,
API.CMD_FIRST, API.CMD_LAST, CMF.NORMAL | CMF.EXPLORE);  有了菜单项,我们就可以弹出该菜单了,我们用 TPM_RETURNCMD 标志指定 TrackPopupMenu 必须返回用户所选菜单项的 ID,以便稍后通过IContextMenu.InvokeCommand 来执行菜单命令:

//弹出菜单
uint cmd = API.TrackPopupMenuEx(contextMenu,TPM.RETURNCMD,
MousePosition.X, MousePosition.Y, this.Handle, IntPtr.Zero);

//获取命令序号,执行菜单命令
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);
}  惯例附上图片和源代码:

DSC0009.jpg

源代码:/Files/lemony/WinShell3.rar

下一节深入讲述 iContextMenu,让我们可以插入自己的菜单,或者直接调用菜单命令。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-61539-1-1.html 上篇帖子: Shell编程-awk 下篇帖子: [转贴]GMail Drive shell extension
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表