无论是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注册成功
脚本文件存在,位置与注册表对应项一致