1.关于

硕正轻量级富Web应用套件(以下简称“硕正套件”)是运行在客户端的Web插件集。该插件集包含了硕正树列表、自由表头、报表、打印、统计图等一系列插件，用以弥补Web页面在这些方面的欠缺、方便程序员开发基于Web的企业应用、提升B/S类应用程序的总体可用性。
对于最终用户而言，硕正套件相当于是一个页面插件；对于程序员而言，硕正套件又相当于是一套辅助性的开发工具、可编程和可操控的控件。
硕正套件本身和服务器的规格无关，但是必须部署在服务器，由服务器提供下载。硕正套件支持包括Tomcat、IIS、JBoss、WebSphere在内的所有Web服务器。
硕正套件只能用于浏览器客户端，支持 Google(Chrome)、IE、FireFox(火狐) 三大浏览器。对于Chrome、Firefox而言，硕正套件是一个符合 Mozilla NPAPI 规范的Plug-in插件；对于IE而言，硕正套件则是一个标准的ActiveX控件。
硕正套件的客户端操作系统支持Win 2000以后(包括Win 2000)的所有Windows系列，尤其以WinXP、Windows 7为佳。
硕正套件是以C/C++开发的，在纯净的Windows下就能运行，不需要诸如.NET、Java的支撑环境。
硕正套件功能强大而尺寸奇小，总下载量才 1MB 多一点(包括插件/加载项在内的所有组件, 注：64位版是1.8MB)。
硕正套件有一套平滑的版本升级机制，由于体积小使得升级快速，免除了手工安装升级的麻烦。
硕正套件内核采用Unicode编码，内置文字包含中文简、繁体(BIG5)、英文，且支持动态切换，满足了国际化应用的需求。
硕正套件同时提供32位/64位程序包，支持64位操作系统(如 Win2003 x64/Windows 7 x64)中的64位浏览器运行。
硕正套件的FireFox插件和IE加载项经国际著名的VeriSign公司代码签名，能确保本产品安全无阻地下载、运行。
硕正套件是经过中华人民共和国版权局登记的自主版权软件产品，著作权人为杭州硕正软件有限公司。
硕正套件充分吸收了PowerBuilder Datawindow、ExtJS、DevExpress、Delphi等开发工具的设计思想，由经验丰富的 C/C++ 开发人员开发而成。硕正套件经已成功应用于多家大型企业、跨国软件公司，经受住 了成千上万的最终用户的考验，很少发生由于内存泄漏或其它原因导致浏览器崩溃，事实证明硕正套件稳定坚固，安全可靠。
为了方便开发和使用，硕正公司将本网站的大部分资料压缩成zip包并提供下载，网站中的"在线演示"演示了硕正套件功能的方方面面，这些演示页大多是静态页面，并且每个页面都非常简洁，大多为3、5k，便于开发者研究、参考。
2.安装

1.首先从硕正网站下载一个可独立安装的网站 zip 包，该包是安装到 Web 服务器的，Web 服务器可以选择 Apache Tomcat、微软的 IIS、或其它服务器产品。
2.然后，配置Web服务器：增加二种 MIME 映射：

extension | mime-type
xpi | application/x-xpinstall
crx | application/x-chrome-extension

如果不增加这 2 个 MIME，FireFox 和 Chrome浏览器将无法下载、安装插件。
3.解开 Zip 包，把 zip 包解压到虚拟目录即可。如果服务器采用 Tomcat，只要把该包直接解压到 webapps 下的某个目录即可；如果是 IIS 服务器，也只需解压、创建虚拟目录而已。
4.此外，如果您的应用中需要用到条形码的功能，那么您还必须到 www.supcan.cn 的下载区的“其它第三方组件”栏去下载条形码的 zip 包，解开该 zip 文件，把里面的 binary 目录下的所有文件拷贝到前面的 binary 目录即可。
至此，通过浏览器访问Web服务器，您就能感受硕正轻量级富Web应用套件了。浏览器能够自动从服务器下载、安装本产品，安装的过程将非常方便，除了首次下载时有一个“安装缺失插件”(在IE下是“需要安装以下加载项...”)的安全警告，不需要其它任何干预。
如果服务器是JBoss，虚拟目录名的后缀须为".war";
在Win2000的IIS下，需要将文件index.htm改名为default.htm
3.集成部署

