在C#中使用ASV封装编程实践中遇到的问题总结
- 许可证问题:不能直接将SVG VIEWER捆绑发布,但可以要求用户自行下载安装。(另:好像某些公司可以从ADOBE获得独立许可)
3.0.1 的缺省安装目录为c:/windows/system32/adobe/svg viewer 3.0
在 3.0.3 版本后,动态设置SVG文件,setSrc会导致内存保护问题,只能在设计阶段指定文件,以下为该问题的ADOBE的描述。
Known Issue: SVG 3.03 and later may limit embedding SVG to: Internet Explorer
Summary
As a consequence of changes in the ActiveX control needed to prevent security vulnerabilities when hosted by certain classes of applications, the functionality of the control may be impacted when hosted by other applications (Word, Excel, Frame, etc.).
Issue
I'm trying to use the Adobe SVG Viewer (ASV) as an ActiveX control. This works on Adobe SVG Viewer 3.02, but an error occurs and my application exits on Adobe SVG Viewer 3.03.
I use the parameter "C:/svg/mySVG.svg" to invoke method setSrc(string).
Why?
Solution
To fix a security vulnerability (CAN-2005-0918), ASV 3.03 added a test for and disallows cross-domain scripting. This broke the ActiveX control for use in Office and other applications.
The reason:
- Internet Explorer supports the COM IHtmlDocument2 interface--Office products (and many other applications) do not.
- The cross-domain test requires that the host of the ActiveX control implement COM's IHtmlDocument2 interface in order for calls to the setSrc(string) method to succeed.
- Anyone wanting to use the Adobe SVG Viewer ActiveX control within an application other than IE must somehow ensure the host implements the IHtmlDocument2 interface in order to call setSrc(string) successfully.
Background
- http://www.adobe.com/support/techdocs/323585.html
- Vulnerability Summary ID is: CAN-2005-0918
http://www.us-cert.gov/cas/bulletins/SB05-131.pdf
因此我们只能使用 3.0.2 之前的版本。
- 发布问题
l 将ADOBE SVG VIEW下的文件拷贝到发布机器(一般在C:/WINDOWS/system32/Adobe/SVG Viewer 3.0下, 包括所有动态库和说明文件)
l 注册COM组件, REGSVR32 NPSVG3.DLL
l 第一次使用时接受ADOBE协议
- 新建项目的问题:不能动态增加SVG元素的事件处理器,不能通过ECMAScript调用C#对象函数。都是从ECMAScript调用C#存在问题。其它方法好像没有问题,例如增加新的SVG元素,得到或设置属性等。可能是项目配置引起的,使用DEMO项目作为模板建立新项目则没有这个问题。
- 打开文件,ASV为控件名称
ASV.setSrc(filename);
- 使用定时器控制文件的打开状态
loadDelay = new System.Windows.Forms.Timer();
loadDelay.Tick += new EventHandler(SVGBegin);
loadDelay.Interval = 100;
//在定时器事件中
private void SVGBegin(Object obj, EventArgs args)
{
if ( ASV.ReadyState == 4 ) {
loadDelay.Stop();
// init globals
svgWindow = new ASVWindow(ASV);
svgDocument = svgWindow.svgDocument;
svgRoot = svgDocument.rootElement;
…………
- 使用ID得到元素,改变属性并增加C#事件处理函数
SVGCircleElement circle = new SVGCircleElement(svgDocument.getElementById("clickMe").Object);
circle.setAttributeNS(null, "fill", "red");
circle.addEventListener("mousedown", this, false);
public class SvgEventHandler : IEventListener
{
public object Object
{
get { return this; }
}
public void handleEvent(object evt)
{
MouseEvent e = new MouseEvent(evt);
MessageBox.Show("C#: Clicked at (" + e.clientX + "," + e.clientY + ")");
}
}
- 屏蔽ASV缺省的右键菜单
e.stopPropagation();
e.preventDefault();
- 调用ECMAScript
string result = (string) svgWindow.InvokeMethod("sayHello", "Billy");
MessageBox.Show("C#: result = " + result);
- 调用CSharp
svgWindow.SetProperty("csharp", this);
public string sayHello(string name) {
MessageBox.Show( "C#: Hello, " + name );
return "Hello, " + name;
}
//JS脚本中
var csharp;
function callCSharp(e) {
if ( window.csharp != null ) {
var result = csharp.sayHello("Johnny");
alert("ECMAScript: result = " + result);
} else {
alert("Unable to call C# method: csharp object not defined");
}
}
- 显示右键菜单并屏蔽ASV缺省右键菜单
MouseEvent e = new MouseEvent(evt);
if (e.button == 2)
{
e.preventDefault();
contextMenuStrip1.Show(ASV, e.screenX, e.screenY);
}
- 中文问题,
首先要注意的是字体问题,要在svgviewer中显示中文字体,需要将中文字体名称进行“国际化”,即将汉字字体名称改为英文名称,如将“宋体”改为“Simsun",“黑体”改为"Simhei"等,下面是部分字体对照列表:
English Name Localized Name
SimSun 宋体
SimHei 黑体
FangSong_GB2312 仿宋_GB2312
KaiTi_GB2312 楷体_GB2312
YouYuan 幼圆
STSong 华文宋体
STZhongsong 华文中宋
STKaiti 华文楷体
STFangsong 华文仿宋
STXihei 华文细黑
STLiti 华文隶书
STXingkai 华文行楷
STXinwei 华文新魏
STHupo 华文琥珀
STCaiyun 华文彩云
FZYaoTi 方正姚体简体
FZShuTi 方正舒体简体
NSimSun 新宋体
LiSu 隶书
例如:
<text font-family="SimSun" x="50" y="190" text-anchor="middle">中文的情况</text>
其次要注意文件编码问题:将svg文件保存的时候要选择utf-8编码或者unicode编码,当然svg文件的encoding属性也应该是"utf-8",
例如:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
- 可以在脚本使用getURL得到数据,但注意文件必须放在有权限的目录下(范围?),不过建议只使用SVG作为显示,而C#中操作数据
//Load quiz data
getURL("data.xml", fileLoaded);
}
function fileLoaded (data)
{
if(data.success)
{
//alert("ok");
//return;
quiz = new Quiz(data.content);
quiz.showCurrentQuestion();
}
else
{
alert("error");
return;
}
}
- 使用浏览器控件的脚本不能执行,例如
this.dom = new ActiveXObject("MSXML2.DOMDocument");
this.dom.loadXML(data);
建议使用C#中的功能实现
- 新增节点
Element elem = svgDocument.createElement("circle");
String offset = pos.ToString();
elem.setAttribute("id", name);
elem.setAttribute("cx", offset);
elem.setAttribute("cy", offset);
elem.setAttribute("r", "60");
elem.setAttribute("fill", "blue");
//<animate attributeName="r" from="1" to="50" dur="5s" repeatCount="indefinite" />
Element animate = svgDocument.createElement("animate");
animate.setAttribute("attributeName", "r");
animate.setAttribute("from", "1");
animate.setAttribute("to", "60");
animate.setAttribute("dur", "5s");
animate.setAttribute("repeatCount", "indefinite");
elem.appendChild(animate);
svgDocument.rootElement.appendChild(elem);
Text myData = svgDocument.createTextNode(name);
elem = svgDocument.createElement("text");
elem.setAttribute("x", offset);
elem.setAttribute("y", offset);
elem.appendChild(myData);
svgDocument.rootElement.appendChild(elem);
//Add new use
//public static string svgNS = "http://www.w3.org/2000/svg";
//public static string xlinkNS = "http://www.w3.org/1999/xlink";
Element elem = svgDocument.createElement("use");
elem.setAttribute("id", "m2");
elem.setAttribute("x", "100");
elem.setAttribute("y", "100");
elem.setAttribute("width", "100");
elem.setAttribute("height", "100");
elem.setAttributeNS(xlinkNS, "href", "#message");
SVGElement g1 = new SVGElement(svgDocument.getElementById("root").Object);
g1.appendChild(elem);
- 多重消息处理
在JS和C#中可以同时定义消息处理函数,其处理流程待查。例如在JS中定义οnmοusedοwn="grab(evt)" οnmοusemοve="drag(evt)" οnmοuseup="drop(evt)",在C#中
svgRoot.addEventListener("mousedown", this, false);
public void handleEvent(object evt) {
MouseEvent e = new MouseEvent(evt);
if (e.button == 2)
{
e.preventDefault();
contextMenuStrip1.Show(ASV, e.screenX, e.screenY);
}
else if (e.button == 0)
{
SVGElement elem = new SVGElement(e.target.Object);
String[] value ={"id", elem.getAttribute("id")};
showProperty(value);
}
以上代码能够实现屏蔽ASV缺省右键菜单,并显示C#右键菜单,而左键不仅能够拖动,而且能够在属性窗口中显示选中图形的属性。
- 在C#中使用getElementById判断是否存在重复元素时,不能使用elem == null作为判断条件,而应使用elem.Object == null
Element elem = svgDocument.getElementById(newId);
if(elem == null)
break; //Never happen
正确方法:
if(elem.Object == null)
break;