`
weiyinchao88
  • 浏览: 1187380 次
文章分类
社区版块
存档分类
最新评论

IE浏览器 自定义地址协议的实现

 
阅读更多


关键字:IE插件,shell接口编程,自定义IE协议,VC2003ATL实现COM

浏览QQ空间的时候发现,只要在IE地址中输入象一下这种形式的地址,
tencent://Message/?Uin=251464630&websiteName=qzone.qq.com&Menu=yes
就会弹出给251464630发送信息的对话框,也就是说QQ对IE地址栏的东西做了监控。而且可以发现输入地址确定之后他就启动了timwp.exe这

个程序。在PPlive也有实现类似的功能,只要你电脑上安装了PPlive这个程序,在IE地址栏中输入
synacast://09jN1+TK3K3nodzJoaLOmqeS1KGhoKOZoqGcltid1qeZy9ec1dbRy9ue1aKe5pzI2dSpna+VpJbayuPKrbOvvcySpRMUHl01NaScmcEIGRMUNh4vQz

NmNR8IGaqemauXq7OvvcySpZiekrCWoKOfj+LU162emaiToaGgl6eToaalo66VoKCmoaaVoJbX2LPa1ODgo6WU057TmtqT3tXgo66VoKCn3trV5KqbmNuT16HQl+T

K5KqkmaaVq+XQ2eqfn5/Nl92W1J7azuqfqKCcmbHZ0+Dgo6WU1J7TmtqT3tXgo66Vq+TP2eqfn5/Ol92W1J7azuqfqKCn3dnV5KqbmNyT16HQl+TK5KqkmZzZ2NXZ

zrPN5ePg3N7G4tWSwtvR3N/judfM1bnQpqeXpZavyurG3N/Tstqip6k=

然后确定,就会弹出播放CCTV5的窗口。很有意思的一种功能,竟然这么多程序都用到了,我也就找了一下,找到了一下实现方法。

方法一:也就是QQ和PPlive所采用的方法,在注册表里面添加两种类型的注册。

QQ的:

WindowsRegistryEditorVersion5.00

[HKEY_CLASSES_ROOT/TENCENT]
@="TencentProtocol"
"URLProtocol"="C://ProgramFiles//Tencent//QQ//Timwp.exe"

[HKEY_CLASSES_ROOT/TENCENT/DefaultIcon]
@="C://ProgramFiles//Tencent//QQ//Timwp.exe,1"

[HKEY_CLASSES_ROOT/TENCENT/shell]

[HKEY_CLASSES_ROOT/TENCENT/shell/open]

[HKEY_CLASSES_ROOT/TENCENT/shell/open/command]
@="/"C://ProgramFiles//Tencent//QQ//Timwp.exe/"/"%1/""

PPlive的:

WindowsRegistryEditorVersion5.00

[HKEY_CLASSES_ROOT/Synacast]
@="URL:synacastProtocol"
"Version"="1.5.38"
"URLProtocol"=""

[HKEY_CLASSES_ROOT/Synacast/DefaultIcon]
@="C://ProgramFiles//PPLive//PPLive.exe"

[HKEY_CLASSES_ROOT/Synacast/Shell]

[HKEY_CLASSES_ROOT/Synacast/Shell/Open]

[HKEY_CLASSES_ROOT/Synacast/Shell/Open/Command]
@="C://ProgramFiles//PPLive//PPLive.exe/"%1/""


通过多方查找终于发现是注册表这两项在起作用,原来只要在注册表里象添加文件扩展名一样,添加两个Synacast和TENCENT扩展名来,IE就会

自动查找到这里来调用相应的程序。IE果然和windows系统内核整合起来了!原来注册表扩展名项还有这种作用,自己见识太少了,这种方法实

现IE地址的自定义估计是最简单的了。


方法二:一开始不知道方法一的时候,在网上找了很多可以实现这种功能的代码,采用BHO(BrowserHelperObject,浏览器辅助对象)或者

IURLSearchHook接口来做到。也就是通常所说的IE插件了,我这里统称为方法二。如果不知道什么叫做BHO和IURLSearchHook的就去搜索一下

吧,最近流氓插件很火,所以这个技术也有多人提到,借助IURLSearchHook还可以实现中文实名上网等功能,不过那些臭名昭著的流氓软件可

都不是这样子坐的他更多的精力是放到防止别人卸载那边去了。
因为我没有编写过ATL或者COM方面的程序,所以也就借着这个机会写了个IURLSearchHook的实现,以后碰到IE插件编程,ATL编程,COM编

程,Shell接口编程的时候也好能够玩一玩,好像shell接口编程还是有很多有意思东西的。
这个是MSDN上IURLSearchHook接口的说明:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/ifaces/iurlsearchhook/iurlsearchhook.asp

下面这个是MSDN上shell接口编程的说明:http://msdn2.microsoft.com/en-us/library/ms631201.aspx
这个是ATL编程的http://msdn2.microsoft.com/zh-cn/library/65t81w8a(vs.80).aspx
有一片不错的来之VCbase的文章说得是“ATL实现定制的IE浏览器栏、工具栏和桌面工具栏”
http://www.vckbase.com/document/viewdoc/?id=1457

简单的说,IURLSearchHook被浏览器用来转换一个未知的URL协议地址,当浏览器企图去打开一个未知协议的URL地址时,浏览器首先尝试从这个地址得到当前的协议,如果不成功,浏览器将寻找系统里所有注册为“URLSearchHook”(资源搜索钩子,USH)的对象并把这个IE不能理解的地址发送过去,如果某个USH对象“认识”这个地址,它就返回一个特定的标识告诉IE它知道怎么打开这个地址,然后IE就根据约定的方法调用它,最终打开这个地址。其实USH对象并不陌生,我们一些偷懒的用户就经常为了省事而不输入“http://”,但是IE最终还是能认出并打开某个地址,就是USH的功劳。当然通过BHO的GetSite方法也可以做到同样的事情,不过IURLSearchHook简单一些,只有一个Translate方法,我技术不行所以专挑简单的^_^

以下是实现代码:
使用VC2003新建一个名字为UrlSearchHook的ATL工程

进入工程之后在类视图中右击工程名字-》添加类—》添加一个叫WidebrightBlog的“ATL简单对象”

还是类视图中右击WidebrightBlog类——》添加->实现接口,利用向导找到shell接口中的IURLSearchHook后添加实现。


向导里面列了很多,不过我是没找到啦,所以之后手工添加接口实现了,以下全部代码,红色的是自己写的。

//WidebrightBlog.h:CWidebrightBlog的声明

#pragmaonce
#include"resource.h"//主符号

#include<comdef.h>

#include<shlobj.h>


//IWidebrightBlog
[
object,
uuid("1F0B2F61-221A-456C-A8E1-E0E01796E482"),
dual,helpstring("IWidebrightBlog接口"),
pointer_default(unique)
]
__interfaceIWidebrightBlog:IDispatch
{
};

//CWidebrightBlog

[
coclass,
threading("apartment"),
vi_progid("UrlSearchHook.WidebrightBlog"),
progid("UrlSearchHook.WidebrightBlog.1"),
version(1.0),
uuid("44AA49F1-7E20-472E-A5A4-08D3233D9132"),
helpstring("WidebrightBlogClass")
]
classATL_NO_VTABLECWidebrightBlog:
publicIWidebrightBlog,
publicIURLSearchHook
{
public:
CWidebrightBlog()
{
//MessageBox(NULL,"在CWidebrightBlog()","widebright",MB_OK);
}

DECLARE_PROTECT_FINAL_CONSTRUCT()

//组件接口映射部分,该部分映射主要是告诉QueryInterface能返回哪些接口给外部

BEGIN_COM_MAP(CWidebrightBlog)
COM_INTERFACE_ENTRY(IWidebrightBlog)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IURLSearchHook)
END_COM_MAP()


HRESULTFinalConstruct()
{
returnS_OK;
}

voidFinalRelease()
{
}

public:

STDMETHODIMPTranslate(LPWSTRlpwszSearchURL,DWORDcchBufferSize)
{
//MessageBox(NULL,"在Translate函数中了","widebright",MB_OK);

if(wcsncmp(L"widebright",lpwszSearchURL,10)==0)
{
//MessageBox(NULL,"找到了","widebright",MB_OK);
wcscpy(lpwszSearchURL,L"http://hi.baidu.com/widebright");
returnS_OK;
}
returnE_FAIL;//没有修改lpwszSearchURL
returnS_FALSE;//修改了lpwszSearchURL的,但还需要继续处理

}

intMyFunction(void)//这个是自己利用向导生成Method的函数,想试一下COM接口,没什么用的,根本程序无关。
{
return0;
}
};

不过编译一下,有错,说是IURLSearchHook接口GUID没定义,明显是有这个接口的,在MSDN里面没有什么说明,最后在CSDN上找到一张帖子
,说是VC2003里面和VC6的ATL不同,在VC6里面上面代码是可以通过的,但在VC2003以后版本就不行了。这是引用帖子中原话“Therearetwo

<comdef.h>headerfilesinVC.NET,oneinVc7/includeandtheotherinVc7/PlatformSDK/include.Theformersplitsoffthe

smartpointertypedefsintocomdefsp.h,anditdoesn'tincludeIContextMenu.Thelatterdoes.Youcantryto#includethe

PlatformSDKheaderdirectly,changeyourINCLUDEpathorder,orsupplythemissingtypedefyourself,e.g.
struct__declspec(uuid("000214e4-0000-0000-c000-000000000046"))
IContextMenu;

_COM_SMARTPTR_TYPEDEF(IContextMenu,__uuidof(IContextMenu));”

我查看了VC目录下的两个文件也确实如此,所以手工添加了一下Include路径确保#include<comdef.h>包含的是Platform中的那个comdef.h就行了。在UrlSearchHook工程-“工程属性”-》“C/C++”-》“附加包含目录”属性,增加一个"C:/ProgramFiles/MicrosoftVisualStudio.NET2003/Vc7/PlatformSDK/Include"。

然后再编译就通过了,生成了dll文件,整个代码很简单,就是实现IURLSearchHook接口的Translate函数,BEGIN_COM_MAP和COM_INTERFACE_ENTRY几个ATL宏声明IURLSearchHook接口外部可见,就一些ok了。

不过要让IE知道有这个URLSearchHook扩展,还要修改注册表才行。我手工在HKEY_CURRENT_USER/Software/Microsoft/InternetExplorer/UrlSearchHooks添加了一项REG_SZ类型名字为{44AA49F1-7E20-472E-A5A4-08D3233D9132}的项,其中名字和你生成的dll注册类型对应,在上面代码里也可以看到。注意的是MSDN上说的是HKEY_LOCAL_MACHINE/../..注册表位置,但其他文档说得是HKEY_CURRENT_USER位置,而且我在HKEY_LOCAL_MACHINE下也没看到UrlSearchHooks项,不知道添加在HKEY_LOCAL_MACHINE会不会有效果,不过添加在HKEY_CURRENT_USER/Software/Microsoft/InternetExplorer/UrlSearchHooks会成功就是了。

好了,启动IE7,输入widebright开头的地址,都跳到http://hi.baidu.com/widebright来了,在卡卡上网助手里可见CWidebrightBlogObject地址栏搜索项。


方法三:也是使用IE扩展接口实现,我之所以把它独立处理列为一种方法,是我觉得是一种很使用的价值的功能。我发现电脑里面有的电子书在我升级到IE7后看不了,可能也是这方面有问题。在注册表中都可见到这些Ebook电子书的注册值,可能Ebook也就是这么干的吧。

更多相关内容搜索:协议插件(AsynchronousPluggableProtocols),MIMEFilter

我是在下面这篇文章里面发现这种实现方法的,下面转载:
转贴来互联网,不过文章作者倒是很眼熟,好像是看过他几篇文章了,支持!

IE异步可插入协议扩展
作者陈省

介绍

对于每天都要使用的IE浏览器的人来说,输入www.google.com等网址进行网上冲浪就象呼吸一样自然。大多数情况时,我们可能根本想不起来要在网址前面加上http://来声明要访问的是一个基于http协议的Web网站。所谓网络协议,其实无非就是一组描述如何获取不同资源并进行通讯的行为规则。IE浏览器除了内置了对http协议外,还持ftp和gopher等协议。

从IE4开始,IE允许通过插入式异步协议扩展来扩展它处理协议的功能,人们可以通过自定义的扩展来让IE支持更多的协议,比如一些不是普遍支持的流媒体协议等。此外,我们还可以通过插入式协议扩展让IE可以以HTML文件的形式显示一个数据库中的表。

异步可插入协议的原理

可插入式协议是基于异步的URLMoniker技术的。Moniker最早是从OLE2中引入的概念,当时的Moniker就是一个COM绑定和定位对象,人们可以使用Moniker来定位并加载被保存到文件中的COM组件,实现COM的可持续性,一开始Moniker是基于同步方式实现的。随着网络技术的发展,定位并从网络上获取信息的需求逐渐超过了对本地数据的存取需求,因为网络的通讯通常都是不稳定的,因此需要以异步的方式来实现。为此微软设计了URLmoniker对象来提供网络信息下载过程的一个统一接口,基于URL来访问网络资源的Moniker演变成了以异步方式实现的Moniker。
IE的URLmoniker是在urlmon.dll动态连接库中实现的。当urlmon.dll处理http,ftp,Gopher等内置协议的访问时,它把访问请求转发给内部的一个COM组件来处理,该COM组件使用WinInet函数来完成实际的处理工作。对于非内置的协议,urlmon.dll则把请求转发给特定的可插入协议扩展进行处理,比如说mailto:协议。

一个典型的异步可插入协议(APP)的主要工作的就是接收一个非IE内置的UrlURL协议字符串,对字符串进行解析,分析字符串的元素,并根据协议访问相应的系统或者网络资源,并将网络资源的内容输出到浏览器。

一个自定义的电子书可插入协议的实现

我平时业余时间喜欢上网上找一些娱乐小说和技术书籍来看,其中有一些小说采用的是付费方式才能看既然是付费的小说,自然会提供一些加密的方式,避免盗版书在网上的传播。

接下来,我想写一个程序对一些Html文件进行加密,只有用户在浏览器中键入EBook://c:/abc.htm,然后输入口令后,才能看到解密后的Html页面。接下来,就看如何使用APP来实现这样一个可插入协议。

创建COM组件

首先,新建一个ActiveXLibrary项目,保存为IEProtocol.dpr,然后新建一个名为TIEEncryptAPP的COM组件,保存为CIEProtocol.pas文件。一个APP组件至少要实现IInternetProtocol接口(该接口定义在urlmon.pas单元中),又由于IInternetProtocol接口派生自IInternetProtocolRoot,所以我们还需要实现IInternetProtocolRoot接口。下面是实现了IInternetProtocol接口的TIEEncryptAPP类的定义:

type
TIEEncryptAPP=class(TComObject,IInternetProtocol)
protected
//IInternetProtocolRoot接口定义
functionStart(szUrl:LPCWSTR;OIProtSink:IInternetProtocolSink;
OIBindInfo:IInternetBindInfo;grfPI,dwReserved:DWORD):HResult;
stdcall;
functionContinue(constProtocolData:TProtocolData):HResult;stdcall;
functionAbort(hrReason:HResult;dwOptions:DWORD):HResult;stdcall;
functionTerminate(dwOptions:DWORD):HResult;stdcall;
functionSuspend:HResult;stdcall;
functionResume:HResult;stdcall;
//IInternetProtocol接口定义
functionRead(pv:Pointer;cb:ULONG;outcbRead:ULONG):HResult;stdcall;
functionSeek(dlibMove:LARGE_INTEGER;dwOrigin:DWORD;outlibNewPosition:
ULARGE_INTEGER):HResult;stdcall;
functionLockRequest(dwOptions:DWORD):HResult;stdcall;
functionUnlockRequest:HResult;stdcall;
end;

其中IInternetProtocolRoot接口的方法意义如下:

Abort
停止一个正在进行的资源下载过程

Continue
允许协议扩展继续进行进行资源数据下载过程。

Resume
未来扩充需要,暂时未实现。

Start
启动同该协议相关的资源下载过程。

Suspend
未来扩充需要,暂时未实现

Terminate
结束下载过程,释放扩展分配的资源。

而IInternetProtocol协议的方法定义如下:

LockRequest
锁定资源下载请求,这时IInternetProtocolRoot接口的Terminate方法将允许被调用,与此同时未下载完的数据仍然可以被读取。

Read
浏览器调用这个方法从协议扩展获得相应的数据。

Seek
移动读取数据的位置。

UnlockRequest
释放请求锁定

对于电子图书这样一个简单的协议扩展来说,我们只需要实现Start方法来启动下载过程,并通过Read方法向浏览器返回解密后的电子图书的数据就可以了。其它的方法只要简单的返回请求结果,而无须做任何的操作:

functionTIEEncryptAPP.Abort(hrReason:HResult;dwOptions:DWORD):HResult;
begin
Result:=Inet_E_Invalid_Request;
end;

functionTIEEncryptAPP.Continue(
constProtocolData:TProtocolData):HResult;
begin
Result:=Inet_E_Invalid_Request;
end;

functionTIEEncryptAPP.LockRequest(dwOptions:DWORD):HResult;
begin
Result:=S_OK;
end;

functionTIEEncryptAPP.Resume:HResult;
begin
Result:=Inet_E_Invalid_Request;
end;

functionTIEEncryptAPP.Seek(dlibMove:LARGE_INTEGER;dwOrigin:DWORD;
outlibNewPosition:ULARGE_INTEGER):HResult;
begin
Result:=E_Fail;
end;

functionTIEEncryptAPP.Suspend:HResult;
begin
Result:=Inet_E_Invalid_Request;
end;

functionTIEEncryptAPP.Terminate(dwOptions:DWORD):HResult;
begin
Result:=S_OK;
end;

functionTIEEncryptAPP.UnlockRequest:HResult;
begin
Result:=S_OK;
end;

启动协议处理

首先来看如何启动协议处理,当我们在浏览器中输入EBook://c:/ebook.htm字符串想要浏览加密的页面文件时,IE会找到EBook的扩展协议,然后调用协议的Start方法来启动协议处理过程:

threadvar
ResultHTML:array[0..64*1024-1]ofChar;{64kB}
CurrPos:Integer;
BytesLeft:Integer;
ProtSink:IInternetProtocolSink;

functionTIEEncryptAPP.Start(szUrl:LPCWSTR;
OIProtSink:IInternetProtocolSink;OIBindInfo:IInternetBindInfo;grfPI,
dwReserved:DWORD):HResult;
Const
ErrorHTML='<HTML><BODYBGCOLOR="#FFFFFF">'#13+
'<H2>浏览电子书%s时发生错误</H2>'#13+
'<P><I>%s</I></P>'#13+
'</BODY></HTML>';
var
S:string;
begin
S:=WideCharToString(szURL);
{EBook://}
Delete(S,1,8);
//去掉后面/符号
SetLength(S,Length(S)-1);
S:=HTTPDecode(S);
ifFileExists(S)then
begin
//显示密码提示框
ifInputBox('密码','请输入密码','')<>'hubdog'then
S:=Format(ErrorHTML,[S,'无效的密码'])
else
S:=Decrypt(S);
end
else
S:=Format(ErrorHTML,[S,'没有找到文件']);
CurrPos:=0;
BytesLeft:=Length(S);
FillChar(ResultHTML,SizeOf(ResultHTML),0);
StrPCopy(ResultHTML,S);
ProtSink:=OIProtSink;
//数据通知
OIProtSink.ReportData(bscf_LastDataNotification,0,BytesLeft);
//数据可完全获得的通知
OIProtSink.ReportData(bscf_DataFullyAvailable,0,BytesLeft);
Result:=S_OK;
end;

Start方法中有一个szUrl的参数,对应着我们在浏览器中输入的url字符串(注意:IE会在输入的字符串末尾自动加上一个斜杠),为了获得要处理的被加了密的html文件,使用Delete函数先从字符串中删除EBook://8个字符,然后在用SetLength去掉IE添加的斜杠,同时要注意IE传过来的字符串参数是进行Http编码的,所以还要调用HttpApp单元中的HttpDecode来进行解码还原为c:/ebook.htm的文件名字符串。

如果输入的文件存在的话,则提示用户输入密码,如果密码匹配的话,则调用Decrypt函数对文件进行解密并,返回解密后的文本串。如果文件不存在,或者密码不匹配,则生成ErrorHtml返回一个错误描述的HTML页面。关于加密和解密过程,比较简单,我会在后面介绍。

获得解密后的文本后,将文本内容复制到ResultHTML字符串缓冲区中(这里的缓冲区处于简单的考虑,写死成64K)。另外要注意的是这里用的参数都使用ThreadVar来声明,这是因为协议处理过程是一个多线程异步的过程,同一时刻,可能有多个EBook的协议请求在处理中,所以变量都要声明为线程安全的,以避免资源冲突。接下来保存IE通过Start方法传过来的OIProtSink协议处理事件接口(稍后还会用到),然后调用接口的ReportData方法通知IE要获取的数据量为BytesLeft,并通过设定ReportData的grfBSCF参数为LastDataNotification和DataFullyAvailable通知IE,数据已经完全准备好了,这样稍后IE就会调用扩展的Read方法来获得解密后的页面数据。

返回解密数据

functionTIEEncryptAPP.Read(pv:Pointer;cb:ULONG;
outcbRead:ULONG):HResult;
var
I:Integer;
begin
if(BytesLeft>0)then
begin
I:=CB;
if(I>BytesLeft)then
I:=BytesLeft;
Move(ResultHTML[CurrPos],PV^,I);
CBRead:=I;
Dec(BytesLeft,I);
Inc(CurrPos,I);
Result:=S_OK;
{通知IE读取更多的数据}
end
else
begin
//数据全部下载完成
Result:=S_False;
ProtSink.ReportResult(S_OK,0,nil);
end;
end;

在Read方法中,IE会传过来一个内部缓冲区的指针pv,同时cb参数表示缓冲区的大小,电子书的数据有可能会很大,而IE的缓冲区不会无限大,因此IE会分多次来读取电子书的数据,我们每次应该尽可能读取cb大小的数据,将其移动到IE的缓冲区内,读取完成后减少BytesLeft的值,同时增加CurrPos的值来记录当前以发送给IE的数据位置,并返回cbRead告诉IE传送的数据到底有多少。如果一次没有返回全部的数据,则返回S_OK通知IE还有没传送完的数据,这样IE就会继续调用Read方法来完成数据下载,最后当所有的数据都处理完毕后,则返回S_False通知IE已经没有要传的数据了,同时,调用事件接口ProtSink的ReportData方法通知IE,协议处理完毕。

加密解密

还是为了简单起见,html页面的加密非常简单,我使用XOR加密,这样的好处是,处理简单。因为XOR加密和解密是一个可逆过程,加密和解密使用同一个函数就可以完成了。下面是加密和解密字符串类:

type
//加密字符串类
TEncryptStrings=class(TStringList)
public
procedureSaveToStream(Stream:TStream);override;
end;

//解密字符串类
TDecryptStrings=class(TStringList)
public
procedureLoadFromStream(Stream:TStream);override;
end;

implementation

//用xor算法进行加密

procedureEncodeStream(Input,Output:TStream);
var
InBuf:array[0..1023]ofbyte;
BufPtr:PChar;
I,BytesRead:Integer;
begin
Assert(Assigned(Input),'无效的流指针');
//必须重新设置流指针位置
Input.Position:=0;
Output.Position:=0;
repeat
BytesRead:=Input.Read(InBuf,SizeOf(InBuf));
I:=0;
whileI<BytesReaddo
begin
InBuf[I]:=InBuf[I]xor8;
Inc(I);
end;
OutPut.Write(InBuf,BytesRead);
untilBytesRead=0;
Input.Position:=0;
Output.Position:=0;
end;

{TDecryptStrings}

procedureTDecryptStrings.LoadFromStream(Stream:TStream);
var
OutStream:TMemoryStream;
begin
//解密
OutStream:=TMemoryStream.Create;
try
EncodeStream(Stream,OutStream);
inheritedLoadFromStream(OutStream);
finally
OutStream.Free;
end;
end;

{TEncryptStrings}

procedureTEncryptStrings.SaveToStream(Stream:TStream);
var
OutStream:TMemoryStream;
begin
inherited;
//加密
OutStream:=TMemoryStream.Create;
try
EncodeStream(Stream,OutStream);
Stream.CopyFrom(OutStream,0);
finally
OutStream.Free;
end;
end;

为了减少编码工作量,我直接从TStringList类派生了两个字符串列表处理类,并重载了LoadFromStream和SaveToStream方法来对流进行加解密处理。加解密处理都是调用的EncodeStream方法来对字符串流进行加密,加密使用每个字符同8进行xor运算。

下面我写了一个程序,可以对html文件进行处理点击Button1,则将文件进行加密处理,点击Button2可以对察看解密后文件的原有内容:

procedureTForm1.Button1Click(Sender:TObject);
var
Strings:TEncryptStrings;
begin
ifnotOpenDialog1.ExecutethenExit;
Strings:=TEncryptStrings.Create;
try
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);
Strings.Text:=Memo1.Text;
Strings.SaveToFile(OpenDialog1.FileName);
Memo2.Lines.LoadFromFile(OpenDialog1.FileName);
finally
Strings.Free;
end;
end;

procedureTForm1.Button2Click(Sender:TObject);
var
Strings:TDecryptStrings;
begin
ifnotOpenDialog1.ExecutethenExit;
Strings:=TDecryptStrings.Create;
try
Memo1.Lines.LoadFromFile(OpenDialog1.FileName);
Strings.LoadFromFile(OpenDialog1.FileName);
Memo2.Lines.Text:=Strings.Text;
finally
Strings.Free;
end;
end;

界面如下:

注册扩展

完成了扩展协议后,只剩下注册扩展了,要想注册扩展,需要在注册表的HKEY_CLASSES_ROOT/PROTOCOLS/Handler/下添加EBook关键字,然后在该关键字下添加名为CLSID的字段,设定其值为扩展的Guid,下面是用于注册的类工厂:

type
TIEEncryptAPPFactory=class(TComObjectFactory)
public
procedureUpdateRegistry(Register:Boolean);override;
end;

{TIEEncryptAPPFactory}

procedureTIEEncryptAPPFactory.UpdateRegistry(Register:Boolean);
begin
inherited;
ifRegisterthen
CreateRegKeyValue(HKEY_CLASSES_ROOT,'PROTOCOLS/Handler/EBook','CLSID',
GuidToString(ClassID))
else
DeleteRegKeyValue(HKEY_CLASSES_ROOT,'PROTOCOLS/Handler/EBook','CLSID');
end;

initialization
TIEEncryptAPPFactory.Create(ComServer,TIEEncryptAPP,Class_IEEncryptAPP,
'IEEncryptAPP','',ciMultiInstance,tmApartment);
end.

最后,将本书光盘中的ebook.htm文件放到c:根目录下,注册扩展后,启动IE,输入ebook://c:/ebook.htm,然后在弹出的密码框中输入hubdog,IE就会显示解密后的电子小说,界面示意如下:

临时注册扩展

上面的注册方法可以称为持久注册的方法,一旦注册就总是生效,。IE还提供临时注册的方法,只要编写一个BHO扩展,在BHO加载时,调用TemporyRegister方法进行注册,在IE退出时调用:

var

Factory:IClassFactory;

procedureTemporaryRegister;

begin

CoGetClassObject(Class_IEEncryptAPP,CLSCTX_SERVER,nil,IClassFactory,Factory);

CoInternetGetSession(0,InternetSession,0);

InternetSession.RegisterNameSpace(Factory,Class_IEEncryptAPP,'EBook',0,nil,0);

end;

procedureUnRegister;

begin

InternetSession.UnregisterNameSpace(Factory,'EBook');

end;

这样的好处是,在程序运行时,可以随时解除对扩展协议的支持,而前面的永久注册法必须在解除注册后,重新启动IE才行。缺点是必须通过一个BHO来实现临时注册。

其它的APP

除了上面的协议扩展外,IE还支持NameSpaceHandler以及Mime-Handler两种APP扩展。其中NameSpace扩展是对特定名字空间进行处理的协议扩展,比如如果我们注册一个对名字空间<hubdog>,则当IE处理http://hubdog.csdn.netmailto:hubdog@263.net的URL时,一旦遇到hubdog名字空间,就会调用我们的NameSpaceHandler进行处理,而不管URL是基于http协议的还是ftp等其它协议的都进行处理。从实现的角度来看,NameSpace的实现方法和前面的协议扩展几乎一样,除了注册时要填写的注册表项内容不同而已。

而Mime协议扩展处理的主要是对一些特殊的媒体资源如图片,声音文件进行处理,比如下表是IE默认支持的一些媒体形式。

text/richtext

text/html

audio/x-aiff

audio/basic

audio/wav

image/gif

image/jpeg

如果那天哪天你发明一种新的音乐形式,比如扩展名为.sy,就可以注册一个Mime扩展对.sy文件处理,让IE播放相应的声音。

Mime扩展除了需要支持IInternetProtocol接口外,还必须实现IInternetProtocolSink接口,接口定义如下:

IInternetProtocolSink=interface
['{79eac9e5-baf9-11ce-8c82-00aa004ba90b}']
functionSwitch(constProtocolData:TProtocolData):HResult;stdcall;
functionReportProgress(ulStatusCode:ULONG;szStatusText:LPCWSTR):HResult;stdcall;
functionReportData(grfBSCF:DWORD;ulProgress,ulProgressMax:ULONG):HResult;stdcall;
functionReportResult(hrResult:HResult;dwError:DWORD;szResult:LPCWSTR):HResult;stdcall;
end;

数据通讯方式上来看,Mime扩展同一般的协议扩展差别比较大,通讯的流程是这样的:

1.首先,IE会在遇到相应资源下载请求时,调用扩展的Start方法来启动下载过程。

2.然后IE会调用扩展的ReportProgress方法,告知扩展被下载的数据保存的缓存文件名称。

3.当IE下载完原始数据后,会调用扩展的ReportData方法通知扩展准备对原始数据进行加工处理。

4.这时,扩展需要调用IE提供的IInternetProtocol接口的Read方法来获得原始数据。

5.对原始数据处理后,扩展要调用IE的IInternetProtocolSink接口的ReportData方法通知IE数据处理完毕。

6.最后,IE调用扩展的Read方法获得处理后的数据。

可以看出来同一般协议扩展的纯主动向IE返回数据的方式不同,Mime的数据通讯方式即有被动的接收IE获取的原始数据,也有将处理后的数据返回IE的主动通讯方式。

由于本质上来看,Mime同一般的APP的实现相差不多,所以这里我将不再浪费篇幅来给出Mime扩展的实现实例了。

总结

IE早已经不再是一个单纯意义的Web浏览程序了,通过对IE支持的协议扩充,我们可以将IE变成一个网络开发平台,可以将IE的功能无限延伸。


Trackback:http://tb.blog.csdn.net/TrackBack.aspx?PostId=1376137

分享到:
评论

相关推荐

    Web系统通过EXE文件实现读取客户电脑MAC等硬件信息且兼容非IE浏览器

    对于一般情况来说,我们用得最多的可能是使用ActiveX控件的方法来实现,但此方案只适用于IE浏览器。为了能兼容不同的浏览器,如FireFox等,我们就需要考虑到一种比较通用的方法。此方法我们可以参考“在很多网站中,...

    工单系统 PESCMS Ticket v1.2.23.zip

    IE浏览器不保证兼容 安装使用: 下载并解压程序至您的HTTP运行环境所在目录。 没有配置虚拟主机,则访问Public目录。反之,请将虚拟主机目录配置到Public 根据安装程序填写对应数据,完成软件安装。 快速使用: ...

    vc++ 应用源码包_1

    实现了 清楚internet临时文件、Cookie的清除、游览器地址栏历史地址的清除、清楚表单自动完成历史记录、清楚自动密码历史记录、清除收藏夹中的内容、清除RAS自动拨号历史记录、清除系统临时文件夹、清空回收站、清除...

    人工智能-项目实践-C#-基于C#的支付宝商家版用户账单爬虫.zip

    c 实现原理:利用WinForm的内置浏览器webBrowser访问支付宝,爬取账单信息,通过http协议发送其他服务 实现功能:自动跳转到账单界面、定时(自定义)...使用环境:NETFramework,Version=v4.5 ie浏览器version&gt;=11

    vc++ 应用源码包_2

    实现了 清楚internet临时文件、Cookie的清除、游览器地址栏历史地址的清除、清楚表单自动完成历史记录、清楚自动密码历史记录、清除收藏夹中的内容、清除RAS自动拨号历史记录、清除系统临时文件夹、清空回收站、清除...

    vc++ 应用源码包_6

    实现了 清楚internet临时文件、Cookie的清除、游览器地址栏历史地址的清除、清楚表单自动完成历史记录、清楚自动密码历史记录、清除收藏夹中的内容、清除RAS自动拨号历史记录、清除系统临时文件夹、清空回收站、清除...

    vc++ 应用源码包_5

    实现了 清楚internet临时文件、Cookie的清除、游览器地址栏历史地址的清除、清楚表单自动完成历史记录、清楚自动密码历史记录、清除收藏夹中的内容、清除RAS自动拨号历史记录、清除系统临时文件夹、清空回收站、清除...

    vc++ 应用源码包_3

    实现了 清楚internet临时文件、Cookie的清除、游览器地址栏历史地址的清除、清楚表单自动完成历史记录、清楚自动密码历史记录、清除收藏夹中的内容、清除RAS自动拨号历史记录、清除系统临时文件夹、清空回收站、清除...

    EB8000的使用教程

    只要任何有网络的地方,在IE浏览器里面输入需 要的IP地址和密码,即可监视现场的HMI和机器的运行情况 16、支持视频播放功能(MT8000X系列机器支持此功能)。只要您录入需要的视频文件并在 HMI上来播放,让操作人员...

    宏天影像采集系统演示 Ver3.16.123(2013-08)

    将IE浏览器的“Internet选项 -&gt; 安全 -&gt; 本地Intranet -&gt; 自定义级别”中,启用“对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本”。 3、在IE浏览器中打开“宏天采集控件演示.html”文件,在IE提示下选择...

    vc++ 开发实例源码包

    实现了 清楚internet临时文件、Cookie的清除、游览器地址栏历史地址的清除、清楚表单自动完成历史记录、清楚自动密码历史记录、清除收藏夹中的内容、清除RAS自动拨号历史记录、清除系统临时文件夹、清空回收站、清除...

    基于LabVIEW的ROV上位机控制软件

    主要功能:控制机器人、传感器数据显示、摄像头图像显示(图像显示为网页调用形式,需要保证在IE浏览器(谷歌不可以)上能直接观看,自己的摄像头是用树莓派转接的)。可控制四个推进器。具体使用教程见附件一。 和...

    明日科技C#开发入门及项目实战

    实例206 设置ie浏览器的默认下载路径 第19章 c#语言新技术 实例207 使用隐式类型局部变量实现字母的大小写转换 实例208 使用扩展方法显示员工信息 实例209 使用lambda表达式查找指定字符串 实例210 检查序列中是否...

    《C#经典编程220例》.(明日科技).【带书签】-共3部分

    实例206 设置ie浏览器的默认下载路径 394 第19章 c#语言新技术 396 实例207 使用隐式类型局部变量实现字母的大小写转换 397 实例208 使用扩展方法显示员工信息 398 实例209 使用lambda表达式查找指定字符串 400 实例...

    asp.net知识库

    关于能自定义格式的、支持多语言的、支持多数据库的代码生成器的想法 发布Oracle存储过程包c#代码生成工具(CodeRobot) New Folder XCodeFactory3.0完全攻略--序 XCodeFactory3.0完全攻略--基本思想 XCodeFactory...

    Google Chrome 6.0.451.0 Dev 版(一个由Google公司开发的网页浏览器)

    扩展程序可让您自定义谷歌浏览器的各种功能,同时可以精简浏览器,去掉其中不需要的功能。 扩展程序有以下几种不同的类型:  浏览器操作  此类扩展程序会在"网页"菜单和"工具"菜单旁添加一个按钮;这样,无论您...

    Visual C++程序开发范例宝典(光盘) 第四部分

    实例196 隐藏IE浏览器的右键关联菜单 实例197 设置IE的默认主页 实例198 清空上网历史记录 7.3 文件控制 实例199 如何建立文件关联 实例200 控制光驱的自动运行功能 7.4 游戏设置 实例201 设置“蜘蛛纸牌”...

    Visual C++程序开发范例宝典(光盘) 第八部分

    实例196 隐藏IE浏览器的右键关联菜单 实例197 设置IE的默认主页 实例198 清空上网历史记录 7.3 文件控制 实例199 如何建立文件关联 实例200 控制光驱的自动运行功能 7.4 游戏设置 实例201 设置“蜘蛛纸牌”...

    Visual C++程序开发范例宝典(PDF扫描版).part3

     cc实例196 隐藏IE浏览器的右键关联菜单   cc实例197 设置IE的默认主页   cc实例198 清空上网历史记录   7.3 文件控制   cc实例199 如何建立文件关联   cc实例200 控制光驱的自动运行功能   7.4...

    Visual C++程序开发范例宝典(PDF扫描版).part2

     cc实例196 隐藏IE浏览器的右键关联菜单   cc实例197 设置IE的默认主页   cc实例198 清空上网历史记录   7.3 文件控制   cc实例199 如何建立文件关联   cc实例200 控制光驱的自动运行功能   7.4...

Global site tag (gtag.js) - Google Analytics