图标覆盖之IShellIconOverlayIdentifier

想实现类似SVN样式的文件夹及文件的效果,即如果文件已经有改动,则需要在相应的文件图标上添加一个标志。

下面的几个连接可以提供很多参考

http://msdn.microsoft.com/en-us/library/windows/desktop/bb761265(v=vs.85).aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/hh127442(v=VS.85).aspx

http://www.codeproject.com/Articles/7484/How-to-overlay-an-icon-over-existing-shell-objects

  1 public sealed class ShellInterop
  2     {
  3         private ShellInterop()
  4         {
  5         }
  6         [DllImport("shell32.dll")]
  7         public static extern void SHChangeNotify(int eventID, uint flags, IntPtr item1, IntPtr item2);
  8     }
  9 
 10     [ComVisible(false)]
 11     [ComImport]
 12     [Guid("0C6C4200-C589-11D0-999A-00C04FD655E1")]
 13     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
 14     public interface IShellIconOverlayIdentifier
 15     {
 16 
 17         [PreserveSig]
 18         int IsMemberOf([MarshalAs(UnmanagedType.LPWStr)]string path, uint attributes);
 19 
 20         [PreserveSig]
 21         int GetOverlayInfo(
 22             IntPtr iconFileBuffer,
 23             int iconFileBufferSize,
 24             out int iconIndex,
 25             out uint flags);
 26 
 27         [PreserveSig]
 28         int GetPriority(out int priority);
 29     }
 30 
 31     [ComVisible(true)]
 32     [Guid("B8FA9E43-38E6-4654-8A13-FF905AD22CE5")]
 33     public class XavierMyIconOverlay : IShellIconOverlayIdentifier
 34     {
 35 
 36         #region IShellIconOverlayIdentifier Members
 37         public int IsMemberOf(string path, uint attributes)
 38         {
 39             //Show everything with icon overlay
 40             return 0; // S_OK
 41         }
 42 
 43         public int GetOverlayInfo(IntPtr iconFileBuffer, int iconFileBufferSize, out int iconIndex, out uint flags)
 44         {
 45 
 46             System.Diagnostics.Debug.WriteLine(string.Format("GetOverlayInfo::{0}", iconFileBuffer));
 47 
 48             System.Diagnostics.Debug.WriteLine(string.Format("GetOverlayInfo::{0}", iconFileBufferSize));
 49             string fname = @"c:\favicon.ico";
 50 
 51             int bytesCount = System.Text.Encoding.Unicode.GetByteCount(fname);
 52 
 53             System.Diagnostics.Debug.WriteLine(string.Format("GetOverlayInfo::{0}", bytesCount));
 54 
 55             byte[] bytes = System.Text.Encoding.Unicode.GetBytes(fname);
 56 
 57             if (bytes.Length + 2 < iconFileBufferSize)
 58             {
 59                 for (int i = 0; i < bytes.Length; i++)
 60                 {
 61                     Marshal.WriteByte(iconFileBuffer, i, bytes[i]);
 62                 }
 63                 //write the "\0\0"
 64                 Marshal.WriteByte(iconFileBuffer, bytes.Length, 0);
 65                 Marshal.WriteByte(iconFileBuffer, bytes.Length + 1, 0);
 66             }
 67 
 68             iconIndex = 0;
 69             flags = 1; // ISIOI_ICONFILE
 70             return 0; // S_OK
 71         }
 72 
 73 
 74         public int GetPriority(out int priority)
 75         {
 76             priority = 0; // 0-100 (0 is highest priority)
 77             return 0; // S_OK
 78         }
 79         #endregion
 80 
 81         #region Registry
 82         [ComRegisterFunction]
 83         public static void Register(Type t)
 84         {
 85             RegistryKey rk = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\_"
 86             + t.Name);
 87             rk.SetValue(string.Empty, t.GUID.ToString("B").ToUpper());
 88             rk.Close();
 89             ShellInterop.SHChangeNotify(0x08000000, 0, IntPtr.Zero, IntPtr.Zero);
 90         }
 91 
 92         [ComUnregisterFunction]
 93         public static void Unregister(Type t)
 94         {
 95             Registry.LocalMachine.DeleteSubKeyTree(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\_"
 96             + t.Name);
 97             ShellInterop.SHChangeNotify(0x08000000, 0, IntPtr.Zero, IntPtr.Zero);
 98         }
 99         #endregion
100     }

在项目属性中,选择签名,以产生程序集的强名;然后生成解决方案,会在bin目录的debug或release目录下产生xxx.dll文件

注册服务: regasm xxx.dll /codebase

重启Explorer,即可看到效果

后记:改代码还有不足,首先其编译出的Dll有版本的限制,不能同时支持64位和32位的系统,在选择生成32位的dll注册后,其仅能支持32位的程序,64位的程序不能调用该dll。如果编译成64位dll其原理一样,所以解决该问题需要把X86和x64同时注册到服务中。

在此感谢xuguilin 的帮助,http://www.cnblogs.com/xuguilin/archive/2010/04/05/1704885.html#2709859 参看该篇文章,颇有收获。同时想说CLR的代码托管机制需要更加深入的研究。

Demo:下载

原文地址:https://www.cnblogs.com/caosenianhuan/p/3108662.html