NPAPI 插件 编程起步

NPAPI 插件 编程起步

最近需要写一个Mac平台上的简单的跨浏览器的插件,需要在js中调用本地方法,而npapi满足此要求。
NPAPI就是Netscape Plugin Application Programming Interface的缩写了,虽然Netscape已经去了,但是这个却被沿用下来,在各大浏览器中都得以实现。还是纪念下曾经的浏览器的鼻祖啊。

在网络上搜索了很长时间,一直没有找到合适的满足自己需求的代码例子。且这方面的文档也少的可怜。
还是先提一下,有两个系列的文章还是不错,虽然或许可能也不完全正确,但是帮助理解npapi的编程模型是非常有帮助的:

  1. http://colonelpanic.net/category/plugindev/npapi-plugindev/
  2. http://rintarou.dyndns.org/category/browser/plugin

下面是我寻找解决方法的过程
  • 一开始找到mozilla的一篇官方文档:Writing a plugin for Mac OS X,这里面提到了了官方的代码库中有demo,于是就跑到公司checkout下mozilla的分支。并看了下里面的一个mac的例子.
    不过这个例子没有使用npruntime的东西,加上一开始的时候对npapi不熟悉,就继续搜索.
  • 在google, stackoverflow,github, google codes 中不停的搜索,结果甚少,最后找到一个npruntime的例子,Call Native API from Google Chrome Extension on Mac OS X只可惜编译后只能在mac的chrome下运行。
  • 后来又找到了Firebreath这个跨平台的浏览器NPAPI插件开发框架,可以通过python和cmake的配合,生成适合不同操作系统的浏览器插件的工程,于是就测试了,果真生成xcode项目后,编译,然后测试了下js调用插件的方法,还真能在各个浏览器(测试了三个比较常用的safari,chrome,firefox)下运行。但是无奈由于包含一些高级的程序代码其最小编译后的大小都2m+对于一个功能单一的插件来讲,无疑是让人无法接受的,所以继续找demo.
  • 后来找到了npsimple-win32 这个windows下的vs的项目,我将其移植到mac上,编译运行后,唯独在safari下无法运行,悲剧的一塌糊涂,对于一个npapi不同的浏览器在实现的具体细节上竟然有细微的差别,真是太变态鸟。
  • 最后无奈之下,将Weikit开源项目中的例子弄出来,然后和npruntime的相关代码进行整合,发现在safari,chrome可以运行在firefox中没法运行,好吧,至少现在两个例子的并集是完整的,我就将两个代码进行查看,最终找出了问题的所在,在safari下需要启动CoreGraphics,而在firefox下scriptable的NPObject的hasProperty和getProperty必须设置,可能在firefox下调用某函数,先去scriptable NPObject中找有没有这个名字的属性,然后在找方法吧。
最后终于写出了一个简单的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#import <WebKit/npapi.h>
#import <WebKit/npfunctions.h>
#import <WebKit/npruntime.h>



// Browser function table,可以通过它来得到浏览器提供的功能
static NPNetscapeFuncs * browser ;
static const char *plugin_method_name_open = "open" ;

////////////////////////////////////
/*******各种接口的声明*********/
//在NPAPI编程的接口中你会发现有NP_打头的,有NPP_打头的,有NPN_打头的
//NP是npapi的插件库提供给浏览器的最上层的接口
//NPP即NP Plugin是插件本身提供给浏览器调用的接口,主要被用来填充NPPluginFuncs的结构体
//NPN即NP Netscape ,是浏览器提供给插件使用的接口,这些接口一般都在NPNetscapeFuncs结构体中

//Mach-o entry points,浏览器和创建交流的最上层的接口
NPError NP_Initialize (NPNetscapeFuncs *browserFuncs ) ;
NPError NP_GetEntryPoints (NPPluginFuncs *pluginFuncs ) ;
void NP_Shutdown ( void ) ;

