zoukankan      html  css  js  c++  java
  • C#打开目录并选中文件(夹)的实现

      很久之前想把这个写下来的,谁知道用Firefox在博客园上在线编辑快完成时浏览器死掉,郁闷之下没有写了。今天突然想起,随便记录一下吧。

      本文想讲的内容,如果你还不是很清楚,可以看看下图:


      没错,就是想实现像上图中点击“查找目标”按钮一样的功能,即是打开目录并选中文件(夹)。有人可能会问,使用explorer.exe程序加/select参数不是可以做到吗?当然,这是一种办法,不过,也许你更希望使用Windows中的某个API来实现,因为使用explorer.exe程序来实现会有些问题的。那么,Windows中哪个API可以做到呢?答案是shell32.dll中的SHOpenFolderAndSelectItems函数,关于它的详细信息可以查看MSDN,需要注意的是这个API要在Windows XP及以上操作系统才支持。

      如果你希望使用VC来实现,那么网上也有很多例子,并且支持Windows XP以下的操作系统,可是我在网上找不到C#实现的例子,或许有我没有找到,所以只好自己动手,丰衣足食了。

      首先,C#导入shell32.dll中的SHOpenFolderAndSelectItems函数:

            [DllImport("shell32.dll", ExactSpelling = true)]

            public static extern int SHOpenFolderAndSelectItems(

                IntPtr pidlFolder,

                uint cidl,

                [In, MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,

                uint dwFlags);

      VC中的一些数据类型,我们使用.NET中的IntPtr特定类型来代替行了,因为我们并不关心这些数据类型的数据,知道指针就OK了。SHOpenFolderAndSelectItems的第一个参数pidlFolder指你要查找的目标文件(夹)的PIDL,我们为了获取文件(夹)的PIDL,需要使用shell32.dll中的IShellLink接口。那么我们需要创建IShellLink接口的一个实例,需要使用到ole32.dll中的CoCreateInstance函数。创建的实例保存到指针,如下:

            [DllImport("ole32.dll", ExactSpelling = true)]

            public static extern int CoCreateInstance(

                [In] ref Guid rclsid,

                IntPtr pUnkOuter,

                CLSCTX dwClsContext,

                [In] ref Guid riid,

                [Out] out IntPtr ppv);

            public enum CLSCTX : uint

            {

                INPROC_SERVER = 0x1

            }

            Guid CLSID_ShellLink = new Guid("00021401-0000-0000-C000-000000000046");

            Guid IID_IShellLink = new Guid("000214F9-0000-0000-C000-000000000046");

     

            IntPtr ppsl = IntPtr.Zero;

            int result = CoCreateInstance(

                ref CLSID_ShellLink,

                IntPtr.Zero,

                CLSCTX.INPROC_SERVER,

                ref IID_IShellLink,

                out ppsl);

      这样,ppsl变量就保存了IShellLink的一个实例对象,为了使用IShellLink接口中的方法,我们还需要定义IShellLink接口,下面是Unicode版本的IShellLink,名为IShellLinkW:

        [ComImport]

        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

        [Guid("000214F9-0000-0000-C000-000000000046")]

        public interface IShellLinkW

        {

            [PreserveSig]

            int GetPath(StringBuilder pszFile, int cch, [In, Out] ref WIN32_FIND_DATAW pfd, uint fFlags);

     

            [PreserveSig]

            int GetIDList([Out] out IntPtr ppidl);

     

            [PreserveSig]

            int SetIDList([In] ref IntPtr pidl);

     

            [PreserveSig]

            int GetDescription(StringBuilder pszName, int cch);

     

            [PreserveSig]

            int SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);

     

            [PreserveSig]

            int GetWorkingDirectory(StringBuilder pszDir, int cch);

     

            [PreserveSig]

            int SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);

     

            [PreserveSig]

            int GetArguments(StringBuilder pszArgs, int cch);

     

            [PreserveSig]

            int SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);

     

            [PreserveSig]

            int GetHotkey([Out] out ushort pwHotkey);

     

            [PreserveSig]

            int SetHotkey(ushort wHotkey);

     

            [PreserveSig]

            int GetShowCmd([Out] out int piShowCmd);

     

            [PreserveSig]

            int SetShowCmd(int iShowCmd);

     

            [PreserveSig]

            int GetIconLocation(StringBuilder pszIconPath, int cch, [Out] out int piIcon);

     

            [PreserveSig]

            int SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);

     

            [PreserveSig]

            int SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);

     

            [PreserveSig]

            int Resolve(IntPtr hwnd, uint fFlags);

     

            [PreserveSig]

            int SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);

        }

            [Serializable, StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode), BestFitMapping(false)]

            public struct WIN32_FIND_DATAW

            {

                public uint dwFileAttributes;

                public FILETIME ftCreationTime;

                public FILETIME ftLastAccessTime;

                public FILETIME ftLastWriteTime;

                public uint nFileSizeHigh;

                public uint nFileSizeLow;

                public uint dwReserved0;

                public uint dwReserved1;

                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]

                public string cFileName;

                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]

                public string cAlternateFileName;

            }

            [Serializable, StructLayout(LayoutKind.Sequential)]

            public struct FILETIME

            {

                public uint dwLowDateTime;

                public uint dwHighDateTime;

            }

      上面的定义可以参照VC中的IShellLinkW定义得到。那么,我们就可以把前面创建的IShellLink实例对象转化为IShellLinkW了:

    IShellLinkW psl = Marshal.GetObjectForIUnknown(ppsl) as IShellLinkW;

      然后设置你想获取PIDL的目标路径,以C:\WINDOWS\regedit.exe为例:

    psl.SetPath(@"C:\WINDOWS\regedit.exe");

    IntPtr pidl = IntPtr.Zero;

    psl.GetIDList(out pidl);

      这样,我们就拿到了C:\WINDOWS\regedit.exe的PIDL,保存在IntPtr类型的pidl变量中。接下来就是让SHOpenFolderAndSelectItems方法使用这个PIDL了:

    SHOpenFolderAndSelectItems(pidl, 0, null, 0);

      执行了上面这句代码后,如无意外,Windows就会打开C:\WINDOWS目录,并且选中regedit.exe文件了。最后要做的事情就是清理内存和释放对象:

    Marshal.FreeCoTaskMem(pidl);

    Marshal.Release(ppsl);

      主要的功能实现就已经讲完了,如果你要测试,也不难,把上面讲到过的代码合并起来就应该可以执行了。为了方便使用,你可以把它写成一个方法,哪里需要就调用一下即可。

      水平有限,文中难免有错或不足,请不吝赐教。

      原作:秋忆

      博客:http://qiuyi21.cnblogs.com

  • 相关阅读:
    怎么保存退出vi编辑
    rpmlib(PayloadIsLzma) <= 4.4.6-1 is needed【转载】
    自制rpm包
    程序员应该具备的十个代码习惯
    面试时可以问的问题
    Git教程(二)-如何上传和同步自己的git项目
    Git教程及问题解析
    HTML5调用百度地图API进行地理定位实例
    PHP基于单例模式编写PDO类的方法
    PHP输出缓存ob系列函数详解
  • 原文地址:https://www.cnblogs.com/qiuyi21/p/1510592.html
Copyright © 2011-2022 走看看