Broken Thoughts

Techknowledge

.Net Dojo: Getting Around ActiveX Activation

Have you ever gone to a website where you have to click to activate a flash control?  This is only an issue if your users use IE.  A blaring example of this is to open any wordpress page that has Youtube video on it.  You have to click it before you can actually click it to start it playing.  Microsoft was forced to enable this on their browsers, but there is a very simple solution to the problem that only a few website developers seem to implement.

According to the W3C, IE was used by 57% of the people browsing the internet.  If you are using flash on your site and you are not using a workaround for activation, you are annoying over 1/2 your user base.  Lucky for you, I have compiled the solution into a simple ASP.NET 2.0 control that you can use.  Don’t like ASP.NET?  You can take the principals of the workaround and apply them to any language.

The basis for the workaround is that any flash tags written via javascript are immune to the ActiveX activation.  The problem that I discovered while building this control is that all browsers behave differently when it comes to javascript.  My first version of the control used <noscript>…</noscript> tags to show the control normally if the user has javascript disabled.  The problem we found is that Safari does not support noscript tags.  On Safari on a mac, no flash would appear.  So, I reworked the control to detect the browser version.  If it is any version of IE, it uses javascript to write the flash and <noscript>…</noscript> as a backup.  For all other browsers, the ActiveX activation is not a problem, so I just write the flash out normally, thus eliminating the pesky javascript issues.

Let’s pick apart the class.  First we have my properties, which are set in the html.  I take in a name for the flash, and the URL.  In previous versions I accepted other properties, like height, width, etc.  In this version, I inheirit from WebControls which gives me the height and width properties.


private string name;
private string flashUrl;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public string FlashUrl
        {
            get { return flashUrl; }
            set
            {
                if (String.IsNullOrEmpty(value))
                {
                    flashUrl = value;
                }
                else
                {
                    flashUrl = value.ToLower(CultureInfo.InvariantCulture);
                }
            }
        }

Here we see how the control is rendered.  On pre-render, I attach a javascript file that writes out the tags.  I just pass in a fiew variables and it takes care of the rest.  On render, I look to see in “ie” exists in the browser type.  If it does, I use the javascript writer.  If it doesn’t I write the object tags out.


        protected override void OnPreRender(EventArgs e)
        {
            //register the needed javascript file
            Page.ClientScript.RegisterClientScriptInclude("ActiveXWriter", Page.ClientScript.GetWebResourceUrl(this.GetType(), "Olympus.WebControls.Scripts.ActiveXWriter.js"));
            base.OnPreRender(e);
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            if (System.Web.HttpContext.Current.Request.Browser.Type.ToLower(CultureInfo.InvariantCulture).IndexOf("ie") != -1)
            {
                writer.Write("\n\n");

                writer.Write(GenerateJavaScript());

                writer.Write("\n\n<noscript>\n");
                writer.Write(GenerateObjectTags());
                writer.Write("\n</noscript>");
            }
            else
            {
                writer.Write(GenerateObjectTags());
            }
        }

Notice the pre-render.  I am calling the script as a library resource.  The Flash.cs file is located in the Webcontrols folder.  There is a Scripts folder that contains ActiveXWriter.js, which is set to be an embedded resource and has output set to “do not copy”.  To add an embedded resource, in the AssemblyInfo.cs file, you must add the System.Web.UI. namespace and then add the following attribute.


[assembly: WebResource("Olympus.WebControls.Scripts.ActiveXWriter.js", "text/javascript")]

Here we see how I build either the javascript code to call the ActiveXWriter, or the object tags that are rendered directly to the page.


 private string GenerateJavaScript()
        {
            StringBuilder script = new StringBuilder();
            script.Append("<script language=\"Javascript\">\n");
            script.Append("writeFlashComponent(\"");
            script.Append(Name);
            script.Append("\", \"");
            script.Append(FlashUrl);
            script.Append("\", ");
            script.Append(Height.Value);
            script.Append(", ");
            script.Append(Width.Value);
            script.Append(", \"");
            script.Append(this.BackColor);
            script.Append("\", \"");
            script.Append(System.Web.HttpContext.Current.Request.IsSecureConnection.ToString(CultureInfo.InvariantCulture).ToLower(CultureInfo.InvariantCulture));
            script.Append("\");\n");
            script.Append("</script>");
            return script.ToString();
        }
        private string GenerateObjectTags()
        {
            StringBuilder script = new StringBuilder();
            bool isSecure = System.Web.HttpContext.Current.Request.IsSecureConnection;
            if (isSecure)
            {
             script.Append("<object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" codebase=\"https://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0\" ");
         }
         else
         {
             script.Append("<object classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" codebase=\"http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0\" ");
         }
            if (Width.Value != 0)
            {
                script.Append("width=\"");
                script.Append(Width.Value);
                script.Append("\" ");
            }
            if (Height.Value != 0)
            {
                script.Append("height=\"");
                script.Append(Height.Value);
                script.Append("\" ");
            }
            script.Append(" id=\"");
            script.Append(Name);
            script.Append("\" align=\"middle\" VIEWASTEXT>");
            script.Append("<param name=\"allowScriptAccess\" value=\"sameDomain\" />");
            script.Append("<param name=\"movie\" value=\"");
            script.Append(FlashUrl);
            script.Append("\" />");
            script.Append("<param name=\"menu\" value=\"false\" />");
            script.Append("<param name=\"quality\" value=\"high\" /><param name=\"wmode\" value=\"transparent\" />");
            script.Append("\" />");
            script.Append("<embed src=\"");
            script.Append(FlashUrl);
            script.Append("\" menu=\"false\" quality=\"high\" wmode=\"transparent\" ");
            if (this.BackColor != null)
            {
                script.Append(" bgcolor=\"");
                script.Append(this.BackColor);
                script.Append("\" ");
            }
            if (Width.Value != 0)
            {
                script.Append("width=\"");
                script.Append(Width.Value);
                script.Append("\" ");
            }
            if (Height.Value != 0)
            {
                script.Append("height=\"");
                script.Append(Height.Value);
                script.Append("\" ");
            }
            script.Append("name=\"");
            script.Append(Name);
            
         if (isSecure)
            {
             script.Append("\" align=\"middle\" allowscriptaccess=\"sameDomain\" type=\"application/x-shockwave-flash\" pluginspage=\"https://www.macromedia.com/go/getflashplayer\" />");
         }
         else
         {
             script.Append("\" align=\"middle\" allowscriptaccess=\"sameDomain\" type=\"application/x-shockwave-flash\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\" />");
         }
         
         script.Append("</object>");
            return script.ToString();
        }

The javascript file is very simply a document.write with the tags.  If you wanted to be lazy you could even pass the object tags from the method above into a javascript method that just spits them out with a document.write.  As you can see, I even make the flash work with secure websites.  You do this by simply using https in the urls to macromedia.  Then you won’t see the security error for your swf.By adding the control to your website, and setting the name, url, height, width, and backcolor properties, you can render flash without having to annoy your visitors.You can download the source and the javascript file from my Box.Net account.

November 20, 2007 - Posted by Broken Bokken | .Net | , , , , , , , , , , , , , , | No Comments

No comments yet.

Leave a comment