使用IDownloadManager控制Windows窗体Webbrowswer

我正在使用Systems.Windows.Forms.Webbrowser控件,需要覆盖下载管理器。 我按照这里的说明CreateWebBrowserSiteBase()表单并覆盖CreateWebBrowserSiteBase()

 ///  /// Browser with download manager ///  public class MyBrowser : WebBrowser { ///  /// Returns a reference to the unmanaged WebBrowser ActiveX control site, /// which you can extend to customize the managed  control. ///  ///  /// A  that represents the WebBrowser ActiveX control site. ///  protected override WebBrowserSiteBase CreateWebBrowserSiteBase() { var manager = new DownloadWebBrowserSite(this); manager.FileDownloading += (sender, args) => { if (FileDownloading != null) { FileDownloading(this, args); } }; return manager; } } 

DownloadWebBrowserSite ,我实现IServiceProvider以在请求时提供IDownloadManager

  ///  /// Queries for a service ///  /// the service GUID ///  ///  ///  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取自上面的示例。

 ///  /// Intercepts downloads of files, to add as PDFs or suppliments ///  [ComVisible(true)] [Guid("bdb9c34c-d0ca-448e-b497-8de62e709744")] [CLSCompliant(false)] public class DownloadManager : IDownloadManager { ///  /// event called when the browser is about to download a file ///  public event EventHandler FileDownloading; ///  /// Return S_OK (0) so that IE will stop to download the file itself. /// Else the default download user interface is used. ///  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,以便获取我应该下载的实际文件。

谷歌表示我必须创建一个IBindStatusCallback实现,它也实现IHttpNegotiateIServiceProvider来响应IID_IHttpNegotiate ,这样我就可以看到IHttpNegotiate.OnResponse 。 我已经成功实现了这一点,但是, QueryService似乎只是要求IID_IInternetProtocol而不是IID_IHttpNegotiate

任何建议都会很棒。

您错过了对CreateBindCtx的调用。

将以下内容添加到DownloadManager:

  [DllImport("ole32.dll")] static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc); 

然后确保在注册回调之前调用此方法。 我在你的Download()方法中实现了这个,如下所示:

 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)) { Debug.WriteLine("DownloadManager: initial URL is: " + url); CreateBindCtx(0, out pbc); RegisterCallback(pbc, url); BindMonikerToStream(pmk, pbc); return MyBrowser.Constants.S_OK; } } return 1; } 

有了这个,您的IHttpNegotiate实现将被调用,您将可以访问响应头。