用delphi创建一个外壳扩展(Shell Extension)程序的基本步骤如下:

(1) 创建一个 ActiveX Library 工程,命名为“CloudUpload“
(2) 创建一个新的自动化对象(Automation Object)。 命名为“ TCloudUploadContext ”

TCloudUploadContext 类必须实现两个接口即:IShellExtInitIContextMenu
这样就可以在Windows Explorer 中集成该上下文菜单(Context Menu)。

{ IShellExtInit Methods }
{ Initialize the context menu if a files was selected}
function IShellExtInit.Initialize = ShellExtInitialize;
function ShellExtInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult; stdcall;

{ IContextMenu Methods }
{ Initializes the context menu and it decides which items appear in it,
based on the flags you pass }
function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,
uFlags: UINT): HResult; stdcall;

{ Execute the command, which will be the upload to Amazon or Azure}
function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;
{ Set help string on the Explorer status bar when the menu item is selected }
function GetCommandString(idCmd: UINT_PTR; uFlags: UINT; pwReserved: PUINT;
pszName: LPSTR; cchMax: UINT): HResult; stdcall;

ShellExtInitialize 定义了是否在 Windows Explorer 中显示上下文菜单(Context Menu)。
在该例子中,上下文菜单(Context Menu)仅当一个文件被选中的时候才显示出来,否则不会显示。
在一文件被选中时, FFileName 变量将接收该文件的文件名。

function TCloudUploadContextMenu.ShellExtInitialize(pidlFolder: PItemIDList;
lpdobj: IDataObject; hKeyProgID: HKEY): HResult;
var
DataFormat: TFormatEtc;
StrgMedium: TStgMedium;
Buffer: array [0 .. MAX_PATH] of Char;
begin
Result := E_FAIL;

{ Check if an object was defined }
if lpdobj = nil then
Exit;

{ Prepare to get information about the object }
DataFormat.cfFormat := CF_HDROP;
DataFormat.ptd := nil;
DataFormat.dwAspect := DVASPECT_CONTENT;
DataFormat.lindex := -1;
DataFormat.tymed := TYMED_HGLOBAL;

if lpdobj.GetData(DataFormat, StrgMedium) <> S_OK then
Exit;

{ The implementation now support only one file }
if DragQueryFile(StrgMedium.hGlobal, $FFFFFFFF, nil, 0) = 1 then
begin
SetLength(FFileName, MAX_PATH);
DragQueryFile(StrgMedium.hGlobal, 0, @Buffer, SizeOf(Buffer));
FFileName := Buffer;
Result := NOERROR;
end
else
begin
// Don't show the Menu if more then one file was selected
FFileName := EmptyStr;
Result := E_FAIL;
end;