//NPP Functions
NPError NPP_New (NPMIMEType pluginType , NPP instance , uint16_t mode , int16_t argc , char * argn [ ] , char * argv [ ] , NPSavedData * saved ) ;
NPError NPP_Destroy (NPP instance , NPSavedData ** save ) ;
NPError NPP_SetWindow (NPP instance , NPWindow * window ) ;
NPError NPP_NewStream (NPP instance , NPMIMEType type , NPStream * stream , NPBool seekable , uint16_t * stype ) ;
NPError NPP_DestroyStream (NPP instance , NPStream * stream , NPReason reason ) ;
int32 NPP_WriteReady (NPP instance , NPStream * stream ) ;
int32 NPP_Write (NPP instance , NPStream * stream , int32 offset , int32 len , void * buffer ) ;
void NPP_StreamAsFile (NPP instance , NPStream * stream , const char * fname ) ;
void NPP_Print (NPP instance , NPPrint * platformPrint ) ;
int16_t NPP_HandleEvent (NPP instance , void * event ) ;
void NPP_URLNotify (NPP instance , const char * URL , NPReason reason , void * notifyData ) ;
NPError NPP_GetValue (NPP instance , NPPVariable variable , void *value ) ;
NPError NPP_SetValue (NPP instance , NPNVariable variable , void *value ) ;

//Functions for scriptablePluginClass
bool plugin_has_method (NPObject *obj , NPIdentifier methodName ) ;
bool plugin_invoke (NPObject *obj , NPIdentifier methodName , const NPVariant *args , uint32_t argCount , NPVariant *result ) ;
bool hasProperty (NPObject *obj , NPIdentifier propertyName ) ;
bool getProperty (NPObject *obj , NPIdentifier propertyName , NPVariant *result ) ;
////////////////////////////////////

static struct NPClass scriptablePluginClass = {
    NP_CLASS_STRUCT_VERSION ,
    NULL ,
    NULL ,
    NULL ,
    plugin_has_method ,
    plugin_invoke ,
    NULL ,
    hasProperty ,
    getProperty ,
    NULL ,
    NULL ,
} ;

//接口的实现
NPError NP_Initialize (NPNetscapeFuncs * browserFuncs )
{
    browser = browserFuncs ;
    return NPERR_NO_ERROR ;
}

NPError NP_GetEntryPoints (NPPluginFuncs * pluginFuncs )
{
    pluginFuncs ->version = 11 ;
    pluginFuncs ->size = sizeof (pluginFuncs ) ;
    pluginFuncs ->newp = NPP_New ;
    pluginFuncs ->destroy = NPP_Destroy ;
    pluginFuncs ->setwindow = NPP_SetWindow ;
    pluginFuncs ->newstream = NPP_NewStream ;
    pluginFuncs ->destroystream = NPP_DestroyStream ;
    pluginFuncs ->asfile = NPP_StreamAsFile ;
    pluginFuncs ->writeready = NPP_WriteReady ;
    pluginFuncs ->write = (NPP_WriteProcPtr )NPP_Write ;
    pluginFuncs ->print = NPP_Print ;
    pluginFuncs ->event = NPP_HandleEvent ;
    pluginFuncs ->urlnotify = NPP_URLNotify ;
    pluginFuncs ->getvalue = NPP_GetValue ;
    pluginFuncs ->setvalue = NPP_SetValue ;
   
    return NPERR_NO_ERROR ;
}


void NP_Shutdown ( void )
{
   
}



