不知是什么原因Richfaces控件在IE下速度特别的慢.在IE8下时有部分控件甚至会出现问题只能用兼容模式下使用.在网上找找了发现很多人有这问题.不知道Richfaces4.0会不会好一点,但richfaces4.0只能在JSF2.0上运行所以我也没办法试.就在网上找了点优化的方法,
如下:
http://feidaodalian.javaeye.com/blog/435779
虽然有点效果但是还是很慢,特别是那个datatable在数据多不分页时特别慢.所以看来项目还是要少用Richfaces的组件多使用H的标准组件,但是我的项目中已大量使用了Rich组件要改也不太现实了.但是Rihcfaces组件在firefox或chrome下确是非常快的(不解).所以只好推荐客户使用firefox还使用系统.但是问题又来了.我的项目中使用了很多ACTIVEX控件来使用本地硬件设备.而firefox是不支持Activex控件的(上网上找了很多使firefox支持Activex控件的方法都不好用).要想使用客户端本地资源要使用firefox的插件才行,
- 使用Delphi开发firefox插件
所以问题就转到了火狐插件开发上.我之前所有的ActiveX控件都是使用Delphi开发的.使用Delphi开发ActiveX插件非常之方便,所以一开始我就想到是不是也可以用Delphi来开发firefox插件.就上网找了一下,别说还真就找到了,有老外把Mozilla的插件接口用Delphi翻译了一下.还提供了一下例子下载,地址如下: (由于伟大的长城防火墙的存在,需要使用一个代理还翻墙才能访问)
http://ftp.newbielabs.com/Delphi%20Mozilla%20Plugin/Readme.htm
可以下载两个Zip包:nplug.zip和SamplePlugin.zip和一个readme文件.其中SamplePlugin.zip是一个完整的例子.可以直接编译后发生成的文件放到firefox的plug目录中去运行(具体查看readme),而nplug.zip中只有一个plugAPI.pas大概是新版的插件api,readme中说要创建自己的应用就使用这个plugAPI.pas替换SamplePlugin.zip中的api文件来建立项目.
关与firefox插件开发的知识可以到Mozilla 的MDC官网去看英文的.中文的没有,但发现了一个blog上写了不少,地址如下:
http://www.cppblog.com/epubcn/category/8842.html(重要的是方法的调用顺序及方法)
经过对这两个包的研究后我发现了一些问题在这里列出来:
1.用plugAPI.pas替换后例子是可以运行的.但是需要改下注册form的方法(参数和原来不同了),并在onCreate中加入self.show;才行,但是在关闭firefox时会报错导制firefox崩溃,大概是有内存泄露问题,我也没有仔细去找,因为不替换的话是可以使用的,
2.在使用delphi2007以上(包括2010)的版本编译的时候得到的插件参数是乱码,这应该和2007以后dehpi使用UNICODE有关,如果你确实想得到插件参数的话用delphi7或2007等未使用UNICODE的版本来编译就正常了.
3.这个例子中对form的释放有问题,症状是:你用firefox打开包含你的插件的页面后不关闭firefox而是只关闭你的页面,再用firefox打开这个页点上面的控件时,firefox会出错误提示:无效的句柄...
在分析了firefox插件的调用过程后发现是这样的:
firefox 在首次加载时会调用dll中的NP_Initialize和NP_GetEntryPoints方法来初始化插件并得到插件的入口函数,在加载你的插件时会调用NPP_NEW来建立你的插件,之后会调npp_setWindow来设置你的窗口(两个zip包中这里不同,SamplePlugin.zip中的例子是在NPP_NEW时Create的form而另一个是在NPP_SetWindow时Create的,所以后者要Show一下),但是当你关闭你的页时firefox会调用NPP_Destroy来释放资源,只有你在关闭firefox时才会调用NP_Shutdown,而经过我查看代码后发现例子中的NPP_Destroy方法只是释放了TPlugin而并没用释放form,所以在你再次打开这个页时又调用NPP_NEW来Create这个form时内存中就存在了两个form这个firefox在对form发关window消息时就找不到之前那个form的句柄了.
找到了原因,就可以解决这个问题了.在NPPlugin中建立一个全局变量来存储你的form,然后在NPP_Destroy时利用这个全局变量来free这个form,问题就解决了.
4.这个例子有个致命的问题就是无法与页面的javaScript交互.也就是说你只能在页面上显示一个窗体来做所有的事情,而不能把结果返回给js,也不能通过js控制你的插件行为,就因为这个问题所以我后来只好使用VC来开发我的插件,但是如果你的插件无须与js交互,就可以使用Delphi来开发,具体的问题如下:
(1).要想firefox插件与js交互的话那就就要在NP_GetEntryPoints时提供NPP_GetValue方法来建立交互,但是这个例子就没就做这方面的工作,我也试着将官方C++的API代码来翻译成Delphi的以实现这个功能,但是发现C++的API要使用一个xulrunner-sdk的开发包.要想加入这个功能就必须包这个包中的大量C++代码翻译成Delphi的.工作量实在是太太了.
(2).我还想到另外一个办法就是在NP_GetEntryPoints中返回结构体中直接加入我的js交互方法,而不使用NPP_GetValue来实现与js的交互.但是经我实验后发现,这么做在SamplePlugin.zip(另一个无效)中的确可以调到方法中的功能,但是调用完成后方法不返回,好像是卡在什么地方了.后来经过多次实验均未成功.
另外发布时要改一下MIMETYPE这个相当于Activex的clsID,先改rc文件,然后用brcc32.exe来生成res文件,再重新编译项目就行了
- 用VC++开发firefox插件
由于我的插件须要与js交互,所以用delphi是不行了.只好老老实实的用C++来写了.C++的资料就比较多了.(我用的是vs2008)
先是下载和编译官方的例子,引用一下,官方原文:
https://developer.mozilla.org/en/Compiling_The_npruntime_Sample_Plugin_in_Visual_Studio
有人翻译过来的:
http://www.cnblogs.com/eping/archive/2010/10/06/1844575.html
我是按原文做的.不知道翻译过来是不是不漏了什么,有一次我按翻译做的,但是不成功(也可能是我自己漏了什么),
然后在这个例子中加入自己的方法就可以了.也引用几个文章来说下开发过程:
http://nick.workao.org/index.php/date/2010/05/21
http://nick.workao.org/index.php/other/56
http://www.cppblog.com/epubcn/category/8842.html
总之编译很简单,很容易就过了.但是这个例子也有问题(大概是太老了),还有一些在使用时要注意的问题,这里我说下:
1.关与开发后在自己的机器上好用.但在别的电脑上就不能用的问题,出现这个问题可能有两个原因:
(1)一定要用release版本,Debug的不成.
(2)例子中的返回值方法在windows2003以下版本(如xp)的操作系统上是错误的,而在windows2003及以上(如vista)是可以的,要想在所有的系统上都好用那就是修改一下了.把原来的返回值方法如:
改为
就可以在所有系统中运行了.
2.返回的类型,由于返回值要NPVariant的所以所有类型都要调用API转一下如:
STRINGZ_TO_NPVARIANT
OBJECT_TO_NPVARIANT
VOID_TO_NPVARIANT
INT32_TO_NPVARIANT
BOOLEAN_TO_NPVARIANT
DOUBLE_TO_NPVARINAT
返回字符串时要将串转成utf8的如:
但是没有Long类型的转换,所以我只好都用的INT32_TO_NPVARIANT或DOUBLE_TO_NPVARINAT来处理Long类型的
3.取得js的参数
使用的方法和返回正好反过来,不过字符串要转换一下.
4.调用ocx组件
由于很多功能我都做成的ocx的.所以没必要再写一次,直接用C++的智能指针调用已写好的Activex组件就好了(关于C++的智能指针网上查一下资料很多).但是又有很多类型转换问题:
_variant_t 类型字符串的返回:
bstr_t ,int32和bool类型的可直接返回;
另外,使用firefox插件调用Activex插件时并不会保存Activex插件的状态.如我在A方法中改变了activeX的一变量,当用B方法来读这个变量里,A方法中的改变并未生效,可能是在调B方法时又重新创建了这个Activex控件,这个应该是可以避免的,但是由于我不需要这样的功能所以也没有仔细研究.希望有知道的大侠来说明一下.
5.关于异常处理,由于我要封装的Activex插件会在某些情况下抛出异常,再由js的try..catch来处理,本着不改变原有js的原则,所以我的firefox插件也要抛出异常,但是如果在插件代码中直接抛出异常,会导至firefox 直接崩溃,那怎么样才会使插件抛出能被js捕获的异常呢,其实很简单只要在 Invoke方法中捕获原异常后返回PR_FALSE,如return PR_FALSE;就会抛出能被js捕获的异常了.
引用一个标准C++异常处理的文章:
http://hi.baidu.com/micfree/blog/item/32dad589cc7f14be0f244437.html
6.js 的调用
这里就很简单了.先用js判断一下浏览器的类型,是ie就创建activex返之就建embed
另不要忘记了改MIMETYPE哦...就在nprt.rc中..这个相当于ocx的clsid