【发布时间】:2012-11-02 00:15:10
【问题描述】:
我正在使用Systems.Windows.Forms.Webbrowser 控件并且需要覆盖下载管理器。我已按照说明 here 对表单进行子类化并覆盖 CreateWebBrowserSiteBase()
/// <summary>
/// Browser with download manager
/// </summary>
public class MyBrowser : WebBrowser
{
/// <summary>
/// Returns a reference to the unmanaged WebBrowser ActiveX control site,
/// which you can extend to customize the managed <see ref="T:System.Windows.Forms.WebBrowser"/> control.
/// </summary>
/// <returns>
/// A <see cref="T:System.Windows.Forms.WebBrowser.WebBrowserSite"/> that represents the WebBrowser ActiveX control site.
/// </returns>
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
{
var manager = new DownloadWebBrowserSite(this);
manager.FileDownloading += (sender, args) =>
{
if (FileDownloading != null)
{
FileDownloading(this, args);
}
};
return manager;
}
}
在DownloadWebBrowserSite 中,我实现IServiceProvider 以在请求时提供IDownloadManager。
/// <summary>
/// Queries for a service
/// </summary>
/// <param name="guidService">the service GUID</param>
/// <param name="riid"></param>
/// <param name="ppvObject"></param>
/// <returns></returns>
public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
{
if ( (guidService == Constants.IID_IDownloadManager && riid == Constants.IID_IDownloadManager ))
{
ppvObject = Marshal.GetComInterfaceForObject(_manager, typeof(IDownloadManager));
return Constants.S_OK;
}
ppvObject = IntPtr.Zero;
return Constants.E_NOINTERFACE;
}
DownloadManager 取自上面的示例。
/// <summary>
/// Intercepts downloads of files, to add as PDFs or suppliments
/// </summary>
[ComVisible(true)]
[Guid("bdb9c34c-d0ca-448e-b497-8de62e709744")]
[CLSCompliant(false)]
public class DownloadManager : IDownloadManager
{
/// <summary>
/// event called when the browser is about to download a file
/// </summary>
public event EventHandler<FileDownloadEventArgs> FileDownloading;
/// <summary>
/// Return S_OK (0) so that IE will stop to download the file itself.
/// Else the default download user interface is used.
/// </summary>
public int Download(IMoniker pmk, IBindCtx pbc, uint dwBindVerb, int grfBINDF, IntPtr pBindInfo,
string pszHeaders, string pszRedir, uint uiCP)
{
// Get the display name of the pointer to an IMoniker interface that specifies the object to be downloaded.
string name;
pmk.GetDisplayName(pbc, null, out name);
if (!string.IsNullOrEmpty(name))
{
Uri url;
if (Uri.TryCreate(name, UriKind.Absolute, out url))
{
if ( FileDownloading != null )
{
FileDownloading(this, new FileDownloadEventArgs(url));
}
return Constants.S_OK;
}
}
return 1;
}
}
问题在于 pmk.GetDisplayName 返回初始 URL,而不是要下载的项目的 URL。如果 URI 指向一个动态页面,例如http://www.example.com/download.php,我就没有得到要下载的实际文件。我需要从标头中获取 URL,以便获取我应该下载的实际文件。
Google 表示我必须创建一个IBindStatusCallback 实现,该实现还实现IHttpNegotiate 和IServiceProvider 以响应IID_IHttpNegotiate,这样我才能看到IHttpNegotiate.OnResponse。我设法实现了这一点,但是,QueryService 似乎只要求IID_IInternetProtocol 而从不要求IID_IHttpNegotiate。
任何建议都会很棒。
【问题讨论】:
-
嗨,您提到实现 IBindingStatusCallback - 据我所知,该接口称为 IBindStatusCallback - 这是一个错字吗?您还没有展示 IBindStatusCallback 的实现。 MSDN 提到 Urlmon.dll 将使用 IBindStatusCallback 的 QueryInterface 实现来获取指向您的 IHttpNegotiate 接口的指针。看看msdn.microsoft.com/en-us/library/ms775054(v=vs.85).aspx
-
是否可以将可编译的示例放在某个地方以便我们进行测试?
-
@SimonMourier 我会在接下来的一两天内研究创建示例。
-
@Anthill 是的,应该是
IBindStatusCallback。我已经编辑了这个问题。我已经实现了 msdn.microsoft.com/en-us/library/ms775054(v=vs.85).aspx 的建议。问题是IBindStatusCallback的QueryService永远不会用IID_IHttpNegotiate调用(这样我就可以返回IHttpNegotiate实现)。它总是用IID_IInternetProtocol调用。当QueryService要求IID_IInternetProtocol时,我不知道该返回什么。 -
@SimonMourier 我为演示示例应用程序添加了一个保管箱链接,解决方案中包含 README.txt。
标签: c# winforms webbrowser-control download-manager