原文:浏览器扩展系列————异步可插入协议(pluggable protocol)的实现
IE中有很多我们比较熟悉的协议,如http,https,mailto,ftp等。当然你也可以实现自己定义的协议,稍微谈一下这里所说的协议,从我的理解来说这里的协议只有当你的网页引用某个资源时才会调用,而不是随便在某个属性的值前面加上某个协议的名称就可以了。常见的协议调用如img的src属性中,很多元素style中的background-image属性中,还有a标签的href属性中。
言归正传,前面说到的实现自定义协议就用到了一种IE下异步可插入协议的技术。
从分类上来说,这种异步可插入协议的技术还分为两种:
- 永久的异步可插入协议,就像http,https,mailto这种不论在ie中或是其它用到浏览器控件中使用。
- 临时的异步可插入协议,只能用在某个进程内,用完可以擦除。
更详细介绍异步可插入协议的资源有http://www.cppblog.com/bigsml/archive/2008/03/23/45145.html。
因为网上介绍永久的异步可插入协议的资源还很多,如codeproject上的:
这篇就主要谈谈如何实现临时的异步可插入协议的方法。
下面谈下具体的实现。
在本实现中主要用到了下面这几个接口:
- IInternetProtocol
- IInternetProtocolRoot
- IInternetSession
- IInternetProtocolInfo
IInternetProtocol接口
它有四个方法:
LockRequest |
Locks the requested resource so that the IInternetProtocolRoot::Terminate method can be called, and the remaining data can be read. |
Read |
Reads data that the pluggable protocol handler gets. |
Seek |
Moves the current seek offset. |
UnlockRequest |
Frees any resources associated with a lock. |
主要用于下载资源,将处理后的资源传递给IE进行显示。
IInternetProtocolRoot接口
Abort |
Cancels an operation that is in progress. |
Continue |
Enables the pluggable protocol handler to continue processing data on the apartment thread. |
Resume |
Not currently implemented. |
Start |
Starts the operation. |
Suspend |
Not implemented. |
Terminate |
Releases the resources used by the pluggable protocol handler. |
主要用于解析资源,准备待下载的资源。
IInternetSession接口
它包括9个方法,根据需要我们只用到了下面两个方法:
RegisterNameSpace |
Registers a temporary pluggable namespace handler on the current process. |
UnregisterNameSpace |
Unregisters a temporary pluggable namespace handler. |
实现临时可插入协议的注册和取消。
IInternetProtocolInfo接口
它包括4个方法。
CombineUrl |
Combines a base URL and relative URL into a full URL. |
CompareUrl |
Compares two URLs and determines if they are equal. |
ParseUrl |
Parses a URL. |
QueryInfo |
Gets information related to the specified URL. |
主要提供了对于Url的处理。
此外,在构造IInternetSession的时候还用到了一个外部方法:
[DllImport("urlmon.dll")]
private
static
extern
void CoInternetGetSession(int sessionMode,
out
IInternetSession session, int reserved);
预备的知识介绍完,下面就是具体实现了。
一般方法是在一个类中实现IInternetProtocol,IInternetProtocolRoot,IInternetProtocolInfo三个接口,然后通过IInternetSession接口的RegisterNameSpace方法来注册这个自定义协议,用完这后再调用UnregisterNameSpace方法来注销这个自定义协议。
关于IE和IInternetProtocol,IInternetProtocolRoot,IInternetProtocolInfo三个接口的调用流程可以参考msdn上的介绍,中文版的翻译可以参考:
http://www.cnblogs.com/volnet/archive/2008/03/28/About_Asynchronous_Pluggable_Protocols.html
首先通过CoInternetGetSession方法得到一个IInternetSession对象,然后注册自定义的协议:
IInternetSession session;
CoInternetGetSession(0, out session, 0);
Guid guid = new
Guid("79EAC9E4-BAF9-11CE-8C82-00AA004BA90B");
session.RegisterNameSpace(new
ClassFactory(), ref guid, ProcotolName, 0, null, 0);
在注册的时候要传入一个实现了IClassFactory接口的对象,下面是对次接口的实现:
// Interface IClassFactory is here to provide a C# definition of the
// COM IClassFactory interface.
[
ComImport, // This interface originated from COM.
ComVisible(true), // It is not hard to imagine that this interface must not be exposed to COM.
InterfaceType(ComInterfaceType.InterfaceIsIUnknown), // Indicate that this interface is not IDispatch-based.
Guid("00000001-0000-0000-C000-000000000046") // This GUID is the actual GUID of IClassFactory.
]
public
interface
IClassFactory
{
void CreateInstance(IntPtr pUnkOuter, ref
Guid riid, out
IntPtr ppvObject);
}
[ComVisible(true)]
public
class
ClassFactory : IClassFactory
{
#region IClassFactory Implementations
public
void CreateInstance(IntPtr pUnkOuter, ref
Guid riid, out
IntPtr ppvObject)
{
ppvObject = Marshal.GetComInterfaceForObject(new
MyImageProtocol(), typeof(IInternetProtocolInfo));
}
#endregion
}
一下至于IInternetProtocol,IInternetProtocolRoot,IInternetProtocolInfo三个接口实现,大家可以参考上面提到的http://www.cnblogs.com/volnet/archive/2008/03/28/About_Asynchronous_Pluggable_Protocols.html这篇文章。不过要注意的就是这个实现的第二个协议似乎有bug,在实验一次后,可能将IE搞崩溃了,所以实验时要谨慎,不行就用regasm /u命令将dll注销了。