使用Delphi 7 编写一个IE右键菜单项目:自动保存图片

无论是IE中的“图片另存为”还是QQ图片工具条,保存图片的时候都需要选择路径,文件名,然后再按保存。如果是一两张图片这样保存自然无所谓,但是如果长期需要做图片收集还是自己DIY一个菜单吧。

如果你只是想了解用Delphi编写ActiveX或者IE 右键菜单的相关信息,注意每一步下面的Addition,那里有相关主题的更多信息。

正文:

这个菜单实现的功能是:浏览网页时在图片上单击右键,弹出菜单中比平时多一项“自动保存图片”,单击后自动将图片保存到C:\Images\下面,文件名为默认的文件名,如果遇到重名情况,自动在原文件名后添加几个随机生成的字母,然后自动保存。

实现方法简介:

IE右键菜单项 ---------- 修改注册表,添加菜单入口

响应菜单 ---------- VBScript脚本调用ActiveX Object

主体:保存文件 ---------- Delphi ActiveX Library & Automation Object

Step by Step:

1.添加IE右键菜单项

开始菜单,运行,输入regedit,回车,依次展开

HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt

添加一个子键:自动保存图片&Z,修改默认值为:C:\Program Files\PicSaver\PicSaver.htm (这是稍后我们将要编写的脚本),在新建的子键下添加一个REG_DWORD类型的项Contexts,修改值为2。

关闭注册表以保存

此时,新打开的IE窗口在图片上单击右键,已经出现自动保存图片菜单。

Addition:一个子键对应一个菜单项,默认值对应单击菜单时需要激活的脚本文件,Contexts是一个可选项。设置为不同的值表示仅在特定内容上单击右键才会出现这个项目。

Context IE 6.0典型值:

Context Value

---------------------------

Default 0x1

Images 0x2

Controls 0x4

Tables 0x8

Text selection 0x10

Anchor 0x20

添加菜单项更多信息参见MSDN:http://msdn2.microsoft.com/en-us/library/Aa753589.aspx

2.编写VBScript脚本

新建一个空文件,输入以下内容:

<script language="VBScript">

set srcEvent = external.menuArguments.event

set img = external.menuArguments.document.elementFromPoint(srcEvent.clientX, srcEvent.clientY)

set ps = CreateObject("PicSaver.AutoSave")

call ps.SaveImage(img.href)

set ps = nothing

</script>

保存为C:\Program Files\PicSaver\PicSaver.htm

Addition: 这个脚本参考了FlashGet下载软件的脚本。其中external.menuArguments可以获得对应的页面内容, elementFromPoint方法返回一个object(事实上就是那个单击的图片),img.href属性取得object对应的URL地址。

PicSaver.AutoSave是下面将要编写的ActiveX (Automation Object),调用了对象的SaveImage方法。

脚本中使用HTML 的参考资料比较少,只有MSDN的内容

http://msdn2.microsoft.com/en-us/library/ms533050.aspx

这个信息是很全的,但是检索很不方便。

脚本中使用Automation Object的方法与使用Scripting.FileSystemObject的方法完全相同,创建对象,访问属性(properties)和方法(methods)都很简单。

Scripting.FileSystemObject是内置的处理文件的object,Scripting.FileSystemObject的使用方法见:http://msdn2.microsoft.com/en-us/library/6kxy1a51.aspx,一般的VBScript教程里面都有详细说明。

3.编写Automation Object: PicSaver.AutoSave

这是最重要的部分。网上范例用.Net来编写的比较多,本例中我使用Delphi来编写。

选择用Delphi而不用C++, .Net的原因是:我现在用的机器上没有Virtual Studio,只有Delphi 7。寒。

进入正题,先打开Delphi7,File->close all,工具栏,New Item,选择ActiveX->ActiveX Library,Save,Project name为PicSaver。

New Item,选择ActiveX->Automation Object,CoClass Name为AutoSave,其余项目保留默认值。

