博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Windows Shell编程之如何编写为文件对象弹出信息框的Shell扩展
阅读量:6369 次
发布时间:2019-06-23

本文共 4193 字,大约阅读时间需要 13 分钟。

有关COM编程资料

转载:

活动桌面引入一项新特性, 当你在某些特定对象上旋停鼠标时,工具提示将显示它们的描述

例如对TXT格式文件:

系统默认的:                                                            扩展之后的:

                               

 

第一步:新建一个ATL项目,输入工程名:TxtInfo,具体如下图:

 

第二步:点击next

 

第三步:应用类型选择动态库链接(DLL),同时勾选支持MFC,最后点击Finish。

第四步:新建一个ATL简单对象(英文版的VS为ATLSimple Object)

 

单击 Add,在第二页面中, 在Short Name编辑框中输入TxtInofShlExt,点击 Finish.

 

第五步:开始我们需要添加IPersistFileCTxtInfoShlExt实现的接口列表中.打开 TxtInfoShlExt.h, 并添加如下代码:

 

1 #include 
2 #include
3 class ATL_NO_VTABLE CTxtInfoShlExt : 4 public CComObjectRootEx, 5 public CComCoClass, 6 public IDispatchImpl, 7 public IPersistFile 8 { 9 BEGIN_COM_MAP(CTxtInfoShlExt) 10 COM_INTERFACE_ENTRY(ITxtInfoShlExt)11 COM_INTERFACE_ENTRY(IDispatch)12 COM_INTERFACE_ENTRY(IPersistFile)13 END_COM_MAP()

我们需要一个保存浏览器给出的文件名的变量:

protected:
// ITxtInfoShlExt

CString m_sFilename;

注意我们可以在任何地方使用 MFC 对象.如果你看一下 IpersistFile 的文档, 你会看到很多方法.

幸运的是, 对于Shell扩展, 我们只用实现Load(), 而忽略其它方法. 以下是 IPersistFile 方法的原型: 

public: // IPersistFile STDMETHOD(GetClassID)(LPCLSID) { return E_NOTIMPL; }STDMETHOD(IsDirty)() { return E_NOTIMPL; } STDMETHOD(Load)(LPCOLESTR, DWORD); STDMETHOD(Save)(LPCOLESTR, BOOL) { return E_NOTIMPL; } STDMETHOD(SaveCompleted)(LPCOLESTR) { return E_NOTIMPL; } STDMETHOD(GetCurFile)(LPOLESTR*) { return E_NOTIMPL; }

除开 Load() 外的方法都只返回 E_NOTIMPL 以表明我们没有实现它们.

更妙的是, Load() 方法也相当简单. 我们只需保存浏览器传给我们的文件名. 也就是当前鼠标在其上盘旋的文件.

HRESULT CTxtInfoShlExt::Load ( LPCOLESTR wszFilename, DWORD dwMode ){ AFX_MANAGE_STATE(AfxGetStaticModuleState()); // init MFC // 让CString 自动转化文件名为 ANSI 字符.m_sFilename = wszFilename; return S_OK;}

请注意函数的第一行. 要让MFC正确地工作该行代码是必要的.

由于我们的 DLL 要被非MFC程序所调用, 任一个使用MFC的输出函数必须手动初始化 MFC.
如果你不写这行代码, 则许多MFC函数 (大多是与资源处理有关的函数) 将失败或出错.
文件名被保存在 m_sFilename 以备后用.
注意我利用了 CString 的赋值操作符的特性来转化字符串为ANSI格式 - 如果该 DLL以ANSI方式建立.
创建工具提示的文本
在浏览器调用了我们的 Load() 方法之后, 它接着调用 QueryInterface() 获取另一个接口: IQueryInfo. IQueryInfo 是个相当简单的接口,只有两个接口 (而其中也只有一个被真正使用). 打开 TxtInfoShlExt.h ,添加如下标红的代码:

class ATL_NO_VTABLE CTxtInfoShlExt : public CComObjectRootEx, public CComCoClass,public IDispatchImpl, public IPersistFile,public IQueryInfo{BEGIN_COM_MAP(CTxtInfoShlExt)COM_INTERFACE_ENTRY(ITxtInfoShlExt)COM_INTERFACE_ENTRY(IDispatch)COM_INTERFACE_ENTRY(IPersistFile) COM_INTERFACE_ENTRY(IQueryInfo)END_COM_MAP()

然后添加 IQueryInfo 方法的实现:

// IQueryInfo STDMETHOD(GetInfoFlags)(DWORD*) { return E_NOTIMPL; } STDMETHOD(GetInfoTip)(DWORD, LPWSTR*);

GetInfoFlags() 方法当前并不使用, 所以我们只返回 E_NOTIMPL.

GetInfoTip() 让我们返回工具提示文本 字符串. 首先是开头繁琐的代码:

 

HRESULT CTxtInfoShlExt::GetInfoTip ( DWORD dwFlags, LPWSTR* ppwszTip )

{
AFX_MANAGE_STATE(AfxGetStaticModuleState()); // init MFC

LPMALLOC pMalloc;

CStdioFile file;
DWORD dwFileSize;
CString sFirstLine;
BOOL bReadLine;
CString sTooltip;
USES_CONVERSION;

接着,AFX_MANAGE_STATE首先被调用以初始化 MFC.

这是每个函数都该做的第一件事, 甚至应该在变量声明之前,因为MFC构造函数可能调用其它的 MFC 函数.

dwFlags 当前并不被使用. ppwszTip 是个 LPWSTR (Unicode 字符串指针) 变量的指针,我们要将其赋值为我们所分配的字符

串缓冲区的指针.(指向指针的指针)

首先, 我们试着打开文件读取. 由于我们在Load()中保存了文件名,现在就可以使用了.

if ( !file.Open ( m_sFilename , CFile::modeRead | CFile::shareDenyWrite )) return E_FAIL;

现在, 我们需要使用Shell的内存分配器分配一个缓冲, 我们通过SHGetMalloc()函数获取一个IMalloc接口:

if ( FAILED( SHGetMalloc ( &pMalloc ))) return E_FAIL;

关于Imalloc 稍后我有更多的要说. 下一步是取得文件大小并读取第一行:

// 取得文件大小.
dwFileSize = file.GetLength();

// 读取第一行.

bReadLine = file.ReadString ( sFirstLine );
bReadLine总是为真, 除非文件不可获取或长度为0.下一步是创建工具提示的第一部分:文件大小.
sTooltip.Format ( _T("File size: %lu"), dwFileSize );

现在, 我们读取第一行并添加到工具提示中.

if ( bReadLine )
{
sTooltip += _T("\n"); sTooltip += sFirstLine;
}

现在我们完成了工具提示, 我们要分配一个缓冲.在这我们将使用 Imalloc 接口.

由 SHGetMalloc() 返回的指针是一个Shell的Imalloc接口指针的拷贝.
我们用这个接口分配的任何内存都位于Shell的进程空间内, 所以Shell可以使用它.
更重要的是, Shell可以释放它. 所以我们所作的就是分配缓冲区,然后忘掉它.
Shell将在完成操作时释放该内存.

要认识到的一件事是我们返回给Shell的字符串必须是 Unicode 格式的.

这就是为什么下面的Alloc()中的计算要乘以 sizeof(wchar_t);
只分配lstrlen(sToolTip)长的内存只够一半所需的内存.

*ppwszTip=(LPWSTR)pMalloc->Alloc ((1 + lstrlen(sTooltip))*sizeof(wchar_t));

if (NULL == *ppwszTip)
{
pMalloc->Release();
return E_OUTOFMEMORY;
}
// 使用 Unicode 字符串拷贝函数将工具提示文本拷入缓冲区.
wcscpy ( *ppwszTip, T2COLE((LPCTSTR) sTooltip) );
//最后我们释放先前获取得 IMalloc 接口.
pMalloc->Release();
return S_OK;
}

 

用命令行注册COM :regsvr32 dll的绝对路径

注:必须以管理员运行cmd

 卸载COM: regsvr32 /u dll的绝对路径

 

如果你的操作系统是64位的 编译的工程必须x64

如果你的操作系统是32位的 编译工程是Win32

第六步:编辑TxtInfoShlExt.rgs文件

          方式一:

                  

 

方式二:

 源码:

 参考源码:

参考资料:

你可能感兴趣的文章
Edge 浏览器奇葩 bug:“123456”打印成“114447”
查看>>
Sirius —— 开源版的 Siri ,由 Google 支持
查看>>
《OpenGL ES应用开发实践指南:Android卷》—— 2.7 小结
查看>>
《Windows Server 2012活动目录管理实践》——第 2 章 部署第一台域控制器2.1 案例任务...
查看>>
Java Date Time 教程-时间测量
查看>>
Selector.wakeup实现注记
查看>>
《Java EE 7精粹》—— 第1章 Java EE 1.1 简介
查看>>
《Exchange Server 2013 SP1管理实践》——导读
查看>>
syslog:类Unix系统常用的log服务
查看>>
使用Annotation设计持久层
查看>>
深入实践Spring Boot2.4.1 Neo4j依赖配置
查看>>
Zen Cart 如何添加地址栏上的小图标
查看>>
SecureCrt 连接Redhat linux
查看>>
[NHibernate]持久化类(Persistent Classes)
查看>>
如何在Hive中使用Json格式数据
查看>>
linux如何恢复被删除的热文件
查看>>
Eclipse(MyEclipse) 自动补全
查看>>
Struts2中dispatcher与redirect的区别
查看>>
zabbix agentd configure
查看>>
地图点聚合优化方案
查看>>