title: Windows Forms Webbrowswer control with IDownloadManager
body: <p>I'm using the <code>Systems.Windows.Forms.Webbrowser</code> control and need to override the download manager. I've followed the instructions <a href="http://code.msdn.microsoft.com/windowsdesktop/CSIEDownloadManager-8ab5d910" rel="nofollow">here</a> to subclass the form and override <code>CreateWebBrowserSiteBase()</code></p>
  
  <pre><code>/// &lt;summary&gt;
  /// Browser with download manager
  /// &lt;/summary&gt;
  public class MyBrowser : WebBrowser  
  {
      /// &lt;summary&gt;
      /// Returns a reference to the unmanaged WebBrowser ActiveX control site,
      /// which you can extend to customize the managed &lt;see ref="T:System.Windows.Forms.WebBrowser"/&gt; control.
      /// &lt;/summary&gt;
      /// &lt;returns&gt;
      /// A &lt;see cref="T:System.Windows.Forms.WebBrowser.WebBrowserSite"/&gt; that represents the WebBrowser ActiveX control site.
      /// &lt;/returns&gt;
      protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
      {
          var manager = new DownloadWebBrowserSite(this);
          manager.FileDownloading += (sender, args) =&gt;
              {
                  if (FileDownloading != null)
                  {
                      FileDownloading(this, args);
                  }
              };
          return manager;
      }
  }
  </code></pre>
  
  <p>In the <code>DownloadWebBrowserSite</code>, I implement <code>IServiceProvider</code> to provide an <code>IDownloadManager</code> when requested.</p>
  
  <pre><code>        /// &lt;summary&gt;
          /// Queries for a service
          /// &lt;/summary&gt;
          /// &lt;param name="guidService"&gt;the service GUID&lt;/param&gt;
          /// &lt;param name="riid"&gt;&lt;/param&gt;
          /// &lt;param name="ppvObject"&gt;&lt;/param&gt;
          /// &lt;returns&gt;&lt;/returns&gt;
          public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
          {
              if ( (guidService == Constants.IID_IDownloadManager &amp;&amp; riid == Constants.IID_IDownloadManager ))
              {
                  ppvObject = Marshal.GetComInterfaceForObject(_manager, typeof(IDownloadManager));
                  return Constants.S_OK;
              }
              ppvObject = IntPtr.Zero;
              return Constants.E_NOINTERFACE;
          }
  </code></pre>
  
  <p>The <code>DownloadManager</code> is taken from the example above.</p>
  
  <pre><code>/// &lt;summary&gt;
  /// Intercepts downloads of files, to add as PDFs or suppliments
  /// &lt;/summary&gt;
  [ComVisible(true)]
  [Guid("bdb9c34c-d0ca-448e-b497-8de62e709744")]
  [CLSCompliant(false)]
  public class DownloadManager : IDownloadManager
  {
      /// &lt;summary&gt;
      /// event called when the browser is about to download a file
      /// &lt;/summary&gt;
      public event EventHandler&lt;FileDownloadEventArgs&gt; FileDownloading;
  
      /// &lt;summary&gt;
      /// Return S_OK (0) so that IE will stop to download the file itself. 
      /// Else the default download user interface is used.
      /// &lt;/summary&gt;
      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;
      }
  }
  </code></pre>
  
  <p>The problem is that the <code>pmk.GetDisplayName</code> returns the initial URL, not the URL of the item to be downloaded. If the URI points to a dynamic page, such as <a href="http://www.example.com/download.php" rel="nofollow">http://www.example.com/download.php</a>, I'm not getting the actual file to be downloaded. I need to get the URL from the header so that I get the actual file I'm supposed to be downloading. </p>
  
  <p>Google indicates that I have to create a <code>IBindStatusCallback</code> implementation that also implements <code>IHttpNegotiate</code> and <code>IServiceProvider</code> to respond to <code>IID_IHttpNegotiate</code>, so that I can see the <code>IHttpNegotiate.OnResponse</code>. I've managed to implement that, however, <code>QueryService</code> only seems to ever ask for <code>IID_IInternetProtocol</code> and never <code>IID_IHttpNegotiate</code>.</p>
  
  <p>Any advice would be great.</p>