bool plugin_has_method (NPObject *obj , NPIdentifier methodName ) {
    // This function will be called when we invoke method on this plugin elements.
    NPUTF8 *name = browser ->utf8fromidentifier (methodName ) ;
    bool result = strcmp (name , plugin_method_name_open ) == 0 ;
    browser ->memfree (name ) ;
    return result ;
}
bool plugin_invoke (NPObject *obj , NPIdentifier methodName , const NPVariant *args , uint32_t argCount , NPVariant *result ) {
    // Make sure the method called is "open".
    NPUTF8 *name = browser ->utf8fromidentifier (methodName ) ;
    if ( strcmp (name , plugin_method_name_open ) == 0 ) {
        browser ->memfree (name ) ;
        BOOLEAN_TO_NPVARIANT ( false , *result ) ;
        // Meke sure the arugment has at least one String parameter.
        if (argCount > 0 && NPVARIANT_IS_STRING (args [ 0 ] ) ) {
            // Build CFURL object from the arugment.
            NPString str = NPVARIANT_TO_STRING (args [ 0 ] ) ;
            CFURLRef url = CFURLCreateWithBytes (NULL , ( const UInt8 * )str. UTF8Characters , str. UTF8Length , kCFStringEncodingUTF8 , NULL ) ;
            if (url ) {
                // Open URL with the default application by Launch Service.
                OSStatus res = LSOpenCFURLRef (url , NULL ) ;
                CFRelease (url ) ;
                BOOLEAN_TO_NPVARIANT (res == noErr , *result ) ;
            }
        }
        return true ;
    }
    browser ->memfree (name ) ;
    return false ;
}

bool hasProperty (NPObject *obj , NPIdentifier propertyName ) {
    return false ;
}

bool getProperty (NPObject *obj , NPIdentifier propertyName , NPVariant *result ) {
    return false ;
}



//NPP Functions Implements
NPError NPP_New (NPMIMEType pluginType , NPP instance , uint16_t mode , int16_t argc , char * argn [ ] , char * argv [ ] , NPSavedData * saved )
{
    // Create per-instance storage
    //obj = (PluginObject *)malloc(sizeof(PluginObject));
    //bzero(obj, sizeof(PluginObject));
   
    //obj->npp = instance;
    //instance->pdata = obj;
   
    if ( !instance ->pdata ) {
        instance ->pdata = browser ->createobject (instance , &scriptablePluginClass ) ;
    }
    // Ask the browser if it supports the CoreGraphics drawing model
    NPBool supportsCoreGraphics ;
    if (browser ->getvalue (instance , NPNVsupportsCoreGraphicsBool , &supportsCoreGraphics ) != NPERR_NO_ERROR )
        supportsCoreGraphics = FALSE ;
   
    if ( !supportsCoreGraphics )
        return NPERR_INCOMPATIBLE_VERSION_ERROR ;
   
    // If the browser supports the CoreGraphics drawing model, enable it.
    browser ->setvalue (instance , NPPVpluginDrawingModel , ( void * )NPDrawingModelCoreGraphics ) ;
   
    return NPERR_NO_ERROR ;
}

NPError NPP_Destroy (NPP instance , NPSavedData ** save )
{
   
    // If we created a plugin instance, we'll destroy and clean it up.
    NPObject *pluginInstance =instance ->pdata ;
    if ( !pluginInstance ) {
        browser ->releaseobject (pluginInstance ) ;
        pluginInstance = NULL ;
    }
   
    return NPERR_NO_ERROR ;
}

NPError NPP_SetWindow (NPP instance , NPWindow * window )
{
    return NPERR_NO_ERROR ;
}


NPError NPP_NewStream (NPP instance , NPMIMEType type , NPStream * stream , NPBool seekable , uint16_t * stype )
{
    *stype = NP_ASFILEONLY ;
    return NPERR_NO_ERROR ;
}

NPError NPP_DestroyStream (NPP instance , NPStream * stream , NPReason reason )
{
    return NPERR_NO_ERROR ;
}

int32 NPP_WriteReady (NPP instance , NPStream * stream )
{
    return 0 ;
}

int32 NPP_Write (NPP instance , NPStream * stream , int32 offset , int32 len , void * buffer )
{
    return 0 ;
}

void NPP_StreamAsFile (NPP instance , NPStream * stream , const char * fname )
{
}

void NPP_Print (NPP instance , NPPrint * platformPrint )
{

}


int16_t NPP_HandleEvent (NPP instance , void * event )
{
    return 0 ;
}

void NPP_URLNotify (NPP instance , const char * url , NPReason reason , void * notifyData )
{

}

