[ShellExtension]图标扩展-IShellIconlayIdentifier实现

来源:互联网 发布:软件开发维护招聘 编辑:程序博客网 时间:2024/06/05 14:53

习惯性的先亮源码地址:https://git.oschina.net/xiangmu110/template_IShellIconlayIdentifier

以下讲解的可能与源码不同,但都是一个模版出来的!
下面实现的是在后缀为“.txt”的文件图标上面覆盖一个Star图标。
这里写图片描述

首先创建一个C++ ATL工程,取名为“ShellIconlayIdentifier”。
这里写图片描述

将“允许合并代理/存根代码”和“支持MFC”打勾,然后点击完成按钮即可。
这里写图片描述

工程创建完毕,先不着急编译,因为默认情况下编译后VS会自动注册输出,如果注册时没有管理员权限的话,会提示失败。本人觉得自动注册不好,不便于管理,所以在编译之前先将这个设置关闭。如下。
这里写图片描述

至此基本的工程创建和设置就完成了,就可以编译试试了。

接下来就是图标扩展的实现过程。
1、添加一个ATL简单对象。
这里写图片描述

因为是为“.txt”的文件添加覆盖图标,所以我们在简称处填写“TxtExt”,后面的名称均会依据这个简称自动生成。然后点击完成即可。
这里写图片描述

完成之后就创建了三个文件,“CTxtExt”类的头文件和源文件及其注册表文件,如图。
这里写图片描述

2、修改代码,实现继承“IShellIconOverlayIdentifier”接口。

// TxtExt.h : CTxtExt 的声明#pragma once#include  "resource.h"       // 主符号#include "ShellIconlayIdentifier_i.h"#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)#error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。"#endifusing namespace ATL;// CTxtExtclass ATL_NO_VTABLE CTxtExt :    public CComObjectRootEx<CComSingleThreadModel>,    public CComCoClass<CTxtExt, &CLSID_TxtExt>,    public IDispatchImpl<ITxtExt, &IID_ITxtExt, &LIBID_ShellIconlayIdentifierLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,    public IShellIconOverlayIdentifier//添加实现接口{public:    CTxtExt()    {    }DECLARE_REGISTRY_RESOURCEID(IDR_TXTEXT)BEGIN_COM_MAP(CTxtExt)    COM_INTERFACE_ENTRY(ITxtExt)    COM_INTERFACE_ENTRY(IDispatch)    COM_INTERFACE_ENTRY(IShellIconOverlayIdentifier)//添加接口入口END_COM_MAP()    DECLARE_PROTECT_FINAL_CONSTRUCT()    HRESULT FinalConstruct()    {        return S_OK;    }    void FinalRelease()    {    }public:    //实现接口的三个函数    STDMETHOD(GetPriority(THIS_ _Out_ int * pIPriority));    STDMETHOD(IsMemberOf(THIS_ _In_ PCWSTR pwszPath, DWORD dwAttrib));    STDMETHOD(GetOverlayInfo(THIS_ _Out_writes_(cchMax) PWSTR pwszIconFile, int cchMax, _Out_ int * pIndex, _Out_ DWORD * pdwFlags));};OBJECT_ENTRY_AUTO(__uuidof(TxtExt), CTxtExt)// TxtExt.cpp : CTxtExt 的实现#include "stdafx.h"#include "TxtExt.h"// CTxtExt//pwszPath 为当前文件的全路径STDMETHODIMP CTxtExt::IsMemberOf(THIS_ _In_ PCWSTR pwszPath, DWORD dwAttrib){    HRESULT hRef = S_FALSE;    wchar_t* fileClass = _wcsdup(wcsrchr(pwszPath, '.'));    if (fileClass != NULL)    {        if (_wcsicmp(fileClass, L".txt") == 0)        {//判断是否是txt后缀的文件            hRef = S_OK;        }    }    free(fileClass);    //如果是符合要求的文件,就返回S_OK    return hRef;}//pwszIconFile 用于设置图标文件的路径,路径长度不能超过cchMax个字符。//pIndex 用于设置图标覆盖的先后顺序STDMETHODIMP CTxtExt::GetOverlayInfo(THIS_ _Out_writes_(cchMax) PWSTR pwszIconFile, int cchMax, _Out_ int * pIndex, _Out_ DWORD * pdwFlags){    WCHAR *buff = new WCHAR[cchMax];    //获取当前程序的路径,而不是调用该程序的程序的路径,因为调用该程序的是资源管理器(explorer.exe),直接过去路径的话,获取的是资源管理器的路径。    GetModuleFileNameW(_AtlBaseModule.GetModuleInstance(), buff, cchMax);    WCHAR *nChar = wcsrchr(buff, L'\\');    if (nChar != NULL)    {//写入当前程序路径下的图标的名字        wcscpy_s(nChar, cchMax - wcslen(buff), L"\\star.ico");        wcscpy_s(pwszIconFile, cchMax, buff);    }    //设置顺序    *pIndex = 0;    //标识所修改过的数据pwszIconFile 与 pIndex    *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;    free(buff);    //完成返回S_OK    return S_OK;}STDMETHODIMP CTxtExt::GetPriority(THIS_ _Out_ int * pIPriority){    *pIPriority = 0;    return S_OK;}

