| 网站首页 | 业界新闻 | 技术文章 | 视频教程 | 下载频道 | 程序源码 | 个人空间 | 编程论坛 |
 
| 技术教程首页 | 开发语言 | WEB开发 | .NET技术 | 数据库 | 操作系统 | 网页制作 |
 
 
您现在的位置: 编程中国 >> 技术教程 >> 开发语言 >> VC++ >> VC技术资料 >> 正文
  ►  Shell扩展编程实现Windows2000桌面图标透明
Shell扩展编程实现Windows2000桌面图标透明
作者:sinall    阅读人次:……    文章来源:CSDN    发布时间:2007-8-29    网友评论()条
 

(本文根据《Windows Shell扩展编程完全指南》改写)

开始编写上下文菜单 它该做些什么?
开头先让我们做简单一些, 只弹出一个对话框以表明当前的扩展能够正常地工作.
我们把扩展关联到 .TXT 文件, 因此当用户右键单击文本文件对象时扩展就会被调用
.

使用 AppWizard 开始
好吧, 让我们开始吧! 什么? 我还没告诉你怎样使用那些神秘的 shell 扩展接口?
别着急, 我会边进行边解释的。

我觉得先解释一下一个概念再紧接着说明示例代码,对理解例子程序会更简单一些. 当然我也可以把所有的东西都先解释完,然后再解释代码, 但我觉得这样做不能吸引人的注意力。不管怎么样, VC开火,开始!

运行AppWizard,生成一个名为SimpleExt ATL COM 工程. 保留所有默认的设置选项,点击”完成”
.
现在我们已经有了一个空的 ATL工程,它可以编译并生成一个 DLL, 但我们还需要添加Shell扩展的 COM 对象
.
ClassView , 右击 SimpleExt classes 条目, 选择 New ATL Object.

ATL Object Wizard, 第一页默认已经选择了 Simple Object , 所以单击 Next 即可.
在第二页中, Short Name 文本框里输入 SimpleShlExt ,点击 OK. (其余的文本框会自动填充完
.)
这样就创建了一个名为 CSimpleShlExt 的类,其包含了实现COM对象最基本的代码. 我们将在这个类中加入我们自己的代码
.

初始化接口
当我们的shell扩展被加载时, Explorer 将调用我们所实现的COM对象的 QueryInterface() 函数以取得一个 IShellExtInit 接口指针.
该接口仅有一个方法 Initialize(), 其函数原型为:

HRESULT IShellExtInit::Initialize ( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID );

Explorer 使用该方法传递给我们各种各样的信息.
PidlFolder
是用户所选择操作的文件所在的文件夹的 PIDL 变量. (一个 PIDL [指向ID 列表的指针] 是一个数据结构,它唯一地标识了在Shell命名空间的任何对象, 一个Shell命名空间中的对象可以是也可以不是真实的文件系统中的对象
.)
pDataObj
是一个 IDataObject 接口指针,通过它我们可以获取用户所选择操作的文件名。

hProgID
是一个HKEY 注册表键变量,可以用它获取我们的DLL的注册数据.
在这个简单的扩展例子中, 我们将只使用到 pDataObj 参数.

要添加这个接口进 COM 对象, 先打开SimpleShlExt.h 文件, 然后加入下列标红的代码:

#include "shlobj.h"
#include "comdef.h"

class ATL_NO_VTABLE CSimpleShlExt :
public CComObjectRootEx,
public CComCoClass,
public IDispatchImpl,
public IShellExtInit

BEGIN_COM_MAP(CSimpleShlExt)
COM_INTERFACE_ENTRY(ISimpleShlExt)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IShellExtInit)
END_COM_MAP()

COM_MAP是ATL实现 QueryInterface()机制的宏,它包含的列表告诉ATL其它外部程序用QueryInterface()能从我们的 COM对象获取哪些接口.
接着,在类声明里, 加入Initialize()的函数原型.
另外我们需要一个变量来保存文件名:

