【发布时间】:2013-05-02 21:37:09
【问题描述】:
为了能够过滤使用 C# Web 浏览器 (WinForms) 获取的 URL(包括 JS、图像等),唯一可包含的选项似乎是包装 HTTP 的异步可插入协议(以及后来的其他协议) )。不幸的是,原始原始协议实现在多次调用后抛出InvalidCastException失败了
现在一些代码:
首先注册并附加协议的工厂:
var ep = new FilteredHttpProtocolFactory();
Guid id = Guid.Parse ("E00957BD-D0E1-4eb9-A025-7743FDC8B27B");
session.RegisterNameSpace (ep, ref id, "http", 0, null, 0);
(工厂:)
[Guid ("EF474615-8079-4CFA-B114-6D1D28634DD8")]
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.None)]
public class FilteredHttpProtocolFactory : IClassFactory
{
public void CreateInstance (object pUnkOuter, Guid riid, out object ppvObject)
{
ppvObject = new FilteredHttpProtocol();
}
public void LockServer (bool fLock)
{
}
}
这是 IE 使用的原始 HTTP 协议,当使用它而不是包装器时,它工作得很好:
[ComImport]
[Guid ("79eac9e2-baf9-11ce-8c82-00aa004ba90b")]
public class OriginalHttpHandler
{
}
这是包装器本身:
[Guid ("E00957BD-D0E1-4eb9-A025-7743FDC8B27B")]
[ComVisible (true)]
[ClassInterface (ClassInterfaceType.None)]
[AsyncProtocol (Name = "http2", Description = "blah")]
public class FilteredHttpProtocol : IInternetProtocol, IInternetProtocolRoot
{
private readonly IInternetProtocol _wrapped;
public FilteredHttpProtocol ()
{
var originalHttpHandler = new OriginalHttpHandler();
_wrapped = (IInternetProtocol) originalHttpHandler;
}
public void Start (string szURL, IInternetProtocolSink Sink, IInternetBindInfo pOIBindInfo, uint grfPI, uint dwReserved)
{
_wrapped.Start (szURL, Sink, pOIBindInfo, grfPI, dwReserved);
}
public void Continue (ref _tagPROTOCOLDATA pProtocolData)
{
_wrapped.Continue (ref pProtocolData); // <- FAILS HERE
}
// .... other methods from IInternetProtocol
public uint Read (IntPtr pv, uint cb, out uint pcbRead)
{
return _wrapped.Read (pv, cb, out pcbRead); // <- OR HERE
}
}
所以,奇怪的是,构造函数被调用,Start() 被调用,甚至 Read() 和 Continue() 被调用多次,直到整个事情失败(Read() 或 Continue())当页面的某些部分已经可见时(!),但似乎大部分都缺少一个特定的图像(大部分!):
Unable to cast COM object of type 'Clients.Windows.Protocol.OriginalHttpHandler'
to interface type 'Clients.Windows.Protocol.IInternetProtocol'. This operation
failed because the QueryInterface call on the COM component for the interface
with IID '{79EAC9E4-BAF9-11CE-8C82-00AA004BA90B}' failed due to the following
error: No such interface supported (Exception from HRESULT: 0x80004002 E_NOINTERFACE)).
看到我已经多次将对象强制转换到所述接口(这应该导致每次调用QueryInterface(),并且在失败之前已经多次调用它(通过断点等进行验证)这个错误真的是令人费解。通过查看 ref 计数,我已经排除了对象被过早处理的可能性(无论如何都没有意义)。
我已经尝试了几件事:
- 谷歌,但应用程序相当罕见
- http://msdn.microsoft.com/en-us/library/aa767916(v=vs.85).aspx
- 继承 ComImport 的对象 - 然后我的实现被忽略
- 查看引用计数
- 各种类型的演员表
- 检查 GUID 和接口是否有错误
- 询问同事
基本上,我想要实现的是包装 IE 的默认 http 协议实现以过滤掉 URL,包括从中检索资源的 URL。我也会对合适的替代方案感到满意,但它们必须符合 GPLv2,可与浏览器应用程序一起部署,并且不对系统的其余部分进行任何更改(即无代理)。
感谢您的帮助;)
顺便说一句,这将成为我硕士论文的一部分:http://desktopgap.codeplex.com
【问题讨论】:
-
为什么你有 ClassInterfaceType None?我会删除它。此外,E_NOINTERFACE 可能是线程问题。你的对象是什么时候创建的?在什么线程上?这是什么线程公寓类型? (blogs.msdn.com/b/oldnewthing/archive/2004/12/13/281910.aspx)
-
嗨!感谢您的回复。确实在查看了用于调用方法的线程之后:
#1 threadID: 3 C'tor() #1 URL: http://... #1 original thread: 3 calling thread 3 Start() STA #2 threadID: 3 C'tor() #2 URL: http://... #2 original thread: 3 calling thread 3 Start() STA #1 original thread: 3 calling thread 14 Continue() MTA #2 original thread: 3 calling thread 13 Continue() MTA A first chance exception of type 'System.InvalidCastException'...但是这些线程是由调用它们的人创建的,这就是为什么我不确定如何更改公寓... -
是在当前线程上创建每个FilteredHttpProtocol实例还是共享实例?
-
...此外,似乎在需要多个子请求时输入了 MTA,在我的情况下,需要加载 2 个图像(对象 #1 和 #2)——但仍然是每个子请求有自己的对象,并且它们的构造使用相同的线程。
-
我的发现实际上与下面 user2371720 的answer 的发现相同。所以它们似乎也是在单个线程上单独创建的
标签: c# .net internet-explorer http com