2、VS2005(c/c++)外壳扩展编程之windows右键菜单(2)

简介: 第二部分 Windows SHELL编程     There are many types of shell extensions, each type being invoked when different events happen.

第二部分 Windows SHELL编程<?xml:namespace prefix = o />

    There are many types of shell extensions, each type being invoked when different events happen. Here are a few of the more common types, and the situations in which they are invoked:[7]

Type

When it's invoked

What it does

Context menu handler

User right-clicks on a file or folder. In shell versions 4.71+, also invoked on a right-click in the background of a directory window.

Adds items to the context menu.

Property sheet handler

Properties dialog displayed for a file.

Adds pages to the property sheet.

Drag and drop handler

User right-drags items and drops them on a directory window or the desktop.

Adds items to the context menu.

Drop handler

User drags items and drops them on a file.

Any desired action.

QueryInfo handler (shell version 4.71+)

User hovers the mouse over a file or other shell object like My Computer.

Returns a string that Explorer displays in a tooltip.

Before we begin coding, there are some tips that will make the job easier. When you cause a shell extension to be loaded by Explorer, it will stay in memory for a while, making it impossible to rebuild the DLL.

To have Explorer unload extensions more often, create this registry key:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\AlwaysUnloadDLL

and set the default value to "1". On 9x, that's the best you can do. On NT, go to this key:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer and create a DWORD called DesktopProcess with a value of 1. This makes the desktop and Taskbar run in one process,

and subsequent Explorer windows each run in its own process. This means that you can do your debugging with a single Explorer window, and when you close it, your DLL is automatically unloaded, avoiding

any problems with the file being in use. You will need to log off and back on for these changes to take effect.[7]

第一:注册表编程。第二:Shell Extension COM编程。通过注册表方式实现

其实十分简单,请参阅 COM[1]组件注册表实现。在以下的内容为 shell 扩展编程---" Context Menu 处理器。

Shell扩展实例均为进程内组件,它们均以动态库的形式存在。

When our shell extension is loaded, Explorer calls our QueryInterface() function to get a pointer to an IShellExtInit interface.[7]

IShellExtInit接口:IShellExtInit 接口为 Shell 扩展编程必须要实现的接口。该接口主要用来初始化 Shell 扩展处理器,它仅有一个虚成员函数Initialize,用户所有的 Shell 扩展初始化动作都由该函数完成。

Initialize 函数中,我们要做的事情就是获取用户鼠标右键点击的文件名称。当用户在一个拥有WS_EX_ACCEPTFILES风格的窗体中Drag/Drop文件时这些文件名会以同一种格式存储,而且文件完整路径的获取也都以DragQueryFile API函数来实现。但是DragQueryFile需要传入一个HDROP句柄,该句柄即为Drag/Drop文件名称列表数据句柄(开始存放数据的内存区域首指针)。而 HDROP句柄的可以通过接口"DATAOBJECT lpdobj"的成员函数"GetData"来获取。

进程内组件编程的一些特点,大体总结如下:"新建自己的接口,然后继承某些接口,最后一一实现这些接口的所有虚成员函数或加入自己的成员函数,最后就是组件的注册"

1) 初始化接口

int Initialize(IntPtr pidlFolder, IntPtr lpdobj, uint hKeyProgID);

HRESULT IShellExtInit::Initialize (

LPCITEMIDLIST pidlFolder,

LPDATAOBJECT pDataObj,

HKEY hProgID )

Explorer 使用该方法传递给我们各种各样的信息.

