NPAPI插件开发
1.插件是什么
插件是一种遵循一定规范的应用程序接口编写出来的程序。插件必须依附于一个宿主程序,为宿主程序提供增强功能。插件的种类有很多,这里主要讨论浏览器插件。
IE下利用OLE和COM技术开发的浏览器插件称为ActiveX控件。一般以.ocx为扩展名。IE浏览器通过OLE标准与ActiveX控件之间进行交互,完成对现有功能的扩充。
IE和OLE技术都是微软出的,所以如果在非IE浏览器下开发插件,就不能使用现有的COM技术标准。NPAPI技术提供了一种新的开发浏览器下插件的标准。浏览器和插件共同遵守这一标准,完成功能和交互。
2.Netscape插件
支持NPAPI标准的浏览器有很多,这里以Firefox为例进行说明,不同的浏览器在具体的实现上可能有所不同。
Netscape插件是遵循NPAPI标准开发出的对浏览器扩展的插件模块。 在firefox下,将插件(dll)放入firefox安装目录下的plugins文件夹中,启动firefox,浏览器会通过插件的MimeType属性识别出该插件。可以在地址栏中输入about:plugins来查看插件是否被firefox正确识别,也可以通过设置注册表的方式来安装该插件,可以创建HKEY_LOCAL_MACHINE\Software\\MozillaPlugins\\@xxx.cn/xxxx,添加Path字符串项保存插件路径。浏览器会自动加载。
3.MimeType
Mimetype,媒体资源类型,一般用于设定某种扩展名的文件用一种应用程序打开的方式。在编写Netscape插件时,在资源文件中设置该插件的MimeType属性值。如:
- BEGIN
- BLOCK "040904e4"
- BEGIN
- VALUE "CompanyName", "?????"
- VALUE "FileDescription", "TODO: <File description>"
- VALUE "FileVersion", "1.0.0.1"
- VALUE "InternalName", "npplugins.dll"
- VALUE "LegalCopyright", "TODO: (c) <Company name>. All rights reserved."
- VALUE "OriginalFilename", "npplugins.dll"
- VALUE "ProductName", "????"
- VALUE "ProductVersion", "1.0.0.1"
- VALUE "MIMEType", "application/test-plugins"
- END
- END
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "?????"
VALUE "FileDescription", "TODO: <File description>"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "npplugins.dll"
VALUE "LegalCopyright", "TODO: (c) <Company name>. All rights reserved."
VALUE "OriginalFilename", "npplugins.dll"
VALUE "ProductName", "????"
VALUE "ProductVersion", "1.0.0.1"
VALUE "MIMEType", "application/test-plugins"
END
END
当浏览器启动后,会在默认的plugins文件夹中加载插件,并读取插件的MimeType属性,并保存到浏览器内部。输入about:plugins即可以获取所有当前识别出的插件已经MimeType属性。当浏览器加载页面遇到<Embed ID = 'plugins1' type='application/test-plugins'/>这样的文件内容时,即知道应该调用MimeType属性值为type的插件来打开该文件。就会在浏览器中查找到该插件,并进行加载和初始化。如果不存在该属性的插件,则因为找不到指定类型的插件而无法打开该媒体文件。
微软的IE浏览器下的ActiveX控件遵循了COM标准,所以使用Object标签的CLSID来标识应该调用那个插件来读取该文件,不需要为插件设定MIME 的编码。
4.Netscape插件的生命周期
1.打开firefox浏览器。Firefox主动读取安装目录下的plugins文件夹,读取该文件夹下的插件的信息,比如mimetype,并保存起来,输入about:plugins可以查看
2.载入相关页面。当遇到标签为<Embed ID = 'plugins1' type='application/test-plugins'/>这样的文件内容时,浏览器主动查找加载mimetype相匹配的插件。加载的过程也是初始化调用接口的过程。初始化完毕后,浏览器会调用插件相关接口创建一个插件实例,与该页面相关联。
3..载入另一个新的页面。如果已经有页面载入,则此后的所有重新打开的web页面都将跳过插件初始化这一步骤,不过要创建新的插件实例与新的页面相对应。
4..关闭一个页面。销毁与该页面关联的插件实例,如果是最后一个页面,则执行反初始化插件操作。
5. NPAPI标准的接口说明
NPAPI标准定义在一组包含了数据结构和接口函数的头文件中。在实际的开发中,需要将这些头文件加入到工程中,并对头文件定义的部分接口编写实现。用到的主要四个头文件有npapi.h,npfunction.h,npruntime.h,nptype.h,这四个头文件可以在firefox的源码例子插件中找到,同时还提供了一组C++编写的框架用来更方便的开发Netscape插件。
简单介绍一下三类接口函数
1..前缀NP_是npapi的插件库提供给浏览器的最上层的接口,一般为动态链接库的导出接口,主要有NP_GetEntryPoints、NP_Initialize、NP_GetMIMEDescription、 NP_GetValue、NP_Shutdown的等几个函数,不同平台的接口可能略有不同,但基本功能都是一样的,都是通过接口来初始化、销毁以及认知此动态库.
- LIBRARY "npplugins"
- EXPORTS
- ; Explicit exports can go here
- NP_GetEntryPoints @1
- NP_Initialize @2
- NP_Shutdown @3
LIBRARY "npplugins" EXPORTS
; Explicit exports can go here
NP_GetEntryPoints @1
NP_Initialize @2
NP_Shutdown @3
2. 前缀NPP_即NP Plugin是插件本身提供给浏览器调用的接口,主要被用来填充NPPluginFuncs的结构体,主要包括:NPP_New、NPP_Destroy、NPP_SetWindow、NPP_GetMIMEDescription 、NPP_NewStream、NPP_DestroyStream、NPP_StreamAsFile、NPP_WriteReady、NPP_Write、NPP_Print、NPP_HandleEvent、NPP_URLNotify、NPP_GetValue、NPP_SetValue等,详细介绍
NPP_Destroy 删除插件的一个运行实例(instance) NPP_DestroyStream 告知插件将要删除一个流数据 NPP_GetValue 供浏览器查询插件的内部信息 NP_GetValue 供浏览器查询插件的内部信息 NPP_HandleEvent 注册关心的事件,当事件发生时浏览会通知插件 NP_Initialize 只调用一次,在插件加载时调用 NPP_New 创建插件的一个实例 NPP_NewStream 通知插件实例出现了新的流数据 NPP_Print 请求嵌入式打印还是全屏打印 NPP_SetValue 插件添加变量信息 NPP_SetWindow 当窗口创建、移动、改变大小或者销毁时通知插件 NP_Shutdown 销毁插件,与NP_Initialize对应 NPP_StreamAsFile 为数据流提供一个本地文件名 NPP_URLNotify 插件要求通知后,当对于某个URL的请求完成后,浏览器通知插件 NPP_Write 插件读取流数据 NPP_WriteReady 调用NPP_Write之前调用,确实插件可以接收多少字节的数据
3.前缀NPN_XXX类接口一般为浏览器引擎提供给plugin调用的接口主要包括NPN_GetURL、NPN_PostURL、NPN_GetValue、NPN_SetValue、NPN_Status等
当浏览器开始加载插件时,首先调用NP_GetEntryPoint函数用于获取NPP_类函数的地址,为后续调用做初始化工作。接着调用NP_Initialize函数,将浏览器提供的NPN_函数地址通知插件。以上两个动态库导出接口完成了插件后续调用和被调用的初始化工作。当所有插件相关页面退出时,浏览器调用NP_Shutdown来完成反初始化。
接下来当firefox加载页面时,浏览器调用插件的NPP_New函数来创建一个插件实例。当页面退出时,浏览器调用NPP_Destroy来销毁插件实例。注意,只有在第一次加载页面时才会初始化调用插件,后续打开的页面不再重新初始化,因为在第一次初始化时浏览器已经获取了函数接口信息,后续的页面只需要调用NPP_New创建新的插件实例与页面对应即可。同理,只有当最后一个页面退出时,才调用插件的反初始化,即NP_Shutdown函数。这时,浏览器会清除该插件的对象实例,释放资源。
6.NPAPI的主要数据结构
1. 结构NPPluginFuncs:包含了NPP_函数地址的结构体。浏览器中定义一个这样的结构体对象,通过NP_GetEntryPoint函数对该结构体对象赋值,将NPP_函数地址通知浏览器,供浏览器后续调用
2. 结构NPNetscapeFuncs:包含了浏览器中定义的NPN_函数的结构体。插件中定义一个这样的结构体指针,浏览器通过NP_Initialize函数赋值给这个结构体指针,为后续插件调用浏览器中的这些接口服务。
3. 结构NPObject:包含NPClass *_class和uint32_t referenceCount. 插件实例对象
4. 结构NPClass: 包含了访问插件的一组方法。包含在NPObject对象中。主要包含的函数有pluginHasMethod :询问插件是否支持某一js方法。pluginHasProperty :询问插件是否具有某一属性 pluginInvoke :当插件支持该方法时,浏览器调用给方法传递参数和获取返回值。
5. 结构NPVariant:带类型定义的数据信息结构
定义为
typedef struct _NPVariant {
NPVariantType type;
union {
bool boolValue;
int32_t intValue;
double doubleValue;
NPString stringValue;
NPObject *objectValue;
} value;
} NPVariant;
对该结构体的访问可以通过以下的标准宏进行:
NPVARIANT_IS_STRING或者NPVARIANT_TO_BOOLEAN,NPVARIANT_TO_INT32,NPVARIANT_TO_DOUBLE,NPVARIANT_TO_STRING,NPVARIANT_TO_OBJECT等。
NPAPI接口同时提供了一些将其他类型转换为NPVariant结构的宏。如INT32_TO_NPVARIANT,STRINGZ_TO_NPVARIANT,OBJECT_TO_NPVARIANT等,可以很方便的进行数据转换。
7.插件与JS的交互
NPAPI标准提供了一套插件与JS的交互机制。
1. javascript调用插件方法: 浏览器首先会调用NPP_GetValue(NPP instance, NPPVariable variable, void* value)取得NPObject对象的地址。Variable参数为NPPVpluginScriptableNPObject。在取得该对象后浏览器就可以调用插件提供的NPClass函数。最主要的函数有下面几个: pluginHasMethod :询问插件是否支持某一js方法。 pluginHasProperty :询问插件是否具有某一属性 pluginInvoke : 当插件支持某一方法时,浏览器将会调用该函数执行插件为js提供的这一方法。那么对于提供的很多方法插件如何在该函数内区分。分析这个函数: pluginInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result); obj是插件里的NPObject对象地址。 Name表示插件提供方法的名字,通过对比这个参数来区分插件提供的不同方法。 args和argcount分别表示js传来的参数地址和参数个数。 result是函数返回给js的结果。
2. 插件调用js内部的回调函数: Js可以通过2种方式为插件设置回调函数。示例如下: <script language=javascript> Plugin.Onfun = fun;//方式一 通过设置插件属性传入回调函数地址 Plugin.Onfun(fun);//方式二 通过调用插件函数传入回调函数地址 Function fun(){} < /script>
在插件内部,当js函数地址传到插件时,浏览器把它封装为一个NPObject对象,里面存有函数地址 方式一: 在插件内部,浏览器会调用pluginHasproperty确认插件是否有该属性。如果有然后浏览器调用pluginSetproperty函数。pluginSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *variant)的第二个参数判断是哪个属性,第三个参数就是NPObject对象地址。 方式二:在插件内部,浏览器会调用pluginHasmethod确定是否支持该方法。然后调用pluginInvoke,这里面的args参数包含了回调函数NPObject地址。 js设置完回调函数后,插件就可以调用该函数了。需要使用NPN_InvokeDefault,示例代码如下: bool bret = gBrowser->invokeDefault(npp, callbackNPObject, &pV, 1, &result);
另外,插件也可以直接调用js中的函数。在插件内部调用浏览器的getUrl函数。具体格式如下: gBrowser->geturl(inst(), “javascript:function()”, "_self"); 如果想传入整数参数,上面函数第二个参数应写成: “javascript:function(“+num+”)”。 如果传入字符串参数,上面函数第二个参数为: “javascript:function(/’“+”string”+”/’)”。如果字符串含有中文,需要进行url encode。
8.开发Netscape插件的一般方法
尽管开发netscape插件有不少可用框架。但是开发一个典型的netscape插件主要要做的工作有以下:
1.编写一个动态链接库。 插件的表现形式就是一个动态链接库,所以首先编写一个dll文件或者.so文件供浏览器调用。注意,插件的名称应该以np开头,NPAPI标准的默认规则。
2.添加dll导出接口。 在xx.def文件中添加dll的导出函数,如图
上面导出了三个NP_函数,供浏览器调用。这三个函数的作用前面已经说过,不再细述
3.添加插件的mimetype。首先为插件添加一个.rc文件,注意该资源文件的默认语言应该是英文,简体中文的话浏览器识别不出,然后在.rc文件中添加mimetype属性。
如图
4.实现npapi.h中声明的NPP函数。
5.在Np_GetEntryPoints中将NPP_函数地址赋值给传出参数。
6..在NP_Initialize中保存传入的NPNetscapeFuncs对象指针,供插件后续调用
7.在Np_Shutdown中处理反初始化操作。
8.对NPClass中的函数进行实现
NPAPI插件开发的更多相关文章
- NPAPI插件开发新手容易遇到的问题
在网上找了一个npdemo的例子,编译了一下在FireFox运行正常,在Chrome下就是不行,也没任何提示. 折腾了好久,最后发现是rc文件 支持语言编码问题 NPAPI插件开发详细记录:用VS20 ...
- npapi插件开发流程与实例
近期做NPAPI插件,网上的介绍还是比较多,但就是没有一个完整的例子,FQ也没找到,难得NPAPI要走向陌路了?就不去深究额,先解决目前遇到的问题. 现状:已有Activex(仅兼容IE32/64位浏 ...
- NPAPI插件开发详细记录:用VS2010开发NPAPI插件步骤<转>
原帖地址:https://blog.csdn.net/z6482/article/details/7660748 ------------------------------------------- ...
- ppapi,npapi
PPAPI也就是Pepper Plugin API,是在原有网景NPAPI(Netscape Plugin API)基础上发展而来的.NPAPI是当今最流行的插件架构,几乎所有浏览器都支持,不过存在很 ...
- 【转发】NPAPI学习(Firefox和Chrome扩展开发 )
NPAPI学习(Firefox和Chrome扩展开发 ) 2011-11-08 14:41:02 by [6yang], 1172 visits, 收藏 | 返回 Firefox和Chrome扩展开发 ...
- NPAPI开发常识
其实,就在几天前,我根本不知道什么是NPAPI插件.因为最近的项目中用到需要在非IE下检测客户端是否安装,最终找到浏览器插件NPAPI. 以下资料来源于网络收集,以此给那些和我一样迷茫的人.本文的目的 ...
- NPAPI——实现非IE浏览器的类似ActiveX的本地程序(插件)调用
一.Netscape Plugin Interface(NPAPI) 大致的说明可以看下官方文档Plugin 本文主要针对于JavaScript与插件交互部分做一些交流,比如用于数字证书的操作(淘宝和 ...
- 一个实现浏览器网页与本地程序之间进行双向调用的轻量级、强兼容、可扩展的插件开发平台—PluginOK中间件
通过PluginOK中间件插件平台(原名本网通WebRunLocal)可实现在网页中的JavaScript脚本无障碍访问本地电脑的硬件.调用本地系统的API及相关组件,同时可彻底解决ActiveX组件 ...
- JavaScript学习笔记(四)——jQuery插件开发与发布
jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...
随机推荐
- 静态页面中如何传json数据
首页传递参数组装成json数据,再编码 var param="{type:'"+type+"',text:'"+select_text+"',sele ...
- PHP基础入门教程 PHP循环函数
PHP循环主要有四种:while,do…while,for,foreach.下面我们分开讲解每种循环的用法. while语句: 只要指定的条件成立,则循环执行代码块. 格式: while(expr) ...
- 求小于等于n的所有素数
题目:要求输出所有小于等于n的素数(n>=2,且为正整数) 要求:1.每行输出10个素数 2.尽可能采用较优算法 #include<iostream> #include<cma ...
- Beaglebone Back学习七(URAT串口测试)
URAT串口测试
- ubuntu下安装ffmpeg和X264
第一步:安装必要的库 $:-dev libtheora-dev libx11-dev zlib1g-dev 第二步:安装SDL(否则可能编译不出ffplay) $:-dev $:-dev libsdl ...
- Code for the Homework1
作业要求: http://www.cnblogs.com/bingc/p/4919692.html 代码(未使用Eigen): #include <iostream> #include & ...
- Jquery Highcharts 选项配置 说明文档
Highcharts提供大量的选项配置参数,您可以轻松定制符合用户要求的图表,下面为Highcharts常用的最核心的参数选项配置. Chart:图表区选项 Chart图表区选项用于设置图表区相关属性 ...
- hibernateTemplate的load方法
hibernateTemplate的load方法采用延迟加载,所以应当注意. 如果配置不当,采用此方法获取对象,往往会出现异常: javax.servlet.ServletException: org ...
- 数据生成器Bogus的使用以及基于声明的扩展
引言 最近在整理代码,发现以前写的一个数据填充器写了一半没实现,而偏偏这段时间就要用到类似的功能,所以正好实现下. 目标 这个工具的目标是能够在项目初期快速搭建一个"数据提供器", ...
- JAVA CAS单点登录(SSO) 教程
一.教程前言 教程目的:从头到尾细细道来单点登录服务器及客户端应用的每个步骤 单点登录(SSO):请看百科解释猛击这里打开 本教程使用的SSO服务器是Yelu大学研发的CAS(Central Auth ...