protected:
TCHAR m_szFile [MAX_PATH];
public:
// IShellExtInit
STDMETHOD(Initialize)(LPCITEMIDLIST, LPDATAOBJECT, HKEY);

然后, 在 SimpleShlExt.cpp 文件中, 加入该函数方法的实现定义:

HRESULT CSimpleShlExt::Initialize ( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID )

我们要做的是取得当前鼠标所在的窗口,并把它和桌面上的ListView

做比较,如果二者不同,则鼠标是在其他Dictionary上点击,不添加

菜单,直接返回:

{
         HWND Wnd;

         Wnd=::GetDesktopWindow();

         Wnd=FindWindowEx(Wnd, 0, "Progman", NULL);

         Wnd = ::FindWindowEx(Wnd, 0, "SHELLDLL_DefView", NULL);

         Wnd = ::FindWindowEx(Wnd, 0, "SysListView32", NULL);

         POINT Point;

         ::GetCursorPos(&Point);

         if(::WindowFromPoint(Point)!=Wnd)

                   return E_INVALIDARG;

         return S_OK;

}

要是我们返回 E_INVALIDARG, Explorer 将不会继续调用以后的扩展代码.
要是返回 S_OK, Explorer 将再一次调用QueryInterface() 获取另一个我们下面就要添加的接口指针
: IContextMenu.

与上下文菜单交互的接口

一旦 Explorer 初始化了扩展,它就会接着调用 IContextMenu 的方法让我们添加菜单项, 提供状态栏上的提示, 并响应执行用户的选择.

添加IContextMenu 接口到Shell扩展类似于上面IshellExtInit接口的添加 .打开 SimpleShlExt.h,添加下列标红的代码:

class ATL_NO_VTABLE CSimpleShlExt :
public CComObjectRootEx,
public CComCoClass,
public IDispatchImpl,
public IShellExtInit,
public IContextMenu

{
BEGIN_COM_MAP(CSimpleShlExt)
COM_INTERFACE_ENTRY(ISimpleShlExt)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IShellExtInit)
COM_INTERFACE_ENTRY(IContextMenu)

END_COM_MAP()

添加 IContextMenu 方法的函数原型:

public:
// IContextMenu
STDMETHOD(GetCommandString)(UINT, UINT, UINT*, LPSTR, UINT);
STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO);
STDMETHOD(QueryContextMenu)(HMENU, UINT, UINT, UINT, UINT);

修改上下文菜单 IContextMenu 有三个方法.
第一个是 QueryContextMenu(), 它让我们可以修改上下文菜单. 其原型为:

HRESULT IContextMenu::QueryContextMenu ( HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags );

hmenu 上下文菜单句柄.
uMenuIndex
是我们应该添加菜单项的起始位置
.
uidFirstCmd
uidLastCmd 是我们可以使用的菜单命令ID值的范围
.
uFlags
标识了Explorer 调用QueryContextMenu()的原因
,
这我以后会说到的.

而返回值根据你所查阅的文档的不同而不同.
Dino Esposito
的书中说返回值是你所添加的菜单项的个数
.
VC6.0所带的MSDN 又说它是我们添加的最后一个菜单项的命令ID加上
1.
而最新的 MSDN 又说
:
将返回值设为你为各菜单项分配的命令ID的最大差值,加上
1.
例如, 假设 idCmdFirst 设为5,而你添加了三个菜单项 ,命令ID分别为 5, 7,
8.
这时返回值就应该是:
MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 - 5 + 1).

我是一直按 Dino 的解释来做的, 而且工作得很好
.
实际上, 他的方法与最新的 MSDN 是一致的, 只要你严格地使用 uidFirstCmd作为第一个菜单项的ID,再对接续的菜单项ID每次加
1.

[1] [2] 下一页

 

 
文章录入:编辑01    责任编辑:编辑01 
  • 上一篇文章:

  • 下一篇文章:

  •  
    相关文章
    原创地带
    24小时热门帖子