所谓“集成部署”是指将硕正套件集成到您开发的Web应用中、连同您的应用一起发布。
解开zip包，会发现里面除了大量演示用的Html页面和静态的xml数据，真正的核心都在 binary 目录中，这些文件用途说明如下：

| 文件名 | 用途 | 文件尺寸
核心包 | supcan.xpi | 用于浏览器的Plug-in插件 | 110k
supcan.crx | 用于浏览器的Plug-in插件 | 120k
supcan2.cab | 用于浏览器的加载项 | 120k
supcan2.x64.cab | 用于64位 浏览器的加载项 | 140k
BCV1.bin | 硕正树列表、自由表头等基础功能组件 (7z压缩包) | 680k
LuxForm.bin | 硕正报表组件 (7z压缩包) | 420k
License.bin | 授权证书包 | 1k
可选包 | BCV4.bin | 硕正Freeform设计器 (7z压缩包) | 60k
gzip.bin | 让硕正套件能读取后端gzip压缩后的数据 注：首次使用时能自动下载 | 16k
msoffice.bin | 用于读写Excel 2007 注：首次使用时能自动下载 | 50k
LuxFormC.bin | 用于Report的申报模式 注：首次使用时能自动下载 | 30k
WebFile.bin | 用于文件的上传下载 注：首次使用时能自动下载 | 20k
barcode.cab | 用于显示条形码 注1：首次使用时能自动下载； 注2：该文件不在zip包中, 需要您单独到 www.supcan.cn 下载区的 "其它第三方功能组件" 中去下载, 再将其部署到binary目录; 注3.条形码功能不支持64位浏览器; | 1.1M
64位包 | 同名的 *.x64.bin | 用于64位IE浏览器 | 约1.7M

只要将 binary 子目录和 doc 子目录复制到您的 Web 虚拟目录即可。doc 子目录主要是一些在线帮助的内容，最终用户在使用硕正套件过程中可能需要浏览。
此外，binary 目录中还包含了一个 dynaload.js 文件， 该 js 的作用将会在下面作进一步分析。
doc 须整个子目录拷贝走，相对目录须 bin 文件所在的子目录并列；
部署到其它服务器时，别忘了配置 MIME 类型.
4.原理

硕正套件是浏览器的插件或加载项，以<Object ...>形式展现于页面，而<Object ...>的书写格式在IE下和FireFox下是有差别的.
对于、浏览器，将会自动分别下载 supcan.xpi、supcan.crx插件，该插件的type为：
application/supcan-plugin
对于浏览器，下载的是 supcan2.cab 加载项(即ActiveX)，其CLSID为：
619F1AC0-2644-40D3-9EB1-22F81C5FE097
对于64位 浏览器，下载的是 supcan2.x64.cab 加载项(即ActiveX)，其CLSID为：
11249C26-4BCD-4A74-B4D9-068936D77EFE
当浏览器发现页面<Object ...>中的这个type或CLSID尚未安装过，它将自动从服务器下载xpi、crx或cab文件，并自动安装之。
supcan的xpi、crx插件或cab加载项的文件尺寸很小，大约100多k。 硕正套件真正的主角：一系列的功能组件并不在这个文件中，而是在几个独立的Bin压缩包中，这些组件是由该插件/加载项负责进行再一次的下载、安装的。
插件/加载项只是实现以下几个简单的功能：
1.下载、更新功能组件;
2.充当功能组件的容器;
3.与页面交互;
也就是说，该插件/加载项相当于是页面和功能组件之间的接口或桥梁，它将组件功能暴露给页面、供页面 JavaScript 操控。其原理图如下:
一个页面内可能有多个插件/加载项实例，每个插件/加载项实例中有一个功能组件的实例，页面、插件/加载项与功能组件的关系又可以以下图示例：
今后 supcan.xpi、supcan.crx、supcan2.cab 这些加载项将尽可能不升级，而一系列功能组件却可以在用户没有感觉的情况下升级，甚至是较频繁地升级，这就是采用这种设计框架的原因。
5.页面语法