Explorer uses this method to give us various information. pidlFolder is the PIDL of the folder containing the files being acted upon. (A PIDL [pointer to an ID

list] is a data structure that uniquely identifies any object in the shell, whether it's a file system object or not.) pDataObj is an IDataObject interface

pointer through which we retrieve the names of the files being acted upon. hProgID is an open HKEY which we can use to access the registry key containing

our DLL's registration data. For this simple extension, we'll only need to use the pDataObj parameter.[7]

pidlFolder 是用户所选择操作的文件所在的文件夹的PIDL变量(一个PIDL[指向ID列表的指针],是一个数据结构,它唯一地标识了在Shell命名空间的任何对象,一个Shell命名空间中的对象可以是也可以不是真实的文件系统中的对象。)lpdobj是一个IDataObject接口指针,通过它我们可以获取用户所选择操作的文件名。hKeyProgID是一个HKEY注册表键变量,可以用它获取我们的DLL的注册数据。

因此我们可以在这个方法中,获取到被右击选择的一个或多个文件/文件夹名。

The COM_MAP is how ATL implements QueryInterface(). It tells ATL what interfaces other programs can retrieve from our COM objects.[7]

2) 与上下文菜单交互的接口

Once Explorer has initialized our extension, it will call the IContextMenu methods to let us add menu items, provide fly-by help, and carry out the user's selection.[7]

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

处理器类型 COM接口

Context menu 处理器 IContextMenu

Property sheet 处理器 IShellPropSheetExt

Drag and drop 处理器 IContextMenu

Drop 处理器 IDropTarget

QueryInfo 处理器(Shell V4.71+) IQueryInfo

其中的"Drag and drop 处理器"除了COM接口IContextMenu需要实现外还得需要注册表的特殊注册才行。IContextMenu 接口有三个虚成员函数需要我们的组件来实现:

The first one, QueryContextMenu(), lets us modify the menu.[7]

QueryContextMenu,在QueryContextMenu 成员函数中我们可以加入自己的菜单项,通过 InsertMenu API 函数来实现。

HRESULT IContextMenu::QueryContextMenu (

HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd,

UINT uidLastCmd, UINT uFlags );

hmenu is a handle to the context menu. uMenuIndex is the position in which we should start adding our items. uidFirstCmd and uidLastCmd are the range of

command ID values we can use for our menu items. uFlags indicates why Explorer is calling QueryContextMenu(), and I'll get to this later.[7]

3) 在状态栏上显示提示帮助

The next IContextMenu that can be called is GetCommandString(). If the user right-clicks a text file in an Explorer window, or selects a text file and then clicks the File menu, the status bar will show fly-by help when our menu item is highlighted. Our GetCommandString() function will return the string that we want Explorer to show.

GetCommandStringGetCommandString 成员函数为 Explorer 提供了在状态栏显示菜单命令提示信息的方法。在这个方法中 "LPSTR pszName" 是我们要关注的参数,我们只要根据 "UINT uFlags" 参数来填充 "LPSTR pszName" 参数即可。在COM 编程中尽可能使用兼容的 TCHAR 类型,也尽量不要使用C类函数库,因为这样会使您无法通过 "Win32 Release Mindependency " 或其他 UINCode/Release 版本的编译过程。

HRESULT IContextMenu::GetCommandString (

UINT idCmd, UINT uFlags, UINT* pwReserved,

LPSTR pszName, UINT cchMax );

idCmd is a zero-based counter that indicates which menu item is selected. Since we have just one menu item, idCmd will always be zero. But if we had added, say, 3 menu items,

idCmd could be 0, 1, or 2. uFlags is another group of flags, We can ignore pwReserved. pszName is a pointer to a buffer owned by the shell where we will store

the help string to be displayed. cchMax is the size of the buffer. The return value is one of the usual HRESULT constants, such as S_OK or E_FAIL.[7]

GetCommandString() can also be called to retrieve a "verb" for a menu item. A verb is a language-independent string that identifies an action that can be taken on a file. The docs for ShellExecute() have more to say, and the subject of verbs is best suited for another article, but the short version is that verbs can be either listed in the registry

(such as "open" and "print"), or created dynamically by context menu extensions. This lets an action implemented in a shell extension be invoked by a call to ShellExecute().

Anyway, the reason I mentioned all that is we have to determine why GetCommandString() is being called. If Explorer wants a fly-by help string, we provide it. If Explorer is asking for a verb, we'll just ignore the request. This is where the uFlags parameter comes into play. If uFlags

