一.Netscape Plugin Interface(NPAPI)javascript
大体的说明能够看下官方文档Pluginhtml
本文主要针对于JavaScript与插件交互部分作一些交流,好比用于数字证书的操做(淘宝和支付宝的插件),用于播放的flash player插件等java
与javascript的交互须要用到NPAPI中的npruntime Scripting pluginsgit
下面的部分将以示例的方式说明整个过程如何去实现github
在开始前须要从火狐浏览器源代码中获取接口头文件火狐4.0.1源码下载docker
下载后在\firefox-4.0.1.source\mozilla-2.0\modules\plugin能够找到一些samples和头文件windows
这里为方便下载,上传了一份单独的plugin文件夹api
另外,基于NPAPI的一个跨浏览器插件开发的框架FireBreath,很是容易上手并且听说跨浏览器的支持很是好,可是很是笨重,有些功能不须要的也不太容易去掉数组
Firebreath,有兴趣的能够去了解下,Firebreath的源代码也能够做为基于NPAPI开发的一些参考浏览器
还有一个基于NPAPI作的简单的示例,结构很是简单,不用绕来绕去,相对理解起来也简单许多
二.插件入门开发的示例
开发工具为visual studio 2010
1.新建一个Win32 project,命名以np开头(目的是编译完的Dll名必须以np开头才能被识别为插件)
类型为一个DLL的空工程便可
2.右键选中项目的属性,在VC++ Directories目录下,选择Include Directories,Edit,
将plugin/base/public和plugin/sdk/samples/include添加到include
3.新建Version资源文件
4.新建一个Module-Definition File(.def),定义入口函数
5.新建一个CPlugin类继承nsPluginInstanceBase,做为插件实例类(后面再说该类的做用)
肯定以后,在plugin.h中#include <pluginbase.h>
类名为Cplugin,头文件名为plugin.h,(npp_gate.cpp会使用到,不一样能够修改)
修改构造函数的实现,带参数NPP类型并新建一个属性保存该参数
实现父类的三个纯虚函数
6.省得作过多操做,从samples中引入已经编写好的入口函数
从plugin\sdk\samples\npruntime路径添加np_entry.cpp(插件入口函数),npn_gate.cpp(插件调用浏览器的一些方法),npp_gate.cpp(浏览器调用插件的一些方法)
添加后须要作一点修改,
1).np_entry.cpp和npn_gate.cpp的引用
#include "npapi.h"
#include "npfunctions.h"
换成
#include<pluginbase.h>
2).而后进入pluginbase.h,再进入npplat.h,将
#ifdef XP_WIN
#include "windows.h"
#endif
挪到
#include "npapi.h"
#include "npfunctions.h"
前面,
3).而后在项目属性,Preprocessor,Preprocessor Definitions添加XP_WIN的定义
(这样作的缘由是windows.h须要在npapi.h前定义,本身在全部引用了npapi.h的前面加上windows.h的引用也能够)
4),np_entry.cpp中引入头文件#include <stddef.h>
由于使用到offsetof
这三个文件中的函数很是重要,首先来看下np_entry.cpp中的函数
NP_GetEntryPoints函数,为插件入口的函数,插件初始化将会首先调用该函数
该函数用于初始化浏览器调用插件的函数表,以NPP(np plugin)开头,
后面的插件的一些事件(new等)发生时将会以这里初始化的函数做为入口,好比
pFuncs->newp = NPP_New;初始化后将会在建立插件实例时调用NPP_New的实现来建立.
NP_Initialize函数,初始化插件时,在NP_GetEntryPoints后调用,
该函数用于初始化插件调用浏览器的函数表,参数pFuncs带有该函数表信息,
咱们自定义一个对象保存这些信息,从此就可经过该对象调用方法来实现对浏览器的一些操做
NP_Shutdown函数,与NP_Initialize对应,主要释放资源等操做
再来看下npp_gate.cpp,这个文件中的函数都以NPP开头,用于定义浏览器调用插件的方法
通过NP_GetEntryPoints的初始化后,当特定事件发生时,浏览器将会调用这些方法
而后须要注意的是该文件引用了plugin.h,是咱们第5步建立的文件,名字不一样能够改改
NPP_New方法,用于建立插件实例
CPlugin * pPlugin = new CPlugin(instance);这句话为建立一个咱们定义的CPlugin类对象,构造函数为NPP类型
NPP_Destroy方法,用于销毁插件实例,刷新页面,关闭页面等操做会触发
该方法会调用CPlugin的shut方法再delete掉实例
NPP_SetWindow方法,插件窗口发生任何变化都会调用该方法
window建立时会调用一次,若是初始化失败则delete掉实例而后返回错误
NPP_GetValue方法,当获取插件有关的一些信息时会触发该方法调用(如获取插件名,插件实例)
当javascript操做插件对象时,该方法调用CPlugin的GetScriptableObject方法,须要本身实现,返回一个脚本操做对象(NPObject)
在这里返回到CPlugin类,添加GetScriptableObject方法并实现(见第7步操做)
NPP_HandleEvent方法,处理事件,该方法调用CPlugin的handleEvent方法,继续添加实现吧
该文件中其余方法暂时没什么可说的,须要用到的能够查下API并实现出来就好了.
再看下npn_gate.cpp,该文件实现了对浏览器的一些操做的函数,都以NPN(np netscape)开头
其中有一些带有NPObject*参数的与GetScriptableObject方法建立的脚本操做对象有关,将在第7步作说明
该文件中用到的NPNetscapeFuncs NPNFuncs;在NP_Initialize中初始化完成
7.封装一个脚本操做对象
Add一个C++类,该示例命名为PluginObject,继承NPObject
添加静态方法,用于建立该脚本操做的对象
在PluginObject.h中声明一个NPClass对象,使用上面的静态方法将该NPClass对象初始化
在该方法中经过NPNCreateObject方法建立该对象
NPN_CreateObject会在浏览器中作一些操做而后回来调用objectClass中的_allocate方法
须要实现该静态方法,new 一个PluginObject
新建一个NPP npp属性,和一个NPP参数的构造函数
后面的操做中,浏览器调用了NPNFunc中以上的一些方法则会来调用这些静态方法,并将_allocate返回的值做为参数传到其余函数中
接下来的实现就相对比较随意了,能够直接在这些静态方法中实现想要的效果,
也能够在PluginObject中建立对应的成员函数实现,而后在静态方法中经过nobj参数转换为(PluginObject)类型调用相应成员函数
其中几个函数比较重要,_hasMethod判断参见是否有该函数,_getProperty则是判断属性,invoke调用相应方法,
invokeDefault能够在invoke中调用NPN_InvokeDefault来访问,最好不要直接调用,(见API,缘由未知,通常浏览器都要作进一步操做)
hasMethod等方法的相似于参数methodName都是以identifier做为判断的,能够调用NPN_GetStringIdentifier获取
例如:
多说下enumerate方法或者说是NPN_XXX的方法,由于就这个东西折腾我完完整整的两天时间...
enumerate方法的参数有个指针数组,可是他的结构是
并且初始化的时候必定要用NPN_MemAlloc来操做....API上只有关于指针数组的结构说明,并且很简单的提了一句,折腾两天才发现非得用NPN来分配内存- -||
弱弱的总结下,应该是须要给Firefox用到的东西或者说从参数传进来须要你分配内存的都得用NPN_MemAlloc分配内存
若是出现Access Violation,首先想到什么地方应该用NPN_MemAlloc....
三.注册及安装
1.注册表注册位置
HKEY_CURRENT_USER\Software\MozillaPlugins
添加一个项@whuiss.com/npTest
添加字符串值
"Description"="code project test"
"Path"="path to npTest.dll"
"ProductName"="npdemo Dynamic Library"
"Vendor"="zsy"
"Version"="1.0.0.1"
添加子项MIMETypes
添加MIMETypes的子项application/x-npTest
可是实际上只须要一个项@whuiss.com/npTest以及一个Path字符串值,其余无关紧要
在firefox地址栏输入about:plugins可查到你的插件了
2.使用安装文件注册
visual studio新建一个set up project
FileSystem View中选中dll或者某个工程的输出
Registry View中按照上面的位置给添加上相应信息便可
四.使用插件
五.调试插件
先前一直弄错了,觉得是指向Firefox.exe,查了很久,发现原来在Firefox4以后新建了一个plugin-Container.exe进程
调试目标指向plugin-container.exe 或者 tools->attach to process选中plugin-container.exe进程 或者debug->attach to process
六.附上示例工程
打开工程后须要修改include directory
------------------------------------------------------分割线-----------------------------------------------------
发现个新问题,NPAPI执行函数返回值不支持带中文的么?
调试不少次了,也不知道是配置问题仍是什么问题,NPVariant *result中带有值返回的
可是到浏览器就变成空字符串,去掉中文的就能正常显示
Firebreath的也试过了,也不支持中文字符
没办法,只好将返回的值转成base64再在浏览器解码,这样却是能够正常
------------------------------------------------------分割线-----------------------------------------------------
firefox新版本 弹出winform(例如访问某些智能卡私钥会须要输入PIN)的时候致使假死的状况,在火狐社区提问了,可以解决
http://mozilla.com.cn/post/31422/#reply-24747
大体意思就是修改config里面的dom.ipc.plugins.enabled.your-plugin.dll=false
from:http://blog.csdn.net/hzzhoushaoyu/article/details/7387516