NPError NPP_GetValue (NPP instance , NPPVariable variable , void *value )
{
    NPObject *pluginInstance =NULL ;
    switch (variable ) {
        case NPPVpluginScriptableNPObject :
            // If we didn't create any plugin instance, we create it.
            pluginInstance =instance ->pdata ;
            if (pluginInstance ) {
                browser ->retainobject (pluginInstance ) ;
            }
            * (NPObject ** )value = pluginInstance ;
            break ;
        default :
            return NPERR_GENERIC_ERROR ;
    }
   
    return NPERR_NO_ERROR ;
}

NPError NPP_SetValue (NPP instance , NPNVariable variable , void *value )
{
    return NPERR_GENERIC_ERROR ;
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<head>
<script>
function run() {
    var plugin = document.getElementById("pluginId");
    plugin.open("http://www.geeklu.com");
}
</script>
</head>
<body >
<embed width="0" height="0" type="test/x-open-with-default-plugin" id="pluginId">
<button onclick="run()">run </button>
</body>
</html>

6 Responses to NPAPI 插件 编程起步

  1. [...] This post was mentioned on Twitter by Noexu, Luke. Luke said: NPAPI 插件 编程起步 http://geeklu.com/2010/10/getting-started-with-npapi-plugin/ [...]

打开链接下载源码: https://pan.quark.cn/s/8ec3d104bde6 华为MA5671是一款针对宽带接入需求而研发的智能型光猫设备,其核心应用场景为家庭用户及小型企业环境。该设备运用了千兆以太网技术,能够提供卓越的网络连接性能,从而使用户可以体验到稳定流畅的互联网服务。其完整名称为SmartAX MA5671,其中"SmartAX"是华为对其智能接入产品系列的特定命名,意指该设备具备智能化管理功能与自动化配置特性。固件,即Firmware,是指存储于硬件设备内部的一套程序代码,负责控制设备的各项功能运作并合理调配硬件资源。在华为MA5671设备中,固件发挥着核心作用,它直接影响着设备的操作系统运行机制、网络协议兼容性、安全防护机制以及性能表现等多个维度。"MA5671V8R313C00SPC100"作为该固件的标识编号,通过此代码可以解析出以下几个关键层面的信息: 1. **V8**:这通常象征固件的主版本号,或许表明这是第8代产品形态或第8次主要升级迭代。 2. **R313**:这可能代表固件的次级版本或修订层级,暗示着相较于V8版本,该版本经历了313次的迭代优化。 3. **C00**:这部分或许与设备的特定型号设定或地域适配性相关,不同的C00编码可能对应不同的功能模块配置或区域适应性调整。 4. **SPC100**:最后的这一段编码可能标识着特殊版本或性能增强配置,SPC(Special Performance Configuration)可能是华为针对特定性能优化版本设定的代号,而100可能代表这种优化措施的等级或序列编号。 在实际部署过程中,将固件保持为最新版本是非常重要的,这样做能够有效修正已知的安全隐患,优化设备运作效能,...
代码转载自:https://pan.quark.cn/s/558f943fe8b9 Oracle 11g是由甲骨文公司推出的一款面向企业级应用的数据管理平台,其具备丰富的功能特性与性能优化措施,能够充分满足大型商业机构及组织的复杂数据管理诉求。这份“Oracle 11g官方中文帮助文档”作为一份高清晰度且内容全面的资源,专门为中文使用者提供系统化的操作指引必要的技术支持。 1. **Oracle 11g核心构成** - 数据库模型:该系统基于关系数据库架构,负责对结构化数据进行系统化存储处理。 - 实例与服务机制:数据库实例指的是部署在服务器内存中的运行环境,而服务则是客户端接入数据库的核心通道。 2. **部署与设置** - 部署模式:涵盖高级部署流程快速部署方案,以适应多样化的应用场景。 - 参数配置文件:初始化参数文件(init.ora)用于设定数据库的运行环境参数。 - 逻辑存储与物理存储:表空间作为数据库对象的逻辑组织单元,数据文件则是实际存放数据的物理载体。 3. **SQL与PL/SQL技术** - SQL指令集:主要用于数据库数据的查询、录入、修改及删除等操作。 - PL/SQL编程:作为Oracle的特色编程语言,支持过程化编程范式,常用于开发存储过程触发器逻辑。 4. **安全防护机制** - 用户身份与角色管理:通过用户账户角色权限体系来控制数据库的访问权限。 - 授权管理及审计功能:实现数据访问权限的精细化控制,并记录数据库活动日志以保障合规操作。 5. **效能提升策略** - 查询执行优化器:智能选择最优的查询执行路径。 - 重做日志与归档机制:保障事务的持久性系统故障后的恢复能力。 - 数据分区技术:通过将大型数据表...
内容概要:本文档系统介绍了基于档案的多目标优化算法(MAOA)的Matlab代码实现,重点服务于复杂工程与科研场景下的多目标决策问题求解。该算法属于智能优化范畴,具备良好的收敛性与多样性保持能力,适用于电力系统、微电网调度、低碳经济运行等高维度、多约束优化场景。文档不仅提供完整的算法实现代码,还整合了大量相关科研主题,如阻抗建模、稳定性分析、VSG控制、风光储协同调度、电动汽车参与调频等,涵盖从底层建模到上层优化的全流程技术链条。配套资源丰富,包含Simulink仿真模型、复现论文案例、网盘资料链接及公众号获取通道,极大提升了科研复现效率与工程应用可行性。; 适合人群:具备Matlab/Simulink编程基础,从事电力系统自动化、新能源并网、微电网优化、综合能源系统等方向研究的硕士、博士研究生及科研人员。; 使用场景及目标:①用于求解电力系统中兼顾经济性与环保性的多目标优化问题,如低碳经济调度与N-1安全约束协同优化;②结合Simulink搭建高保真系统模型,开展多目标算法在动态系统中的仿真验证;③支撑高水平学术论文(如EI、SCI)的算法复现与创新拓展,加速科研成果转化。; 阅读建议:建议读者结合文档中提供的网盘资源与公众号获取完整代码包,按照技术模块分类逐步学习,重点关注MAOA算法核心逻辑与实际工程问题的映射关系,并尝试将其迁移至个人研究课题中进行调试与改进。
内容概要:本文围绕“弱电网下LCL型光伏并网逆变器分序阻抗建模与宽频耦合失稳机理研究”展开,系统阐述了基于Matlab/Simulink平台对LCL型光伏并网逆变器在弱电网条件下的阻抗建模、动态特性分析及稳定性评估方法。研究采用分序阻抗建模技术,通过正负序解耦手段深入剖析逆变器与电网之间的宽频域耦合振荡机理,重点探讨锁相环、电流控制环路等关键控制模块对系统阻抗特性的影响,并结合扫频法进行阻抗辨识,利用奈奎斯特稳定判据评估系统稳定性。文中提供了完整的Matlab代码与Simulink仿真模型,支持复现阻抗建模全过程,为新能源并网系统中常见的宽频振荡问题提供理论支撑与技术解决方案。; 适合人群:具备电力电子、自动控制理论及电力系统稳定性基础知识,从事新能源并网、微电网控制、逆变器建模与稳定性分析等相关方向的研究生、科研人员及工程技术人员。; 使用场景及目标:① 复现博士论文中关于LCL型逆变器在弱电网环境下的分序阻抗建模与失稳分析流程;② 掌握基于扫频法的序阻抗辨识技术及其在并网系统稳定性判据中的应用;③ 借助所提供的代码与模型开展宽频振荡机理仿真研究,支撑高水平科研项目、学术论文撰写与工程问题排查。; 阅读建议:学习者应结合Matlab代码与Simulink仿真模型同步运行,深入理解各模块的设计逻辑与参数设置,重点关注锁相环动态与控制器参数变化对正负序阻抗曲线的影响,建议通过调整电网强度、控制带宽等变量,观察系统稳定性边界变化,从而深化对宽频耦合失稳机制的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值