has the GCS_HELPTEXT bit set, then Explorer is asking for fly-by help. Additionally, if the GCS_UNICODE bit is set, we must return a Unicode string.[7]

下一个要被调用的IContextMenu 方法是 GetCommandString().。如果用户是在浏览器窗口中右击文本文件,或选中一个文本文件后单击文件菜单时,状态栏会显示提示帮助。我们的 GetCommandString() 函数将返回一个帮助字符串供浏览器显示。

4)执行用户的选择

InvokeCommand,实现最终菜单项命令的执行。

This method is called if the user clicks on the menu item we added. The prototype for InvokeCommand() is:

HRESULT IContextMenu::InvokeCommand (

LPCMINVOKECOMMANDINFO pCmdInfo );

IContextMenu 接口的最后一个方法是 InvokeCommand()。当用户点击我们添加的菜单项时该方法将被调用。其参数:CMINVOKECOMMANDINFO 结构带有大量的信息, 但我们只关心 lpVerb hwnd 这两个成员。

lpVerb performs double duty - it can be either the name of the verb that was invoked, or it can be an index telling us which of our menu items was clicked on. hwnd is the handle of the Explorer

window where the user invoked our extension; we can use this window as the parent window for any UI that we show.[7]

lpVerb参数有两个作用------它或是可被激发的verb(动作),或是被点击的菜单项的索引值。hwnd 是用户激活我们的菜单扩展时所在的浏览器窗口的句柄。我们可以根据被点击的菜单项索引,来执行相应的操作。

5)注册Shell扩展

现在我们已经实现了所有需要的COM接口. 可是我们怎样才能让浏览器使用我们的扩展呢?首先,我们要注册动态库。但仅仅这样是不够的,为了告诉浏览器使用我们的扩展, 我们需要在文本文件类型(因为我们要关联文本)的注册表键下注册扩展。ATL automatically generates code that registers our DLL as a COM server, but that just lets other apps use our DLL. In order to tell Explorer our extension exists, we need to register it under the key that holds info about text files[7]

The NoRemove keyword means that the key should not be deleted when the server is unregistered,ForceRemove, which means that if the key exists, it will be deleted

before the new key is written.

目录
相关文章
|
3月前
|
存储 算法 C++
Windows共享文件:探秘C++实现的B树索引算法奇境
在数字化时代,Windows共享文件的高效管理至关重要。B树算法以其自平衡多路搜索特性,在文件索引与存储优化中表现出色。本文探讨B树在Windows共享文件中的应用,通过C++实现具体代码,展示其构建文件索引、优化数据存储的能力,提升文件检索效率。B树通过减少磁盘I/O操作,确保查询高效,为企业和个人提供流畅的文件共享体验。
|
5月前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
5月前
|
存储 机器学习/深度学习 编译器
【C++终极篇】C++11:编程新纪元的神秘力量揭秘
【C++终极篇】C++11:编程新纪元的神秘力量揭秘
|
9月前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
1086 72
|
9月前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
976 131
|
5月前
|
存储 算法 C++
深入浅出 C++ STL:解锁高效编程的秘密武器
C++ 标准模板库(STL)是现代 C++ 的核心部分之一,为开发者提供了丰富的预定义数据结构和算法,极大地提升了编程效率和代码的可读性。理解和掌握 STL 对于 C++ 开发者来说至关重要。以下是对 STL 的详细介绍,涵盖其基础知识、发展历史、核心组件、重要性和学习方法。
|
5月前
|
存储 安全 算法
深入理解C++模板编程:从基础到进阶
在C++编程中,模板是实现泛型编程的关键工具。模板使得代码能够适用于不同的数据类型,极大地提升了代码复用性、灵活性和可维护性。本文将深入探讨模板编程的基础知识,包括函数模板和类模板的定义、使用、以及它们的实例化和匹配规则。
|
8月前
|
消息中间件 存储 安全
|
9月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
165 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
9月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
159 11