FireFox/Chrome的Plug-in插件 和 IE的ActiveX加载项 在页面中的基本语法如下，使用时1、2、3、4行只能选其一，且将其中的"?"改成所需的值即可：

    <Object id=? width=? height=? type="application/supcan-plugin" Codebase="supcan.xpi">
    <Object id=? width=? height=? type="application/supcan-plugin" Codebase="supcan.crx">
    <Object id=? width=? height=? CLASSID="clsid:619F1AC0-2644-40D3-9EB1-22F81C5FE097" Codebase="supcan2.cab#Version=1,0,0,3">
    (64位)<Object id=? width=? height=? CLASSID="clsid:11249C26-4BCD-4A74-B4D9-068936D77EFE" Codebase="supcan2.x64.cab#Version=1,0,0,3">
     <Param name="CtlName" value="?">
     <Param name="CtlVersion" value="?">
     <Param name="ZipUrl" value="?">
     <Param name="CtlPara" value="?">
     <Param name="DownloadOnly" value="?">
     <Param name="Cookie" value="?">   //for 、Only
     <Param name="id" value="?">   //for Only
    </Object>

第1、2、3、4行中的 Codebase 是 xpi包 / crx包 / cab包的URL，可以是绝对URL，也可以是当前页面的相对URL;
Param的各个 Name-Value对 的含义说明如下：

参数名 | 含义 | 可用值 | 默认值
CtlName | 功能组件名 | 取决于具体组件的规范 |
CtlVersion | 组件版本号。版本号很重要，决定了功能组件的自动升级更新。 | 诸如“1.0.1.0”等，以“.”分隔 |
ZipUrl | 组件所在的压缩包的URL，多个URL之间以逗号分隔。 即告诉插件/加载项，到哪里去下载组件包 | 可以是绝对URL，也可以是相对URL |
CtlPara | 初始参数。即告诉插件/加载项，如何创建功能组件实例。 | 取决于具体组件的规范 |
DownloadOnly | 是否仅仅下载组件。如果仅是下载，那么将不创建组件实例。 该参数不太常用. | 1/0 - 是/否 | 0
Cookie | 用于、，使得插件和功能组件向服务器发送的Http请求能和页面共享同一个Session，保证了数据传输的安全。 备注：IE浏览器中的加载项和组件肯定能和页面共享Session，故不需要此参数 | 通常为document.cookie |
id | 用于，告诉加载项当前实例的id. 备注：FireFox、Chrome插件能通过NPAPI取得<object id=...>中的id，故不需要此参数 | 必须和<object id=? ...>一致 |

页面中有了这个<Object>后，浏览器会自动下载、安装、加载这个加载项/插件，然后，加载项/插件会进一步下载功能组件的Bin包、并将其解压到 \Documents and Settings\[用户名]\BC*目录下 (注：Windows7是 用户\[用户名]\BC*目录)，然后加载该组件、创建该组件的实例、并在浏览器的指定区域中展现。
6.简化开发