弹出PicSaver.tlb窗口(如果没有看到,View->Type Library可以打开这个窗口),Save,Unit name为AutoSave。

在左侧可以看到IAutoSave(接口),右键单击,选择New->Method,取名字为SaveImage,单击Parameters选项卡修改参数,Name:urlstr,Type:BSTR, 单击窗口上的Refresh Implementation。Save。

关闭PicSaver.tlb窗口,弹出代码编辑器。可以看到Delphi已经自动生成了刚才定义的方法:

procedure SaveImage(const urlstr: WideString); safecall;

接下来是Coding,没有太多可说的,附上我的源代码。

<---------------------------------Delphi Code---------------------------------->

unit AutoSave;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses

ComObj, ActiveX, PicSaver_TLB, StdVcl;

type

TAutoSave = class(TAutoObject, IAutoSave)

protected

procedure SaveImage(const urlstr: WideString); safecall;

end;

implementation

uses ComServ, UrlMon, SysUtils, Dialogs, StrUtils;

function DownloadFile(SourceFile, DestFile: string): Boolean;

begin

try

Result := UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0, nil) = 0;

except

Result := False;

end;

end;

function rPos(const substr, str: AnsiString): Integer;

begin

Result := length(str) - pos(AnsiReverseString(substr), AnsiReverseString(str)) + 1;

end;

function rename(filename: string): string;

var

i, p: integer;

randomchar: char;

name, ext: string;

begin

p := rpos('.', filename);

name := copy(filename, 1, p - 1);

ext := copy(filename, p + 1, length(filename) - p);

result := name;

for i := 1 to 5 do

begin

randomchar := Chr(random(300) mod 26 + 65);

result := result + randomchar;

end;

result := result + '.' + ext;

end;

procedure TAutoSave.SaveImage(const urlstr: WideString);

const

PATH = 'C:\Images';

var

url, DestFile, name, rname: string;

len, p: integer;

begin

url := urlstr;

//parse file name and get destfile name

len := length(url);

p := rpos('/', url);

name := copy(url, p + 1, len - p);

rname := name;

while fileexists(PATH + rname) do

begin

rname := rename(name);

end;

name := rname;

DestFile := PATH + name;

if DownloadFile(url, DestFile) then

begin

//ShowMessage('保存成功!');

end

else

begin

ShowMessage('!!!!保存不成功!!!!');

end;

end;

initialization

TAutoObjectFactory.Create(ComServer, TAutoSave, Class_AutoSave,

ciMultiInstance, tmApartment);

end.

<-----------------------------End of Delphi Code-------------------------------->

Save, Compile, Build。

菜单:Run->Register ActiveX Server,弹出注册成功的提示。

OK,整个工程完成。

Addition: Delphi作为一款强大的IDE早已被众多程序员肯定。但是这次是我使用Delphi的最糟糕的经历。

因为“编写一个VBScript脚本里可以调用的object”相关的文档太难找了,开始的时候我选择了COM Object,编写一点问题都没有。但是VBScript CreateObject之后返回值根本不包含对象的引用。然后看到网上有很多例子都是使用ActiveX Control(控件),但是Delphi里面都是需要VCL Component来转换或者创建Active Form来实现,但是我需要的功能不是一个可视组件,只是需要一个方法和接口。之后又看到一些软件使用了BHO(Browser Helper Object),那个可以在页面加载时就开始运行,获取事件响应。BHO 也不符合我的要求。COM+好像与服务有关系,没有考虑。剩下的就只有Automation Object了,试一下居然OK了。

还有值得注意的是字符串参数一定要选BSTR,不能用LPSTR。如果选LPSTR,脚本运行的时候会出错,提示不支持的对象类型。

结论:右键菜单脚本调用object在Delphi中一定要选择Automation Object

4.由于没有制作Setup安装程式,所以使用上需要注意:

确保C:\Images存在

Delphi 提示ActiveX DLL注册成功

脚本文件存在,位置与注册表对应项一致