PROBLEM
You have a Windows Forms component hosted in Internet Explorer, and you want to catch events raised by this control from client side scripting; to avoid security errors at runtime, the control must have “Allow calls to unmanaged assemblies” permission. if you do this, you’ll notice that this works only if you give this permission to the whole Zone or Site, but does not work if you give it just to the Assembly or the URL.
REASON
The reasoning behind the security exception is AppDomains. Before IE can load your assembly, it must create an AppDomain to load the assembly into. When it creates this AppDomain, it assigns all the evidence it knows without loading your assembly, the Site and Zone that it is loading from. Since the AppDomain itself does not get any evidence about the signature that your assembly has (it can’t since the assembly is not loaded yet), it will not match the code group that you created giving extra trust. Now when a security demand occurs, a stack walk begins. When your assembly is checked for correct permissions, it passes, and the stack walk continues until it gets to the AppDomain. Since the AppDomain doesn’t have the permissions that are required by this demand, it causes the SecurityException to be thrown.
SOLUTION
If you want to bypass the above problem and make your application to work only giving permission to the Assembly or the URL, then you have to Assert the permissions you need in the control code, before rising the event. Thanks to asserting, the security check can be done again at runtime after the AppDomain is created.
The following sample should do the trick:
using System; using System.Drawing; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Windows.Forms; [assembly : AllowPartiallyTrustedCallers][ComSourceInterfaces (typeof (ISimpleEvents))] public sealed class SimpleControl : Control { private Button button1; public SimpleControl () { this.BackColor = Color.Green; button1 = new Button (); button1.Text = “Click Me!”; button1.Width = 100; button1.Click += new EventHandler (HandleButtonClick); Controls.Add (button1); } private void HandleButtonClick (object sender, EventArgs e) { try { MethodInvoker h = ButtonClicked; if (null != h) { ButtonClicked (); } } catch (Exception ex) { MessageBox.Show (ex.ToString ()); } } public event MethodInvoker ButtonClicked; public void SayHello () { MessageBox.Show (“Hello from Windows Forms”); } public string ThemedBackgroundColor { get { return ColorTranslator.ToHtml (this.BackColor); } set { this.BackColor = ColorTranslator.FromHtml (value); } } } [InterfaceTypeAttribute (ComInterfaceType.InterfaceIsIDispatch)] public interface ISimpleEvents { //Each event must have a unique DispId [DispId (1)] void ButtonClicked (); }
Cheers
Carlo