为了方便使用硕正套件，开发者可以考虑使用Zip包中根目录下的 dynaload.js 小程序，这样就不必在页面中书写上述烦人的<object ... >了。该 js 小程序封装了页面调用插件、识别浏览器类型、动态下载和创建组件实例的过程，本Demo网站中的所有演示页均调用了该js，其源码非常简单：

    //区分浏览器(Firefox / Chrome / IEx86 / IEx64)
    var $agnt=navigator.userAgent.toLowerCase();
    var $isChrome = false, $is64 = false;
    var $isIE = ($agnt.indexOf("msie")>0) ? true : false;
    if($isIE) {
     if($agnt.indexOf("win64")>=0 || $agnt.indexOf("x64")>=0) $is64 = true;
    }
    else {
     if($agnt.indexOf("chrome")>0) $isChrome = true;
    }

    //private:
    function bldStr(ctlType, id, para)
    {
     //!!!!组件版本号，升级后须修改!!!
     var ctlver = '1.0.75.0';

     //取得组件包的绝对路径(假设和dynaload.js部署在同一个目录)
     var SupcanPath="", arrScript = document.getElementsByTagName("script");
     for(var i=0; i<arrScript.length; i++) {
      var src = arrScript[i].src;
      var index = src.indexOf('dynaload.js');		//假设dynaload.js文件名没变
      if(index >= 0) {
       SupcanPath = src.substring(0, index);
       if(SupcanPath.charAt(0) == '/') {
        src = location.href;
        index = src.indexOf('//');
        if(index != -1) {
         index = src.indexOf('/', index+2);
         if(index != -1) src = src.substring(0, index);
         SupcanPath = src + SupcanPath;
        }
       }
       break;
      }
     }

     var typeid;
     if($isIE) {
      if($is64)
       typeid = 'CLASSID="clsid:11249C26-4BCD-4A74-B4D9-068936D77EFE" Codebase="' +SupcanPath+ 'supcan2.x64.cab#Version=1,0,0,3"';
      else
       typeid = 'CLASSID="clsid:619F1AC0-2644-40D3-9EB1-22F81C5FE097" Codebase="' +SupcanPath+ 'supcan2.cab#Version=1,0,0,3"';
     }
     else {
      typeid = 'type="application/supcan-plugin"';
      if($isChrome==false) typeid += ' Codebase="' +SupcanPath+ 'supcan.xpi"';
     }

     //组件包URL
     var zipurl = SupcanPath + ($is64 ? "BCV1.x64.bin" : "BCV1.bin");
     if(ctlType=="LuxForm")
      zipurl += "," +SupcanPath+ ($is64 ? "LuxForm.x64.bin" : "LuxForm.bin");
     else if(ctlType.indexOf("BCV4")>=0)
      zipurl += "," +SupcanPath+ ($is64 ? "BCV4.x64.bin" : "BCV4.bin");

     var str = '<Object id=' +id+ ' Width=100% height=100% ' +typeid+ '>';
     str += '<param Name="CtlName" Value="' +ctlType+ '">';
     str += '<param Name="CtlVersion" Value="' +ctlver+ '">';
     str += '<param Name="ZipUrl" Value="' +zipurl+ '">';
     str += '<param Name="id" Value="' +id+ '">';
     str += '<param Name="Cookie" Value="' +document.cookie+ '">';
     str += '<param Name="CtlPara" Value="' +para+ '"></Object>';
     return str;
    }

    //public:
    function insertTreeList(id, para)	{ document.write( bldStr("BCV1.TreeList",id, para) ) }
    function insertEdit(id, para)		{ document.write( bldStr("BCV1.Edit",	 id, para) ) }
    function insertReport(id, para)		{ document.write( bldStr("LuxForm",	 id, para) ) }
    function insertTree(id, para)		{ document.write( bldStr("BCV1.Tree",	 id, para) ) }
    function insertFreeForm(id, para)	{ document.write( bldStr("BCV1.FreeForm",id, para) ) }
    function insertChart(id, para)		{ document.write( bldStr("BCV1.Chart",	 id, para) ) }
    function insertUpload(id, para)		{ document.write( bldStr("BCV1.Upload",  id, para) ) }
    function insertFormDesigner(id, para)	{ document.write( bldStr("BCV4.FormDesigner",id, para) ) }

    //必需的函数(控件会反向调用，用途:切换焦点)
    function focusIE(obj_or_id)
    {
     if($isIE==false) {
      document.activeElement.blur();
      return;
     }
     try {
      if(typeof(obj_or_id)=='object') {
       if(document.activeElement != obj_or_id) obj_or_id.focus();
      }
      else {
       if(document.activeElement.id == obj_or_id) return;
       var o = document.getElementById(obj_or_id);
       if(o != null) o.focus();
      }
     }
     catch(e) {
     }
    }

