一、 基本原理
项目需要支持chrome浏览器的使用,需求要支持ActiveX控件或COM组件能在chrome下运行,也就是说要进行使用NPAPI的技术进行对控件封装, 使用动态库都是同理。于是研究了NPAPI的开发过程和原理,现做出以下一些记录。
具备条件: NPAPI SDK. 开发环境。(SDK可以官网下载或其他途径获取);
一个基本的结构式如下所示:
插件的本质
插件的本质,就是一个供浏览器调用的动态链接库,在windows平台是一个dll文件,在unix平台是so文件。只不过NPAPI插件规范了这个动态库的接口,规定了接口需要实现哪些最基本的功能。
二、 开发流程
开发环境:win7 X64, vs2013,chrome版本 28.0.1500.44.
开发流程简介:
1. 创建工程
创建一个win32 工程,下一步选择dll和空工程。如下图:
Name项一定要以np开头,为了将来适应不同操作系统,最好全小写,不要太长,尽量控制在8字符内。本例定义为nptestdemo ,工程路径自定义即可;
NPAPI的SDK 本例定义为F:\Propram Code Lib\nptestdemo\ffplugin, 如下图;
2. 添加文件, 将NPAPI的文件添加到工程中(NPAPI的有几个文件必须添加到工程)
我的NPAPI SDK所在位置如下图所示:
将NPAPI SDK中Common的文件添加到工程;
路径为:…\ffplugin\sdk\samples\common\
3. 添加def文件
新建一个def文件,命名最好与项目一致。如下图;
编辑nptestdemo.def文件:
文件中加入以下内容:
LIBRARY"nptestdemo"
EXPORTS
NP_GetEntryPoints@1
NP_Initialize@2
NP_Shutdown @3
4. 添加资源
新建一个资源文件:选择Version, 选择新建,会自动生成一个资源文件。
资源文件右键选择“查看代码”,打开资源文件,编辑;
找到如下一段:
BEGIN
BLOCK"StringFileInfo"
BEGIN
BLOCK"040904e4" //修改BLOCK 一定要是"040904e4"
BEGIN
VALUE"CompanyName","TODO: <公司名>"
VALUE"FileDescription","TODO: <文件说明>"
VALUE"FileVersion","1.0.0.1"
VALUE"InternalName","nptestde.dll"
VALUE"LegalCopyright","Copyright (C) 2017"
// MIMEType是plugin的唯一标示,需要自己定义
//通常的格式是"application/“+ [plugin name]
//本例中定义为"application/demo-plugin"
VALUE "MIMEType","application/nptestdemo-plugin"
VALUE"OriginalFilename","nptestde.dll"
VALUE"ProductName","TODO: nptestdemo.dll_mkx"
VALUE"ProductVersion","1.0.0.1"
END
END
BLOCK"VarFileInfo"
BEGIN
VALUE"Translation",0x409,1252 //修改VALUE值这两个值
END
END
5. 添加最关键的部分:Plugin实现类
添加一个C++类: CPlugin. 要继承自nsPluginInstanceBace. (注意包含父类文件)
编辑Plugin.h文件:
重写父类三个虚函数:
#pragma once
#include "pluginbase.h"
class CPlugin :public nsPluginInstanceBase
{
public:
CPlugin(NPP pNPInstance);
~CPlugin();
//重写以下三个虚函数
NPBoolinit(NPWindow* pNPWindow)
{
m_bInitialized = TRUE; return TRUE;
}
voidshut() { m_bInitialized = FALSE; }
NPBoolisInitialized() { return m_bInitialized; }
private:
NPPm_pNPInstance;
NPBoolm_bInitialized;
};
编辑Plugin.cpp文件,实现四个全局函数;
NPError NS_PluginInitialize()
{
returnNPERR_NO_ERROR;
}
void NS_PluginShutdown()
{
}
nsPluginInstanceBase *NS_NewPluginInstance(nsPluginCreateData * aCreateDataStruct)
{
if(!aCreateDataStruct)
return NULL;
CPlugin * plugin = new CPlugin(aCreateDataStruct->instance);
returnplugin;
}
voidNS_DestroyPluginInstance(nsPluginInstanceBase * aPlugin)
{
if(aPlugin)
delete(CPlugin *)aPlugin;
}
6. 修改项目属性,加入SDK链接
在第5步之前,应该将工程属性修改,C++->常规->附加包含目录中加入sdk的包含目录;本项目按照SDK路径加入路径为:..\ffplugin\sdk\samples\include; ..\ffplugin\base\public
加入添加预编译宏X86
C++->预处理器->预处理器定义中加入 _X86_
这个宏要是没有加,会报出错误 1 error C1189: #error : "No Target Architecture"等错误还有会报很多vs库文件中的类型错误。所以该编译宏必须添加;
7. 注册、测试
本例编译后,生成文件为nptestdemo.dll
要向注册表注册该文件,打开注册表,注册路径为:
[HKEY_CURRENT_USER\Software\MozillaPlugins]
在该路径下新建@mozilla.com.cn/demo(该名称可以自定义创建,名称自定义)
新建字符串数据“Path” 值为nptestdemo.dll的绝对路径。本例为:F:\Propram Code Lib\nptestdemo\Debug\nptestdemo.dll. 下图:
打开chrome浏览器(版本为开发环境中说明的版本)在地址栏输入“about:plugins” 。如果在plugin列表中有本例的nptestdemo.dll即说明我们的plugin示例已经成功完成,并且浏览器已经成功加载。(360浏览器极速模式亦可完成此动作)
至此,一个简单的流程就完成了。这只是完成了一个基本简单的框架,实际上什么也做不了。浏览器只是加载了插件,实际上相当于和浏览器没发生任何交互动作。
插件的调用
写一个简单的html页面来调用该插件;
1. <html>
<