近日因要使用第三方Activex插件,但是火狐浏览器不支持,故用到了NPAPI封装插件。在此记录一笔,以便日后查阅。
1、创建项目
项目名取名“npplay”,项目名最好以“np”开头。创建新的解决方案,默认方案名与项目名一致。也可以选择已有的解决方案。点击“确认”,进入下一步。
点击“下一步”
选择dll应用程序,点击完成。
2、配置项目属性
1)选中项目右击选择“属性”,进入属性界面。
进入 配置属性->C/C++->常规->附加包含目录;
选择编辑添加 plugin解压后的目录 ~\plugin\base\public
(我本地解压到E:\vs_workspace\);
2)进入 配置属性->C/C++->预处理器->预处理器定义;
选择编辑,换行添加 _X86_
3)进入 配置属性->常规->字符集;
修改为 “使用多字节字符集”,不是必须的。
把文件添加到系统中。
注意:cpp文件中需要添加 #include "stdafx.h"
,不然会报错。
4、添加def文件
编辑def文件如下
LIBRARY "npplay"
EXPORTS
NP_GetEntryPoints @1
NP_Initialize @2
NP_Shutdown @3
EXPORTS 内容是默认写法 LIBRARY 后面内容自定义。
编写rc文件,选中右击选择“查看代码”。
添加如下version描述。
注意:BLOCK与Translation 是对应的,表示可以在火狐中使用插件。
源码如下:
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "xxx"
VALUE "FileDescription", "npplay"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "npplay.dll"
VALUE "LegalCopyright", "Copyright (C) 2017"
VALUE "OriginalFilename", "npplay.dll"
VALUE "ProductName", "npplay"
VALUE "ProductVersion", "1.0.0.1"
VALUE "MIMEType","application/npplay"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
6、添加plugin实现类
项目添加类plugin ,继承 nsPluginInstanceBase。用于定义映射的接口方法。
项目添加类PluginObject,继承NPObject。 用于解析js调用的方法以及参数。添加类方法同上。
编辑Plugin,PluginObject。定义了类直接的映射关系,代码如此复杂是因为已经封装过,可以直接用于显示ocx交互界面。代码如下。
Plugin.h文件
#pragma once
#include "pluginbase.h"
class Plugin :public nsPluginInstanceBase
{
private:
NPWindow* mWindow;
HWND m_hWnd;
NPP m_pNPInstance;
NPBool m_bInitialized;
NPObject *m_pScriptableObject;
public:
Plugin(NPP pNPInstance);
~Plugin(void);
NPBool init(NPWindow* aWindow);
void shut();
NPBool isInitialized();
int16_t handleEvent(void *);
NPObject *GetScriptableObject();
};
Plugin.cpp
#include "stdafx.h"
#include "Plugin.h"
#include
#include
#include "PluginObject.h"
NPError NS_PluginInitialize()
{
return NPERR_NO_ERROR;
}
void NS_PluginShutdown()
{
}
Plugin::Plugin(NPP pNPInstance):nsPluginInstanceBase(),
m_pNPInstance(pNPInstance),
m_bInitialized(FALSE),
m_pScriptableObject(NULL)
{
m_hWnd = NULL;
}
Plugin::~Plugin(void)
{
}
NPBool Plugin::init(NPWindow* pNPWindow)
{
mWindow = pNPWindow;
m_hWnd = (HWND)pNPWindow->window;
if (!m_hWnd)
return false;
CoInitialize(NULL);
RECT rc;
GetClientRect(m_hWnd,&rc);
AfxEnableControlContainer();
CWnd * par = CWnd::FromHandle(m_hWnd);
m_bInitialized = TRUE;
return TRUE;
}
void Plugin::shut()
{
m_hWnd = NULL;
m_bInitialized = FALSE;
}
NPBool Plugin::isInitialized()
{
return m_bInitialized;
}
NPObject* Plugin::GetScriptableObject()
{
// 创建对象
if (m_pScriptableObject == NULL)
{
m_pScriptableObject = NPN_CreateObject(m_pNPInstance, &objectClass);
PluginObject::_setOcx(m_pScriptableObject,this);
testPlugin = this;
}
// 增加对象的引用计数
if (m_pScriptableObject != NULL)
{
NPN_RetainObject(m_pScriptableObject);
}
return m_pScriptableObject;
}
int16_t Plugin::handleEvent(void *pEvent)
{
return 0;
}
PluginObject.h
#pragma once
#include "stdafx.h"
#include "pluginbase.h"
#include "Plugin.h"
//引入Plugin对象
static Plugin *testPlugin;
class PluginObject : public NPObject
{
public:
PluginObject(NPP);
~PluginObject(void);
public:
void setOcx(Plugin * plugin);
void deallocate();
void invalidate();
bool hasMethod(NPIdentifier methodName);
bool invokeDefault(const NPVariant *args, uint32_t argCount, NPVariant *result);
bool invoke(NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
bool hasProperty(NPIdentifier propertyName);
bool getProperty(NPIdentifier propertyName, NPVariant *result);
bool setProperty(NPIdentifier name,const NPVariant *value);
bool removeProperty(NPIdentifier name);
bool enumerate(NPIdentifier **identifier,uint32_t *count);
bool construct(const NPVariant *args,uint32_t argCount, NPVariant *result);
public:
static void _setOcx(NPObject *npobj,Plugin * plugin);
static NPObject* _allocate(NPP npp,NPClass* aClass);
static void _deallocate(NPObject *npobj);
static void _invalidate(NPObject *npobj);
static bool _hasMethod(NPObject* obj, NPIdentifier methodName);
static bool _invokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
static bool _invoke(NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
static bool _hasProperty(NPObject *obj, NPIdentifier propertyName);
static bool _getProperty(NPObject *obj, NPIdentifier propertyName, NPVariant *result);
static bool _setProperty(NPObject *npobj, NPIdentifier name,const NPVariant *value);
static bool _removeProperty(NPObject *npobj, NPIdentifier name);
static bool _enumerate(NPObject *npobj, NPIdentifier **identifier,uint32_t *count);
static bool _construct(NPObject *npobj, const NPVariant *args,uint32_t argCount, NPVariant *result);
private:
NPP npp;
Plugin * plugin;
};
#ifndef __object_class
#define __object_class
static NPClass objectClass =
{
NP_CLASS_STRUCT_VERSION,
PluginObject::_allocate,
PluginObject::_deallocate,
PluginObject::_invalidate,
PluginObject::_hasMethod,
PluginObject::_invoke,
PluginObject::_invokeDefault,
PluginObject::_hasProperty,
PluginObject::_getProperty,
PluginObject::_setProperty,
PluginObject::_removeProperty,
PluginObject::_enumerate,
PluginObject::_construct
};
#endif
PluginObject.cpp
#include"stdafx.h"
#include "PluginObject.h"
#include "Plugin.h"
#include "stdio.h"
#include "stdlib.h"
extern NPNetscapeFuncs NPNFuncs;
PluginObject::PluginObject(NPP npp):
npp(npp)
{
}
PluginObject::~PluginObject(void)
{
}
void PluginObject::deallocate()
{
}
void PluginObject::invalidate()
{
}
bool PluginObject::hasMethod(NPIdentifier methodName)
{
return false;
}
bool PluginObject::invokeDefault(const NPVariant *args, uint32_t argCount, NPVariant *result)
{
return true;
}
bool PluginObject::invoke(NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
return true;
}
bool PluginObject::hasProperty(NPIdentifier propertyName)
{
return false;
}
bool PluginObject::getProperty(NPIdentifier propertyName, NPVariant *result)
{
return false;
}
bool PluginObject::setProperty(NPIdentifier name,const NPVariant *value)
{
return true;
}
bool PluginObject::removeProperty(NPIdentifier name)
{
return true;
}
bool PluginObject::enumerate(NPIdentifier **identifier,uint32_t *count)
{
return false;
}
bool PluginObject::construct(const NPVariant *args,uint32_t argCount, NPVariant *result)
{
return true;
}
void PluginObject::setOcx(Plugin * ocx)
{
this->plugin= ocx;
}
// ========================================静态函数===============================================================
NPObject *PluginObject::_allocate(NPP npp,NPClass *aClass)
{
return new PluginObject(npp);
}
void PluginObject::_deallocate(NPObject *npobj)
{
((PluginObject*)npobj)->deallocate();
if(npobj)
{
delete npobj;
}
}
void PluginObject::_invalidate(NPObject *npobj)
{
((PluginObject*)npobj)->invalidate();
}
bool PluginObject::_hasMethod(NPObject* obj, NPIdentifier methodName)
{
return ((PluginObject*)obj)->hasMethod(methodName);
}
bool PluginObject::_invokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
return ((PluginObject*)obj)->invokeDefault(args,argCount,result);
}
bool PluginObject::_invoke(NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
return ((PluginObject*)obj)->invoke(methodName,args,argCount,result);
}
bool PluginObject::_hasProperty(NPObject *obj, NPIdentifier propertyName)
{
return ((PluginObject*)obj)->hasProperty(propertyName);
}
bool PluginObject::_getProperty(NPObject *obj, NPIdentifier propertyName, NPVariant *result)
{
return ((PluginObject*)obj)->getProperty(propertyName,result);
}
bool PluginObject::_setProperty(NPObject *npobj, NPIdentifier name,const NPVariant *value)
{
return ((PluginObject*)npobj)->setProperty(name,value);
}
bool PluginObject::_removeProperty(NPObject *npobj, NPIdentifier name)
{
return ((PluginObject*)npobj)->removeProperty(name);
}
bool PluginObject::_enumerate(NPObject *npobj, NPIdentifier **identifier,uint32_t *count)
{
return ((PluginObject*)npobj)->enumerate(identifier,count);
}
bool PluginObject::_construct(NPObject *npobj, const NPVariant *args,uint32_t argCount, NPVariant *result)
{
return ((PluginObject*)npobj)->construct(args,argCount,result);
}
void PluginObject::_setOcx(NPObject *npobj,Plugin* ocx)
{
return ((PluginObject*)npobj)->setOcx(ocx);
}
// ========================================静态函数===============================================================
pluginObject.h 因已调用plugin对象,所以只需要解析调用接口即可。
定义 映射方法名名称的变量
pluginObject.cpp 用于解析方法以及变量。
在npp中定义方法名:
PluginObject::PluginObject(NPP npp):
npp(npp)
{
//定义方法名称
funname0 = "Test";
}
hashMethod中判断js调用的方法是否存在
bool PluginObject::hasMethod(NPIdentifier methodName)
{
//判断是否包含方法
NPUTF8 *pName = NPNFuncs.utf8fromidentifier(methodName);
if (strcmp(pName, funname0) == 0) return true;
return false;
}
在invoke中解析方法参数,若符合条件,则调用指定方法
bool PluginObject::invoke(NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
//解析方法参数
char bitem[5000] = {0};
if (NPVARIANT_IS_STRING(args[0])){
NPString ritem = NPVARIANT_TO_STRING(args[0]);
memcpy(bitem, ritem.UTF8Characters, ritem.UTF8Length);
}
if (methodName == NPN_GetStringIdentifier(funname0)){
MessageBox(NULL,bitem,bitem,MB_OK);
testPlugin->Test(bitem);
return true;
}
return true;
}
以上为添加一个方法的步骤,若有多个,如此类推。
没有报错,则表示成功。可以在debug文件夹下查看生成的npplay.dll文件。
9、打包注册dll文件
需要把dll以及依赖文件一起打包注册,
可以参照http://blog.csdn.net/xuziyue214/article/details/56679005
注册成功后,应在注册表表看到注册信息
在火狐浏览器的插件中也应能看见插件信息
10、html测试npapi插件接口
新建html文件,代码如下
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>title>
<style>
html,body{
width:100%;
height:100%;
}
style>
head>
<body onload="videoload()">
<embed type="application/npplay" width="100%" height="100%" id="ocx">
<script>
function videoload(){
var ocx = document.getElementById('ocx');
var result = ocx.Test("123");
}
script>
body>
html>
在火狐下运行html,允许插件激活。刷新界面,应能跳出提示框。
提示框信息,是接口预留用于测试的,实际开发可去除。
到此,所有信息已整理完毕。
第一篇博文就这么拼凑完啦,千里之行第一步。学无止境,乐于分享。