相信您一看就能明白，在页面中只要调用从65到72行之间的任一函数就行，这几个函数都只有2个参数:id、para，参数id就是<object id=...>中的id值，参数para就是名为CtlPara的<Param>的值。
第16行中的版本号，该版本号是自动升级的关键.
其中的 focusIE( ) 是必需的，你可能永远不会去调用它，但是组件会去反向调用它的.
如下就是一个引用了 dynaload.js 的完整的demo页：

    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=GB2312">

    <!--引用dynaload.js。后面的"?20"是让浏览器及时刷新的时间戳，请参见“常见问题解答”-->
    <script type='text/javascript' src='binary/dynaload.js?20'></script>

    </head>
    <body>
    <script>insertReport('AF', '')</script>	//AF是Object的id号、第二个参数为空表示没有初始参数
    </body>
    </html>

你将在页面上看到一个空的硕正报表，一切就那么简单!
如果您是用Java EE、ASP.Net开发的，把上面的 html 文件修改成 jsp 或 aspx 应该是轻而易举的事.
在开发页面过程中，可能经常会把 插件/加载项 安置在<Table>的一个<td>中，例如:

    ...
    <tr height="400">
     <td height="400">
      <script>insertReport('AF', '')</script>
     </td>
    </tr>
    ...

1.要求显式定义<tr>的 height 高度，如同上例.
2.在IE 10浏览器中，<td>都需要显式定义 height 高度.
也可以安置在<div>中，由<div>控制其位置和尺寸, 例如:

    <div style="position:relative;width:96%;height:400px">
        <script>insertReport('AF', '')</script>
    </div>

<div>的 width 可以用px单位，也可以用百分比;
<div>的 height高度必须用px单位，如同上例， 千万不要用百分比, 否则会出现奇怪的现象，比如控件经常会显示不出来.
如果您把 插件/加载项 安置在<Form>中，在IE下可能会遇到问题，请参见底下的“9.不同浏览器之间的一些差别”.
7.函数

插件/加载项可供 js 使用的函数只有1个：

string func(string funcname, string para); 参数funcname：字符串，是组件的真正的函数名，请参见具体组件的规范; 参数para：字符串，参数，如果组件需要传入多个参数，那么以回车符(\r\n)分隔，请参见具体组件的规范; 返回值：字符串，具体含义请参见组件的规范;

插件/加载项本身并不执行这个函数，真正执行该函数的是具体的功能组件，插件/加载项只是把函数传递给组件、将组件的返回值再传回给js，函数的js用法举例如下：

    //要求组件执行print('A', 'B', 'C')函数，并将返回值赋给变量 s
    var s=AF.func("print", "A\r\nB\r\nC");
    //注1: AF为组件的id(<Object id=? ...>)，在Firefox/Chrome中没有必要采用document.getElementById('AF')；
    //注2: para参数中A、B、C以回车分隔，表示实际传递了3个参数;

功能组件的函数是很丰富的，在各自的文档中有详细的介绍，在此不作叙述。
8.事件

所谓“事件”是指组件执行某个动作(如鼠标单击、内容有输入)后会以某种方式通知页面，使页面执行一段相应的js。
事件有2个：OnReady 和 OnEvent.
OnReady事件是指功能组件的实例已经成功创建后，插件/加载项通知页面的事件，这样页面js就可对其作进一步的操控，例如加载数据。当然在<body>的 onLoad( ) 事件中也可以对组件进行操控，但是我们强烈建议不要写在onLoad()事件中，因为在 onLoad( ) 事件执行时，组件实例未必已创建。
OnEvent事件是由功能组件的某个动作触发的，例如鼠标、键盘、状态变化等，在何时抛出事件、以及事件的各个参数的含义请参考功能组件各自的文档。
事件的书写规则举例如下：

    <script>
    //OnReady 事件
    //id参数说明：如果页面中有多个插件/加载项，那么OnReady事件会被触发多次，id就是插件/加载项的id
    function OnReady( id )
    {
     //假如执行如下js
     if(id=='AF') AF.func('ReadXML', 'index.XML');
    }

    //OnEvent 事件
    //OnEvent参数说明: “Event”为事件名，p1,p2,p3,p4参数有特定的含义，由具体的功能组件规定.
    function OnEvent(id, Event, p1, p2, p3, p4)
    {
     //假如执行如下js
     if(id=='AF' && Event == "SelChanged") document.getElementById('Page1').src=p2;
    }
    </script>

