I was working on a C# WinForms project where I had to embed the
Adobe SVG Viewer in my form. The only distribution available comes in the form of an ActiveX control. The control becomes useful when you set its SRC property to some .svg file to render. Unfortunately this must happen at design-time or else a ActiveXStateException is thrown:
System.AccessViolationException was unhandled
Message="Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
Source="Interop.SVGACTIVEXLib"
StackTrace:
at SVGACTIVEXLib.ISVGControl.set_SRC(String pVal)
at AxSVGACTIVEXLib.AxSVGCtl.set_SRC(String value)
The control also offers setSrc and getSrc methods, but these fail with the same exception. More inspection led to the discovery that the control's SRC attribute can only be set after being freshly dropped onto the design surface. What to do? (answer follows...)
In my case, I wanted to generate SVG files at run-time using temporary file storage space, which meant the filename would not be predictable at design time. A lot of Googling turned up an
Adobe support article revealed that only an ActiveX host that implements IHtmlDocument2 can set the SRC attribute for security reasons, starting at their SVG 3.03 version.
Well, seeing as I didn't want to rewrite a web browser, I decided to re-use the .NET component for IE. I would wrap the SVG Viewer ActiveX control into a web browser control, inside a User Control that would hide the ugly workaround. It turns out that very little code was required. The result is that my SVG Viewer can effectively display whatever SVG I want at run-time, with no apparent side effects.
I include the code below, licensed with X11:
SVGViewer.cs ///
/// A user control that wraps up Adobe's SVG Viewer in an
/// IE web browser to allow for changing the source file
/// at run-time.
///
///
/// This is necessary due to:
/// http://support.adobe.com/devsup/devsup.nsf/docs/54114.htm
/// Also references:
/// http://www.csharphelp.com/archives/archive146.html
/// http://ryanfarley.com/blog/archive/2004/12/23/1330.aspx
/// http://www.adobe.com/svg/viewer/install/svgtest.html
///
public partial class SvgViewer : UserControl
{
public SvgViewer()
{
InitializeComponent();
}
const string svgHtml = "<html><head><style>body {{ margin: 0; padding: 0; }} </style><embed src='{0}' width='100%' height='100%' type='text/html; charset=UTF-8' />";
private string source;
[Bindable(true)]
[Category("Appearance")]
[Description("The SVG file to display.")]
public string Source
{
get { return source; }
set
{
source = value;
UpdateHtml();
}
}
protected virtual void UpdateHtml()
{
if (webBrowser1.Document.Body != null)
webBrowser1.Document.OpenNew(true);
webBrowser1.Visible = !string.IsNullOrEmpty(source);
if (string.IsNullOrEmpty(source)) return;
webBrowser1.Document.Write(string.Format(svgHtml, source));
}
}
SVGViewer.Designer.cs
namespace Phylogenetics
{
partial class SvgViewer
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
///
/// Clean up any resources being used.
///
/// <param name="disposing" />true if managed resources should be disposed; otherwise, false.
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.webBrowser1 = new System.Windows.Forms.WebBrowser();
this.SuspendLayout();
//
// webBrowser1
//
this.webBrowser1.AllowNavigation = false;
this.webBrowser1.AllowWebBrowserDrop = false;
this.webBrowser1.Dock = System.Windows.Forms.DockStyle.Fill;
this.webBrowser1.IsWebBrowserContextMenuEnabled = false;
this.webBrowser1.Location = new System.Drawing.Point(0, 0);
this.webBrowser1.MinimumSize = new System.Drawing.Size(20, 20);
this.webBrowser1.Name = "webBrowser1";
this.webBrowser1.ScriptErrorsSuppressed = true;
this.webBrowser1.ScrollBarsEnabled = false;
this.webBrowser1.Size = new System.Drawing.Size(150, 150);
this.webBrowser1.TabIndex = 0;
this.webBrowser1.Url = new System.Uri("about:blank", System.UriKind.Absolute);
this.webBrowser1.WebBrowserShortcutsEnabled = false;
//
// SvgViewer
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.webBrowser1);
this.Name = "SvgViewer";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.WebBrowser webBrowser1;
}
}