BUG: FileDownload event handler in .NET WebBrowser host is never called (325204)
The information in this article applies to:
- Microsoft Internet Explorer (Programming)
- Microsoft Visual C# .NET (2003)
- Microsoft Visual C# .NET (2002)
- Microsoft .NET Framework 1.1
- Microsoft .NET Framework 1.0
This article was previously published under Q325204 SYMPTOMS If you sink the FileDownload event of the DWebBrowserEvents2 source interface for the WebBrowser control that is hosted on a managed application in Visual C#
.NET, the event handler is not called. CAUSEAccording to the documentation, the
FileDownload event fires with a single parameter: the VARIANT_BOOL argument Cancel. However, this event fires with another BOOL argument in addition
to the Cancel VARIANT_BOOL argument. This BOOL argument indicates whether an
Active Document server is loading in memory. However, because the type library
has only one parameter listed, any development tool that generates event
handlers that are based on the type library cannot properly sink the event.
WORKAROUNDTo work around the problem:
- Subclass the AxHost class in System.Windows.Forms instead of importing the WebBrowser control.
- Write all the supporting code to host the WebBrowser control and sink its events.
- Add an event handler for FileDownload that uses the actual signature instead of the signature that is
defined in intermediate definition language (IDL) and the documentation. The
actual signature for the FileDownload event must have two arguments.
Step-by-step workaround- Create a new class named MyWebBrowser that hosts the WebBrowser control and raises the FileDownload event. The MyWebBrowser class derives from AxHost and implements IMyWebBrowserEvents:
public class MyWebBrowser : AxHost, IMyWebBrowserEvents
{
...
} - Define the constructor of MyWebBrowser:
public MyWebBrowser() : base("8856f961-340a-11d0-a96b-00c04fd705a2")
{
} Notice that the constructor for MyWebBrowser calls the base class constructor. The base class is specified by
its GUID. The specified GUID is of the WebBrowser co-class. - Define the IMyWebBrowserEvents with the same methods as the IWebBrowser interface:
[Guid("eab22ac1-30c1-11cf-a7eb-0000c05bae0b")]
interface IMyWebBrowser
{
void GoBack();
void GoForward();
void GoHome();
void GoSearch();
void Navigate(string url, ref object flags, ref object targetFrame, ref
object postData, ref object headers);
void Refresh();
void Refresh2();
void Stop();
void GetApplication();
void GetParent();
void GetContainer();
} Notice that the GUID as specified by the Guid attribute is the interface identifier (IID) of the IWebBrowser interface. The complete method signature of only the method that
is used in the MyWebBrowser class is specified. For example, the Navigate method is specified completely. - Define the IMyWebBrowserEvents interface:
[Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyWebBrowserEvents
{
[DispId(270)]
void RaiseFileDownload(bool Load,ref bool Cancel);
} Notice that the GUID as specified by the Guid attribute is the IID of DWebBrowserEvents2 dispinterface. Additionally, the DispId attribute that is applied to the RaiseFileDownload method is the same as the dispatch identifier (DISPID) of the FileDownload event in the DWebBrowserEvent2 source interface. The signature of the RaiseFileDownload event has two arguments instead of the one argument that is
visible for the FileDownload event. - Provide an event and a delegate for clients of the MyWebBrowser class to receive the FileDownload event from the WebBrowser ActiveX control:
public class MyWebBrowser : AxHost, IMyWebBrowserEvents
{
...
public event FileDownloadEventHandler FileDownload;
...
}
...
public delegate void FileDownloadEventHandler(object sender, FileDownloadEventArgs e);
public class FileDownloadEventArgs
{
public FileDownloadEventArgs(bool load, bool cancel)
{
this.cancel = cancel;
this.load = load;
}
protected bool cancel;
protected bool load;
public bool Load
{
get{return load;}
}
public bool Cancel
{
get{return cancel;}
set{cancel = value;}
}
} - Implement the RaiseFileDownload method to raise the event that is defined in step 5:
public class MyWebBrowser : AxHost, IMyWebBrowserEvents
{
...
public void RaiseFileDownload(bool load,ref bool cancel)
{
FileDownloadEventArgs e = new FileDownloadEventArgs(load,cancel);
if(FileDownload != null)
FileDownload(this, e);
cancel = e.Cancel;
}
...
}
- Override the AttachInterfaces method to get the reference of the WebBrowser ActiveX control being hosted:
public class MyWebBrowser : AxHost, IMyWebBrowserEvents
{
private IMyWebBrowser control;
...
protected override void AttachInterfaces()
{
try { control = (IMyWebBrowser) GetOcx(); }
catch { }
}
...
} - Override CreateSink and DetachSink to attach a sink and detach a sink from the connectable object (WebBrowser instance), respectively:
public class MyWebBrowser : AxHost, IMyWebBrowserEvents
{
...
private ConnectionPointCookie cookie;
...
protected override void CreateSink()
{
try
{
cookie = new ConnectionPointCookie(control, this, typeof(IMyWebBrowserEvents));
}
catch { }
}
protected override void DetachSink()
{
try
{
cookie.Disconnect();
}
catch { }
}
...
} - Implement a simple property that invokes the Navigate method of the WebBrowser ActiveX component that is being hosted:
public class MyWebBrowser : AxHost, IMyWebBrowserEvents
{
...
protected string url;
...
public string Url
{
get { return url; }
set
{
url = value;
object o = null;
control.Navigate(url, ref o, ref o, ref o, ref o);
}
}
...
}
With the MyWebBrowser class, you receive the FileDownload event. Complete code listingFor your reference, the following is the complete code listing for
the steps. To receive the FileDownload event, replace the existing code in Form1.cs for a Visual C# .NET
Windows Application project with this code: using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Data;
using System.IO;
namespace HostingActiveX
{
public class Form1 : System.Windows.Forms.Form
{
private System.ComponentModel.Container components = null;
private MyWebBrowser webBrowser;
public Form1()
{
InitializeComponent();
webBrowser = new MyWebBrowser();
webBrowser.Dock = DockStyle.Fill;
webBrowser.FileDownload += new FileDownloadEventHandler(OnFileDownload);
Controls.Add(webBrowser);
}
protected void OnFileDownload(object sender, FileDownloadEventArgs e)
{
MessageBox.Show("User is trying to download file");
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
}
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void Form1_Load(object sender, System.EventArgs e)
{
webBrowser.Url = "http://www.microsoft.com";
}
}
public class MyWebBrowser : AxHost, IMyWebBrowserEvents
{
private IMyWebBrowser control;
private ConnectionPointCookie cookie;
protected string url;
public event FileDownloadEventHandler FileDownload;
public MyWebBrowser() : base("8856f961-340a-11d0-a96b-00c04fd705a2")
{
}
public void RaiseFileDownload(bool load, ref bool cancel)
{
FileDownloadEventArgs e = new FileDownloadEventArgs(load, cancel);
if(FileDownload != null)
FileDownload(this, e);
cancel = e.Cancel;
}
protected override void CreateSink()
{
try
{
cookie = new ConnectionPointCookie(control, this,
typeof(IMyWebBrowserEvents)); }
catch { }
}
protected override void DetachSink()
{
try
{
cookie.Disconnect();
}
catch { }
}
protected override void AttachInterfaces()
{
try { control = (IMyWebBrowser) GetOcx(); }
catch { }
}
public string Url
{
get { return url; }
set
{
url = value;
object o = null;
control.Navigate(url, ref o, ref o, ref o, ref o);
}
}
}
[Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IMyWebBrowserEvents
{
[DispId(270)]
void RaiseFileDownload(bool Load,ref bool Cancel);
}
public delegate void FileDownloadEventHandler(object sender, FileDownloadEventArgs e);
public class FileDownloadEventArgs
{
public FileDownloadEventArgs(bool load,bool cancel)
{
this.cancel = cancel;
this.load = load;
}
protected bool cancel;
protected bool load;
public bool Load
{
get{return load;}
}
public bool Cancel
{
get{return cancel;}
set{cancel = value;}
}
}
[Guid("eab22ac1-30c1-11cf-a7eb-0000c05bae0b")]
interface IMyWebBrowser
{
void GoBack();
void GoForward();
void GoHome();
void GoSearch();
void Navigate(string url, ref object flags, ref object targetFrame, ref
object postData, ref object headers);
void Refresh();
void Refresh2();
void Stop();
void GetApplication();
void GetParent();
void GetContainer();
}
}
STATUSMicrosoft has confirmed that this is a bug in the Microsoft products that are listed in the "Applies to" section.REFERENCESFor more information about the AxHost class and its members, visit the following MSDN Web site:
Modification Type: | Major | Last Reviewed: | 9/29/2005 |
---|
Keywords: | kbActivexEvents kbCtrl kbEvent kbAutomation kbbug KB325204 kbAudDeveloper kbAudITPRO |
---|
|