对上例稍加分析，你会发现所谓“事件”只是普通的页面 js 函数，只不过这二个函数名被硕正插件/加载项占用了，当组件触发事件时，实际上就是由插件/加载项反向调用页面的 js 函数而已!
事件的语法规则、以及上述示例，、和是没有差别的。
9.不同浏览器之间的一些差别

硕正套件对FireFox、Chrome和IE的支持存在着一些细微的差别，目前已发现的差别如下：
1.FireFox/Chrome的 HTML 页面必须要有<meta ... >的文字编码声明，例如:

    <meta http-equiv="content-type" content="text/html; charset=gb2312">
    //或
    <meta http-equiv="content-type" content="text/html; charset=utf-8">

否则页面调用插件的函数时，参数中的中文很可能会变成乱码.
2.如果您将 插件/加载项 安置在<Form>中，在Firefox和Chrome下没问题，但在IE中针对控件的js会有问题，例如:

    ...
    function OnReady(id)
    {
     AF.func("Build", "g1.xml");
    }
    ...
    <form name="form1">
        <script>insertReport('AF', '')</script>
    </form>
    ...

IE执行到第4行会抛出 'AF'未定义的错误，此时改成如下写法就能成功：

    ...
    function OnReady(id)
    {
     form1.AF.func("Build", "g1.xml");
    }
    ...

当然，您也可以把 上面insertReport( )的语句移出form，这样就不会有这个问题了。
3.如果你的页面很长(指高度)，比如需要垂直滚动条, 如果插件一开始是隐藏在底部的，需要拖动滚动条才能显现，那么在IE中，插件是在初次显现时才会触发OnReady( )事件的!
4.FireFox、Chrome页面中，插件无法感知页面上下文的字体，主要受影响的是Edit组件;
10.硕正套件的一些限制

硕正套件的功能决非无懈可击，目前存在着如下限制(或问题)：
1.硕正套件相当于是客户端的中间件，它的宿主环境是浏览器，不支持C/S模式(硕正套件的C/S版需要另外购买)；
2.硕正套件可以部署在任何软硬件的服务器上，但它的最终运行的操作系统环境是微软的Windows，而无法在Linux桌面、苹果操作系统、或手机终端下运行；
3.硕正套件在浏览器中是插件/加载项，它是一个子窗口，始终位于浏览器窗口的最前方，所以在常规开发中，它无法被页面的 div 覆盖，由此会造成 div 图层反而会被硕正套件遮挡的现象，其实浏览器控件几乎都有这个问题。但硕正套件提供了如下几种解决方案；
1.采用“树列表”的在线演示页“33.遮罩效果”中的方案，通过一个开源的第三方js包实现遮罩；
2.js的 div 菜单肯定会被硕正套件遮挡，为此建议用"自由表头"组件制作工具条和菜单代替div菜单，"自由表头"中的菜单是真正的Windows菜单，它不会被遮挡的。具体的例子在“自由表头”演示页“5.事件、按钮、菜单、工具条”、“6.动态更改属性(1)”中；
4.硕正套件中的表格(包括树列表和报表)的最大行列数，从理论上支持大约50万行、700列，但实际运行中往往受制于内存的限制而达不到这个极限；
5.硕正套件转换成Excel文件输出、或从xlsx读入时，由于套件无法全部包容Excel的格式和函数，可能会出现格式或数据不正确的现象。我们今后会不断逐步地去完善，但此现象不应该被认作是bug；