4.内嵌 IE 方案

4.1 纯 ppapi 的局限

硕正组件的功能中，有二个功能在 ppapi 插件环境下是无法实现：
1).反向调用页面 js, 受影响的在线演示例子如树列表的 “27.过滤 ” 中的 js()、硕正报表的 “10.自定义函数”;
2).事件是 post 的, 所以无法和 js 逻辑严格同步, 导致硕正全局函数 CancelEvent( ) 不起作用、以及导致树列表的例子 “26.自定义右键菜单 ”、报表的例子 “9.自定义工具条、自定义右键菜单” 无法正常弹出自定义的右键菜单, 这2个例子用到了 "MenuBeforePopup" 事件, 由于该事件在 ppapi 中只能异步发给页面, 主线程不阻塞, 不等你作出回应, 右键菜单已经弹出了;

4.2 何为内嵌 IE

如果您的 B/S 应用必须要使用上述的这二个功能, 您可以选择使用另一个方案：内嵌 IE 内核.
微软的 IE 浏览器，其底层是一个 ocx 控件, 即 “Microsoft Web Browser” 或 “Microsoft HTML Viewer”, 您在注册表中可以查到, 假如您精通 C# WinForm 或 VC、Delphi，想必不会对此陌生, 它能够被嵌入到其他 Windows 进程中。 我们在实现 ppapi 的开发过程中，在其内部增加了一个 ocx 的容器子窗口，可以让您的页面在插件内部的 IE 控件中运行！
著名的国产软件金格软件，也是以这种方式实现 MS Office 在 Chrome 中展现的.
本方案的原理模型示意图为：
这种方案，需要 2 个页面来实现，外部的 Chrome 页面，只含有一个硕正 ppapi 插件, 让插件满幅显示; 其内部展现的是另一个页面：就是你真正想要的页面.
内部页面的工作环境是 IE，所以不必考虑 ppapi 因素。

4.3 实现细节

硕正官网的在线演示是双工的, “纯 ppapi” 模式 和 “内嵌 IE” 模式都支持, 在顶部备有下拉选择, 可以随时切换运行模式.
下面我们来分析一下在线演示的一些技术细节, 内嵌 IE 的 “外部文件” 是根目录下的 ppapi-ie.htm。
首先, 打开具体的某一个演示页, 都是由一小段 js 发起的, 以 Treelist 树列表为例, 请打开根目录下 top_treelist.htm 文件, 在文件的中间部分有一个 function navCur() 函数, 请看:

    #65#function navCur()
    {
     ..//略

    #75# var url = 't' + (cur+1) + '.htm?107';    //所谓 “内部页面” 的 URL
     if($B.ppapi) {
      if(document.getElementById('ppapiMode').value == "ie") url = 'ppapi-ie.htm?' + url;  //下拉选择 纯ppapi模式 或 内嵌IE模式
     }
     window.parent.document.getElementById('ContentPage').src = url;  //打开演示页
    }

上面第 76、77 行是关键, 如果当前浏览器是 IE 或 npapi, 就不需要 “外部页面” 了，直接打开最终的 “内部页面” ; 否则就根据 <select> 下拉的选择, 如果您是选择了内嵌 IE, 则打开 “外部页面” , 并把 “内部页面” 的 URL 传递给它, 让它去处理.
接下来我们看看 “外部页面” ppapi-ie.htm 是如何工作的：

    <html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=GB2312">
    <script language="JavaScript">
    //该句相当于是 jquery 的 $(document).ready
    document.addEventListener("DOMContentLoaded", addListener, false);
    //为 pp 对象添加侦听
    function addListener() {
     pp.addEventListener('message', handleMessage, false);
    }
    //ppapi对象的事件侦听
    function handleMessage(message)
    {
     if(message.data.name == "OnReady")
     {
      //URL拼装，比如把 "http://localhost/ppapi.htm?report1.htm" 转换成为 "http://localhost/report1.htm"
      var search = window.location.search;
      var url = window.location.href;
      url = url.substr(0, url.length - search.length);
      var n = url.lastIndexOf('/');
      if(n > 0) url = url.substr(0, n + 1);
      url += search.substr(1);
      //main: 插件的IE内核打开页面
      pp.postMessage( {func: 'Goto', para: url } );
     }
    }
    </script>
    </head>

    <body leftMargin="0" topMargin="0" rightMargin="0" bottomMargin="0" scroll=no style="overflow:hidden">
     <object id="pp" type="application/x-ppapi-supcan" Core="IE" isSilent="false" width="100%" height="100%">
      插件加载失败, 原因可能为：<br>
      1.硕正 ppapi 插件未正确安装;<br>
      2.当前 Chrome 不支持 ppapi, 请用高版本的 Chrome 浏览器
     </object>
    </body>
    </html>

页面不复杂, 有几处需要说明一下.
1.Body 内就一个 <object> 插件, 没有其它元素, Body不需要滚动条, 边界统统设为0, 这样插件就满幅显示了;
2.<object> ... </object> 这中间的文字，是在插件创建失败才显示的;
3.<object> 中的 Core="IE"，表示插件以内嵌 IE 方式运行;
4.插件创建完毕，会触发 OnReady 事件的, 所以要尽早侦听, 在页面加载完毕后马上要给插件添加侦听 (addEventListener);
5.在 OnReady 事件中，无非就是拆解、拼装出 “内部页面” 的 URL, 然后执行插件的 Goto 函数，让插件内部的 IE 控件去加载页面.