3、因为Shell扩展是要注册到系统中去的,所以还需要修改“TxtExt.rgs”注册表文件,也可以写在工程生成时自带的“ShellIconlayIdentifier.rgs”的文件中。
首先要取得创建“CTxtExt”时,系统创建的“TxtExt.rgs”中标识这个类的GUID。
这里写图片描述

然后在上诉两个文件中的任意一个文件中写入如下代码。

HKLM{    NoRemove SOFTWARE    {        NoRemove Microsoft        {            NoRemove Windows            {                NoRemove CurrentVersion                {                    NoRemove Explorer                    {                        NoRemove ShellIconOverlayIdentifiers                        {                            ForceRemove CTxtExt = s '{3FF1599D-C471-4F69-806D-57EA818677BA}'                        }                    }                }            }        }    }}

这段代码的意思就是将这个程序注册到资源管理器下的注册表项中。

至此代码修改完成,接下来生成一个!
需要注意的是需要区分系统是X86/X64,如果是X64的系统,请生成X64的程序,要不然不起作用的。
然后将程序中标明的图标的名字“star.ico”的图标与生成的程序放在一个目录。
这里写图片描述

所有的准备工作已经完成,接下来就是注册这个程序。
以管理员权限打开控制台,然后跳转到程序所在目录。
输入以下命令注册程序。

regsvr32 ShellIconlayIdentifier.dll

注册成功后如下图。
这里写图片描述

程序虽然注册成功了,但是还没有真正被使用,需要重启资源管理器,可以手动重启下。或在控制台下输入以下重启命令。

taskkill /f /im explorer.exe & explorer

重启后就可以看到效果了!
这里写图片描述

如图就实现了,仅对我们需要标识的文件添加覆盖图标。

如果想卸载程序的话需要执行以下命令,并且也需要重启资源管理器。

regsvr32 /u ShellIconlayIdentifier.dlltaskkill /f /im explorer.exe & explorer

之后就可以删除这个程序了,要不然这个程序一直被资源管理器占用,是删除不了的。

最后,还有一些小细节提醒一下,微软对这个覆盖图标的启用数量有限制,但注册的时候不会报错,只不过程序不会启用而已,比较坑。。所以我们可以学学360,看人家多怪,因为启用顺序是从第一个开始的,所以360在前面加“ ”即空格,很多个空格。。让他的程序排序靠前,这就使的他的程序不会被忽略掉=。=,简直6翻了,9999。
这里写图片描述

可以在一个工程中实现多种图标覆盖程序,但是必须新建一个简单对象,然后在新建的简单对象中进行修改。因为是在“IsMemberOf”函数中判断是否是我们需要添加的文件,然后再在“GetOverlayInfo”函数中选择覆盖用的那个图标的,这两个函数之间无法使用成员变量来区分所要添加文件的种类。所以,还是老老实实的一种文件的图标覆盖程序,就对应一个ATL简单对象!

读者如有不懂之处敬请留言,如有不对的地方也请指出,谢谢~

这里写图片描述

0 0
原创粉丝点击