简单的说就是VS的  .sln文件里面的内容改变时,会关联到不同版本的VS例如文件头部是Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008关联的是2008改一改  
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005文件图标就会改变成8.0的 就是关联到VS2005的.我想知道是如何实现的?
有详细实现例子的或有什么类似想法的跟帖讨论下.

解决方案 »

  1.   

    http://rss.buuuz.cn/2009/07/23/page/6/
    ==========================================(C#)Windows Shell 外壳编程系列8 - 同后缀名不同图标?关于注册动态库必须注册才能使用。除了使用 regasm
    来注册 DLL 以外,还应该在代码中增加 RegisterServer 和 UnregisterServer 方法,以指导 DLL 注册时,在 Windows 注册表中增加什么键。关于具体键以下做简单说明:
    1) 注册 DLL 的 Shell Extensions
    。具体位置是 HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionShell ExtensionsApproved,增加以 GUID 为名称的键,值则是动态库说明。(此位置里面全是 Shell 扩展的动态库注册,许多相关软件就是从里面获取信息,例如 ShexView。
    2) 关联文件。Shell 扩展一般是针对文件或者文件夹的,因此必须关联。许多人都熟知“HKEY_CLASSES_ROOT*
    ”的作用,就是用来关联所有文件。而文件夹则是“HKEY_CLASSES_ROOTFolder”。然而如果具体到某种文件类型。可能会稍微复杂一点。我们可以从代码中看到一些启示:
    RegTXT
    private static void RegTXT()
    {
        RegistryKey root;
        RegistryKey rk;
        root = Registry.ClassesRoot;
        rk = root.OpenSubKey(".txt");
        string txtclass = (string)rk.GetValue("");
        if (string.IsNullOrEmpty(txtclass))
        {
            txtclass = "TXT";
            rk.SetValue("", txtclass);
        }
        rk.Close();
        rk = root.CreateSubKey(txtclass + "\shellex\ContextMenuHandlers\" + KEYNAME);
        rk.SetValue("", GUID);
        rk.Close();
        rk = root.CreateSubKey(txtclass + "\shellex\IconHandler");
        rk.SetValue("", GUID);
        rk.Close();
        rk = root.CreateSubKey(txtclass + "\shellex\{00021500-0000-0000-C000-000000000046}");
        rk.SetValue("", GUID);
        rk.Close();
    }
    对于关联 .TXT,首先应该找寻“HKEY_CLASSES_ROOT.txt”,但事情远远没那么简单,因为相当多的文本编辑工具,都会把改键重定向,例如EMEditor会把改键的默认值改为“emeditor.txt”。被重定向后,我们为了不破坏原有关联,应该到新的地方去注册(如果没有,我们就修改重定向至 TXT)。无论是 *、文件夹还是具体文件类型,都会有 ShellEx 的键,为 Shell 扩展专用。具体不同的扩展,应该注册不同的键。例如 ContextMenuHandlers、IconHandler、或者{00021500-0000-0000-C000-000000000046}(其实这就是QueryInfo)。注册的方法很简单,把默认值改为 GUID 即可。
    相同文件类型不同图标?如果是以前,我会对这句话十分吃惊。但现在这种现象比比皆是。除了我们的例子外,.NET 程序员最熟悉的莫过于 Sln 解决方案文件了。不同版本的 Sln 图标不同,上面有个小版本号提示。
    不过后来我了解到,原来不同 Exe 显示不同的图标,也是这种原理,我晕
    扩展接口图标扩展处理器实现两个接口 
    IPersistFile

    IExtractIcon

    记得 
    IShellExtInit
    接口用于一次有多个选择文件时的处理,而 
    IPersistFile
    则用于初始化只涉及一个选择文件时的处理。
    IPersistFile 原型
    [ComImport(), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("0000010b-0000-0000-C000-000000000046")]
    public interface IPersistFile
    {
        [PreserveSig]
        uint GetClassID(out Guid pClassID);
        [PreserveSig]
        uint IsDirty();
        [PreserveSig]
        uint Load([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName, [In] uint dwMode);
        [PreserveSig]
        uint Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName, [In] bool fRemember);
        [PreserveSig]
        uint SaveCompleted([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName);
        [PreserveSig]
        uint GetCurFile([MarshalAs(UnmanagedType.LPWStr)] out string ppszFileName);
    }对于这个接口,我们只需要用到 Load 方法
    Load
    public uint Load(string pszFileName, uint dwMode)
    {
        szFileName = pszFileName;
        return S_OK;
    }szFileName 是全局变量,用来记住当前操作的文件路径。IExtractIcon接口图标扩展处理器实现 IExtractIcon
    接口,当浏览器需要为文件显示一个图标时将调用该接口。
    因为我们的扩展用于文本文件,浏览器将在每次显示文本文件对象时调用 
    IExtractIcon
    的方法。IExtractIcon 
    有两个方法,它们的作用是告诉浏览器所使用的图标。记住:浏览器为显示的每一个文件都将创建一个COM 对象。
    这就是说每一个文件都将有一个COM C++类对象对应. 因此在你的扩展中应该避免费时的操作以防止浏览界面反应迟滞。
    IExtractIcon 原型
    [ComVisible(true), ComImport, Guid("000214eb-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IExtractIcon
    {
        [PreserveSig]
        int GetIconLocation([In] ExtractIconOptions uFlags, 
            [In] IntPtr szIconFile, 
            [In] uint cchMax,
            [Out] out int piIndex, 
            [Out] out ExtractIconFlags pwFlags);
        [PreserveSig]
        int Extract([In, MarshalAs(UnmanagedType.LPWStr)] string pszFile, 
            uint nIconIndex, 
            [Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(IconMarshaler))] out Icon phiconLarge, 
            [Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(IconMarshaler))] out Icon phiconSmall, 
            [In] uint nIconSize);
    } 和许多教程上面说的一样,有两种方法可将图标返回给浏览器。但我在尝试第一种方式的时候,未能成功,十分奇怪。不过我还是应该把这种方法简单说明。第一种是 
    GetIconLocation()
    可以返回文件名/索引对以指出包含图标的文件,和图标在该文件中索引位置(以0为基)。
    Extract()
    只需返回 
    S_FALSE
    给浏览器让它自己来解析图标。该方法的特别之处在于浏览器在 
    GetIconLocation()
    返回之后不一定会调用 
    Extract()
    .。浏览器会保持一个图标缓存以存储最近使用的图标。
    如果 
    GetIconLocation()
    返回最近已使用的文件名/索引对,而且图标仍然在缓存中,浏览器就可以直接使用缓存中的图标而不会去调用
    Extract()。
    第二种方法是从
    GetIconLocation()
    中返回不要查看缓冲的标志,这样会使浏览器去调用
    Extract(),
    Extract()
    则负责加载图标资源并将其句柄返回给浏览器。这里具体介绍第二种方法。在这方法中,
    GetIconLocation()
    作用仅仅是设置一些标志位,以及获取文件大小。
    GetIconLocation
    int IExtractIcon.GetIconLocation(ExtractIconOptions uFlags, IntPtr szIconFile, uint cchMax, out int piIndex, out ExtractIconFlags pwFlags)
    {
        piIndex = -1;
        try
        {
            FileInfo f = new FileInfo(szFileName);
            lngFileSize = f.Length;
            pwFlags = ExtractIconFlags.DontCache | ExtractIconFlags.NotFilename;
            return S_OK;
        }
        catch { }
        pwFlags = ExtractIconFlags.None;
        return S_FALSE;
    }
    其参数为: uFlags 改变扩展行为的标志。
    ExtractIconFlags.DONTCACHE
    告诉浏览器不要检查图标缓冲而去使用最近的
    szIconFile/piIndex
    对。其结果是
    IExtractIcon::Extract()
    将被调用.。
    ExtractIconFlags.
    NOTFILENAME 根据 MSDN,该标志告诉浏览器当
    GetIconLocation()
    返回时忽略 
    szIconFile/piIndex
    的内容。
    szIconFile 是由shell 提供的一个缓冲要求我们填入包含所使用的图标的文件名.
    cchMax 是该缓冲区的大小。
    piIndex int 的指针,要求我们添入图标在文件中的索引。
    pwFlags UINT 的指针,要求我们返回影响浏览器行为的标志。使用第二种方法,我们并不需要填写 piIndex 和 szIconFile,而 IExtractIcon.Extract() 总被调用,并负责加载图标并返回两个图标句柄 HICON 给浏览器 – 一个是大图标, 一个是小图标。该方法的好处是你不必考虑你的图标资源在文件中的顺序位置。其缺陷在于它忽略了浏览器的图标缓冲,这会使显示速度减慢,特别是在有浏览有无数个文件的目录时。
    IExtractIcon.Extract
    int IExtractIcon.Extract(string pszFile, uint nIconIndex, out Icon phiconLarge, out Icon phiconSmall, uint nIconSize)
    {
        phiconLarge = null;
        phiconSmall = null;
        try
        {
            if (lngFileSize > 16 * 1024)
            {
                phiconLarge = Resource1._2;
                phiconSmall = new Icon(Resource1._2, new Size(16, 16));
            }
            else if (lngFileSize > 0)
            {
                phiconLarge = Resource1._1;
                phiconSmall = new Icon(Resource1._1, new Size(16, 16));
            }
            else
            {
                phiconLarge = Resource1._0;
                phiconSmall = new Icon(Resource1._0, new Size(16, 16));
            }
            return S_OK;
        }
        catch { }
        return S_FALSE;
    }
    其参数为: 
    pszFile/nIconIndex 文件名和索引指定图标位置。其值与从 GetIconLocation() 返回的一样。
    phiconSmall HICON 的指针,由 Extract() 返回指向大图标和小图标的句柄数组。
    nIconSize 指定要求的图标大小。高字为小图标的长度 (长宽一致),低字为大图标的长度。在一般情况下, 其值为0×00100020 (高字16, 低字 32) 表示小图标应该是 16×16,大图标为 32×32。在我们的扩展中, 我们并没有在 GetIconLocation() 里填写 pszFile 和 nIconIndex 所以在这忽略,我们只加载图标并返回给浏览器。从代码可以看到,根据文件大小的不同,加载了相应的图标资源返回给浏览器。效果如下:
    代码:MyContextMenu.rar
    关于代码:代码里面还包括了提示扩展的代码,如果有兴趣,可自行阅读。题外话:还有相当多的关于 Shell 扩展的内容无法一一说明,如果有机会,以后会尽量补上。或大家查阅网上的“Windows Shell扩展编程完全指南”(虽然是VC版的,但内容相当丰富)