Shell Extension DLL - 如果用户在文件夹空白区域内单击,如何捕获文件夹路径?

时间:2012-02-23 15:01:10

标签: c++ windows shell-extensions

使用shell扩展dll,如果用户在文件夹空白区域内单击,如何捕获文件夹路径?

2 个答案:

答案 0 :(得分:5)

如果您正在实施shell扩展dll,那么您将IShellExtInit::Initialize(}方法中的路径视为pidlFolder参数。

要确保您的扩展程序还注册了文件夹背景,您还必须在HKCR\Directory\Background\shellex\ContextMenuHandlers

下创建相应的条目

答案 1 :(得分:0)

使用VC ++语言请参考Winmerge源代码 http://sourceforge.net/p/winmerge/code/HEAD/tree/trunk/ShellExtension/

使用C#请参考这篇文章 http://www.codeproject.com/Articles/174369/How-to-Write-Windows-Shell-Extension-with-NET-Lang 并更新一些地方: 在FileContextMenuExt.cs文件中:

...............

    #region Shell Extension Registration

    [ComRegisterFunction()]
    public static void Register(Type t)
    {
        try
        {
            ShellExtReg.RegisterShellExtContextMenuHandler(t.GUID, "Directory", 
                "CSShellExtContextMenuHandler.FileContextMenuExt Class");
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message); // Log the error
            throw;  // Re-throw the exception
        }
    }

    [ComUnregisterFunction()]
    public static void Unregister(Type t)
    {
        try
        {
            ShellExtReg.UnregisterShellExtContextMenuHandler(t.GUID, "Directory");
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message); // Log the error
            throw;  // Re-throw the exception
        }
    }

    #endregion
   ............... 

   public void Initialize(IntPtr pidlFolder, IntPtr pDataObj, IntPtr hKeyProgID)
    {
        if (pDataObj == IntPtr.Zero && pidlFolder == IntPtr.Zero)
        {
            throw new ArgumentException();
        }

        FORMATETC fe = new FORMATETC();
        fe.cfFormat = (short)CLIPFORMAT.CF_HDROP;
        fe.ptd = IntPtr.Zero;
        fe.dwAspect = DVASPECT.DVASPECT_CONTENT;
        fe.lindex = -1;
        fe.tymed = TYMED.TYMED_HGLOBAL;
        STGMEDIUM stm = new STGMEDIUM();          

        try
        {
            if (pDataObj != IntPtr.Zero)
            {
                // The pDataObj pointer contains the objects being acted upon. In this 
                // example, we get an HDROP handle for enumerating the selected files 
                // and folders.
                IDataObject dataObject = (IDataObject)Marshal.GetObjectForIUnknown(pDataObj);
                dataObject.GetData(ref fe, out stm);

                // Get an HDROP handle.
                IntPtr hDrop = stm.unionmember;
                if (hDrop == IntPtr.Zero)
                {
                    throw new ArgumentException();
                }

                // Determine how many files are involved in this operation.
                uint nFiles = NativeMethods.DragQueryFile(hDrop, UInt32.MaxValue, null, 0);

                // This code sample displays the custom context menu item when only 
                // one file is selected. 
                if (nFiles == 1)
                {
                    // Get the path of the file.
                    StringBuilder fileName = new StringBuilder(260);
                    if (0 == NativeMethods.DragQueryFile(hDrop, 0, fileName,
                        fileName.Capacity))
                    {
                        Marshal.ThrowExceptionForHR(WinError.E_FAIL);
                    }
                    this.selectedFile = fileName.ToString();
                }
                else
                {
                    Marshal.ThrowExceptionForHR(WinError.E_FAIL);
                }
            }

            if (pidlFolder != IntPtr.Zero) {
                StringBuilder folderName = new StringBuilder(260);
                if (0 == NativeMethods.SHGetPathFromIDList(pidlFolder, folderName))
                {
                    Marshal.ThrowExceptionForHR(WinError.E_FAIL);
                }
                this.selectedFile = folderName.ToString();
            }
        }
        finally
        {
            NativeMethods.ReleaseStgMedium(ref stm);
        }
    }

在ShellExtLib.cs文件中添加以下来源:

    [DllImport("shell32.dll")]
    public static extern Int32 SHGetPathFromIDList(
        IntPtr pidl,                // Address of an item identifier list that
        // specifies a file or directory location
        // relative to the root of the namespace (the
        // desktop). 
        StringBuilder pszPath);        // Address of a buffer to receive the file system

在ShellExtLib.cs文件中更新RegisterShellExtContextMenuHandler和UnregisterShellExtContextMenuHandler函数

    public static void RegisterShellExtContextMenuHandler(Guid clsid, 
        string fileType, string friendlyName)
    {
        if (clsid == Guid.Empty)
        {
            throw new ArgumentException("clsid must not be empty");
        }
        if (string.IsNullOrEmpty(fileType))
        {
            throw new ArgumentException("fileType must not be null or empty");
        }

        // If fileType starts with '.', try to read the default value of the 
        // HKCR\<File Type> key which contains the ProgID to which the file type 
        // is linked.
        if (fileType.StartsWith("."))
        {
            using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
            {
                if (key != null)
                {
                    // If the key exists and its default value is not empty, use 
                    // the ProgID as the file type.
                    string defaultVal = key.GetValue(null) as string;
                    if (!string.IsNullOrEmpty(defaultVal))
                    {
                        fileType = defaultVal;
                    }
                }
            }
        }
        else {

            // Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
            string keyName1 = string.Format(@"{0}\Background\shellex\ContextMenuHandlers\{1}",
                fileType, clsid.ToString("B"));
            using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName1))
            {
                // Set the default value of the key.
                if (key != null && !string.IsNullOrEmpty(friendlyName))
                {
                    key.SetValue(null, friendlyName);
                }
            }
        }

        // Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
        string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
            fileType, clsid.ToString("B"));
        using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName))
        {
            // Set the default value of the key.
            if (key != null && !string.IsNullOrEmpty(friendlyName))
            {
                key.SetValue(null, friendlyName);
            }
        }
    }


    public static void UnregisterShellExtContextMenuHandler(Guid clsid, 
        string fileType)
    {
        if (clsid == null)
        {
            throw new ArgumentException("clsid must not be null");
        }
        if (string.IsNullOrEmpty(fileType))
        {
            throw new ArgumentException("fileType must not be null or empty");
        }

        // If fileType starts with '.', try to read the default value of the 
        // HKCR\<File Type> key which contains the ProgID to which the file type 
        // is linked.
        if (fileType.StartsWith("."))
        {
            using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
            {
                if (key != null)
                {
                    // If the key exists and its default value is not empty, use 
                    // the ProgID as the file type.
                    string defaultVal = key.GetValue(null) as string;
                    if (!string.IsNullOrEmpty(defaultVal))
                    {
                        fileType = defaultVal;
                    }
                }
            }
        }
        else {
            // Remove the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
            string keyName1 = string.Format(@"{0}\Background\shellex\ContextMenuHandlers\{1}",
                fileType, clsid.ToString("B"));
            Registry.ClassesRoot.DeleteSubKeyTree(keyName1, false);
        }

        // Remove the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
        string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
            fileType, clsid.ToString("B"));
        Registry.ClassesRoot.DeleteSubKeyTree(keyName, false);
    }