{ http://msdn.microsoft.com/en-us/library/ms693491(v=vs.85).aspx }
ReleaseStgMedium(StrgMedium);

end;

在上下文件菜单句柄(context menu handler)在IShellExtInit接口中被初始化之后,
Windows系统使用 IContextMenu 接口去调用(call)上下文件菜单句柄中的其他方法。
在这种情形下,它将调用(call) QueryContextMenu, GetCommandStringInvokeCommand

上下文件菜单选项(包括 Amazon S3Microsoft Azure )将通过 QueryContextMenu 方法被创建。

function TCloudUploadContextMenu.QueryContextMenu(Menu: HMENU;
indexMenu, idCmdFirst, idCmdLast, uFlags: UINT): HResult;
var
CloudMenuItem: TMenuItemInfo;
MenuCaption: String;
SubMenu: HMENU;
uId: UINT;
begin
{ only adding one menu CloudMenuItem, so generate the result code accordingly }
Result := MakeResult(SEVERITY_SUCCESS, 0, 3);

{ store the menu CloudMenuItem index }
FMenuItemIndex := indexMenu;

{ specify what the menu says, depending on where it was spawned }
if (uFlags = CMF_NORMAL) then // from the desktop
MenuCaption := 'Send file from Desktop to the Cloud'
else if (uFlags and CMF_VERBSONLY) = CMF_VERBSONLY then // from a shortcut
MenuCaption := 'Send file from Shourtcut to the Cloud'
else if (uFlags and CMF_EXPLORE) = CMF_EXPLORE then // from explorer
MenuCaption := 'Send file from Explorer to the Cloud'
else
{ fail for any other value }
Result := E_FAIL;

if Result <> E_FAIL then
begin

SubMenu := CreatePopupMenu;

uId := idCmdFirst;
InsertMenu(SubMenu, AmazonIndex, MF_BYPOSITION, uId, TClouds[AmazonIndex]);

Inc(uId);
InsertMenu(SubMenu, AzureIndex, MF_BYPOSITION, uId, TClouds[AzureIndex]);

FillChar(CloudMenuItem, SizeOf(TMenuItemInfo), #0);
CloudMenuItem.cbSize := SizeOf(TMenuItemInfo);
CloudMenuItem.fMask := MIIM_SUBMENU or MIIM_STRING or MIIM_ID;
CloudMenuItem.fType := MFT_STRING;
CloudMenuItem.wID := FMenuItemIndex;
CloudMenuItem.hSubMenu := SubMenu;
CloudMenuItem.dwTypeData := PWideChar(MenuCaption);
CloudMenuItem.cch := Length(MenuCaption);

InsertMenuItem(Menu, indexMenu, True, CloudMenuItem);
end;
end;

在 Windows Explorer 中你用鼠标滑过该云菜单项(Cloud menu items )时会在状态栏中显示出瞬时帮助(提示)信息。 这个提示信息定义并在GetCommandString 方法中实现。

function TCloudUploadContextMenu.GetCommandString(idCmd: UINT_PTR; uFlags: UINT;

pwReserved: PUINT; pszName: LPSTR; cchMax: UINT): HResult;
begin
Result := E_INVALIDARG;

{ Set help string on the Explorer status bar when the menu item is selected }
if (idCmd in [AmazonIndex, AzureIndex]) and (uFlags = GCS_HELPTEXT) then
begin
StrLCopy(PWideChar(pszName), PWideChar('Copy the selected file to ' +
TClouds[idCmd]), cchMax);
Result := NOERROR;
end;

end;

当用户点击了一个云菜单项(Cloud menu items)中某一项时,InvokeCommand 方法将被调用(call)并且启动一个上传被选中的文件到目标云(Cloud)上的进程。
这样,我们就已经有了该文件名,基于 lpici 这个参数,我们能够分辨用户点击了哪个菜单项。

function TCloudUploadContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
var
Item: Word;
begin
Result := E_FAIL;

if HiWord(Integer(lpici.lpVerb)) <> 0 then
Exit;

{ if the index matches the index for the menu, show the cloud options }
Item := LoWord(Integer(lpici.lpVerb));

if Item in [AmazonIndex, AzureIndex] then
begin
try
Upload(lpici.HWND, Item, FFileName);
except
on E: Exception do
MessageBox(lpici.hwnd, PWideChar(E.Message), 'Cloud Upload', MB_ICONERROR);

end;
Result := NOERROR;
end;

end;

为确保当 CloudUpload 被加载时,该 COM对象(COM object)被创建,有必要创建一个类工厂的一个实例,特别是要创建一个该外壳扩展对象(the shell extension object)的一个实例,该工厂实例将在 initialization代码段中被创建。

initialization
TCloudUploadObjectFactory.Create(ComServer, TCloudUploadContextMenu, CLASS_CloudUploadContextMenu, ciMultiInstance, tmApartment);
end.

由于该类工厂将负责注册或反注册该DLL,当你使用 regsvr32.exe 的时候,ApproveShellExtensionUpdateRegistry 两个方法将被调用(invoked)。

注册 CloudUpload 外壳扩展应用
以管理员身份运行cmd

注册命令:
regsvr32 <PATH WHERE IS LOCATED THE DLL>CloudUpload.dll

反注册命令:
regsvr32 <PATH WHERE IS LOCATED THE DLL>CloudUpload.dll /u

原文地址:http://www.andreanolanusse.com/en/shell-extension-for-windows-32-bit-and-64-bit-with-delphi-xe2/

Delphi编写Shell扩展的更多相关文章

  1. 利用Delphi编写IE扩展

    就是如何使IE扩展组件可以响应事件.    在自己的程序中使用过WebBrowser控件的朋友都知道,WebBrowser控件定义了诸如BeforeNavigate.DownloadComplete ...

  2. 启动VNC Shell扩展

    下载source files - 18.3 Kb Introduction 我们使用RealVNC来远程控制我们的网络中的pc机,VNC是一个伟大的产品,但如果不记住计算机名称,它可以是乏味的,在网络 ...

  3. Windows Shell编程之如何编写为文件对象弹出信息框的Shell扩展

    有关COM编程资料 转载:http://www.cnblogs.com/lzjsky/archive/2010/11/22/1884702.html 活动桌面引入一项新特性, 当你在某些特定对象上旋停 ...

  4. Linux下高效编写Shell——shell特殊字符汇总

    Linux下无论如何都是要用到shell命令的,在Shell的实际使用中,有编程经验的很容易上手,但稍微有难度的是shell里面的那些个符号,各种特殊的符号在我们编写Shell脚本的时候如果能够用的好 ...

  5. 利用Delphi编写Socket通信程序

    一.Delphi与Socket 计算机网络是由一系列网络通信协议组成的,其中的核心协议是传输层的TCP/IP和UDP协议.TCP是面向连接的,通信双方保持一条通路,好比目前的电话线,使用telnet登 ...

  6. python编写shell脚本详细讲解

    python编写shell脚本详细讲解 那,python可以做shell脚本吗? 首先介绍一个函数: os.system(command) 这个函数可以调用shell运行命令行command并且返回它 ...

  7. 使用golang 编写postgresql 扩展

      postgresql 的扩展可以帮助我们做好多强大的事情,支持的开发语言有lua.perl.java.js.c 社区有人开发了一个可以基于golang开发pg 扩展的项目,使用起来很方便,同时为我 ...

  8. 编写Postgres扩展之五:代码组织和版本控制

    原文:http://big-elephants.com/2015-11/writing-postgres-extensions-part-v/ 编译:Tacey Wong 在关于编写Postgres扩 ...

  9. 编写Postgres扩展之四:测试

    原文:http://big-elephants.com/2015-11/writing-postgres-extensions-part-iv/ 编译:http://big-elephants.com ...

随机推荐

  1. sas share 备忘录

    options comamid=tcp;libname payable 'E:\shouen';proc server authenticate=optional id=share1 msgnumbe ...

  2. 02-zip文件打包

    package com.day1; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStre ...

  3. 关于Vue实例的生命周期created和mounted的区别

    什么是生命周期 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.卸载等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实例从创建到销毁的过 ...

  4. Linux下单独编译安装PHP扩展包

    首先进入PHP源码目录,比如这个: root@vultr:~/php-/ext/soap# 运行下PHP目录下的phpize,接着就可以和普通代码一样,配置,编译,安装了(注意:有些库可能可以配置参数 ...

  5. es6 import export 引入导出变量方式

    var testdata='sdfkshdf'; //export testdata;//err export {testdata as ms}; export var firstName = 'Mi ...

  6. Linux下使用OTL操作mysql数据库

    首先重点推荐介绍otl介绍及用法的文章:http://www.cnblogs.com/fnlingnzb-learner/p/5835560.html 一.编写代码 注:以下代码来自OTL示例,略有改 ...

  7. CS229 1 .线性回归与特征归一化(feature scaling)

    线性回归是一种回归分析技术,回归分析本质上就是一个函数估计的问题(函数估计包括参数估计和非参数估计),就是找出因变量和自变量之间的因果关系.回归分析的因变量是应该是连续变量,若因变量为离散变量,则问题 ...

  8. 20165205 2017-2018-2 《Java程序设计》实验二 Java面向对象程序设计

    20165205 2016-2017-2 <Java程序设计>实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UM ...

  9. fabric-network_setup.sh安装脚本分析

    在进行镜像安装前,提供了一个sample脚本的下载,可以使用该脚本进行容器的启停.这里对该脚本进行分析. fabric/release/linux-amd64/network_setup.sh 脚本提 ...

  10. Linux 搜索日志信息

    在工作中我们经常要通过日志来查找问题,但有时候日志太多又不知道日志什么时候打印的,这时我们可以通过一下方法来查找: 1.进入到日志文件存放的目录下 2.grep  关键字  *    例如要查找多有有 ...