(1)QueryContextMenu函数:每当系统要显示一个文件对象的上下文相关菜单时,它首先要调用该函数。为了在上下文相关菜单中添加菜单
项,我们在该函数中调用InsertMenu函数。
(2)InvokeCommand函数:当用户选定了某个Context Menu Handler登记过的菜单项后,该函数将会被调用,系统将会传给该函数一个指向
LPCMINVOKECOMMANDINFO结构的指针。在该函数中要执行与所选菜单项相对应的操作。
(3)GetCommandString函数:当鼠标指针移到一个上下文相关菜单项上时,在当前窗口的状态条上将会出现与该菜单项相关的帮助信息,此
信息就是系统通过调用该函数获取的。
下面我通过具体的例程来说明编写一个比较完整的上下文菜单程序,这个程序是一个文件操作程序,当安装并注册了外壳扩展的服务器动态连接库之后,当选择一个或者多个文件并单击鼠标右键后,在右键菜单中就会多出一个“执行文件操作”的上下文菜单,点击菜单就会弹出相应的程序执行文件操作。
在整个程序的编写中,外壳扩展的服务器动态连接库是有Delphi4.0编写的,而动态连接库调用的文件操作程序是由vb6编写的。下面首先介绍服务器动态连接库的编写:
服务器动态连接库的工程文件内容如下:
library contextmenu;
uses
ComServ
ContextMenuHandler in ''Unit2.pas'';
// contmenu_TLB in ''contmenu_TLB.pas'';
exports
DllGetClassObject
DllCanUnloadNow
DllRegisterServer
DllUnregisterServer;
{$R *.TLB}
{$R *.RES}
begin
end.
将工程文件保存为contextmenu.dpr。
服务器动态连接库的单位文件内容如下:
unit ContextMenuHandler;
interface
uses Windows
ActiveX
ComObj
ShlObj
Classes;
type
TContextMenu = class(TComObject
IShellExtInit
IContextMenu)
private
FFileName: array[0..MAX_PATH] of Char;
protected
function IShellExtInit.Initialize = SEIInitialize; // Avoid compiler warning
function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult; stdcall;
function QueryContextMenu(Menu: HMENU; indexMenu
idCmdFirst
idCmdLast
uFlags: UINT): HResult; stdcall;
function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
function GetCommandString(idCmd
uType: UINT; pwReserved: PUINT;
pszName: LPSTR; cchMax: UINT): HResult; stdcall;
end;
const
Class_ContextMenu: TGUID = ''{19741013-C829-11D1-8233-0020AF3E97A9}'';
{全局唯一标识符(GUID)是一个16字节(128为)的值,它唯一地标识一个接口(interface)}
var
FileList:TStringList;
Buffer:array[1..1024]of char;
implementation
uses ComServ
SysUtils
ShellApi
Registry
UnitForm;
function TContextMenu.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult;
var
StgMedium: TStgMedium;
FormatEtc: TFormatEtc;
FileNumber
i:Integer;
begin
file://如果lpdobj等于Nil,则本调用失败
if (lpdobj = nil) then begin
Result := E_INVALIDARG;
Exit;
end;
file://首先初始化并清空FileList以添加文件
FileList:=TStringList.Create;
FileList.Clear;
file://初始化剪贴版格式文件
with FormatEtc do begin
cfFormat := CF_HDROP;
ptd := nil;
dwAspect := DVASPECT_CONTENT;
lindex := -1;
tymed := TYMED_HGLOBAL;
end;
Result := lpdobj.GetData(FormatEtc
StgMedium);
if Failed(Result) then Exit;
file://首先查询用户选中的文件的个数
FileNumber := DragQueryFile(StgMedium.hGlobal
$FFFFFFFF
nil
0);
file://循环读取,将所有用户选中的文件保存到FileList