VS2010 编写NPAPI 插件

来源:互联网 发布:阿里云 docker收费 编辑:程序博客网 时间:2024/05/22 04:58

近日因要使用第三方Activex插件,但是火狐浏览器不支持,故用到了NPAPI封装插件。在此记录一笔,以便日后查阅。

准备工作

  • 安装好VS2010;
  • 下载依赖库 plugin sdk;http://pan.baidu.com/s/1qY76lvm

动手吧

1、创建项目

新建Win32项目

项目名取名“npplay”,项目名最好以“np”开头。创建新的解决方案,默认方案名与项目名一致。也可以选择已有的解决方案。点击“确认”,进入下一步。

这里写图片描述

点击“下一步”

这里写图片描述

选择dll应用程序,点击完成。

2、配置项目属性
1)选中项目右击选择“属性”,进入属性界面。
这里写图片描述

进入 配置属性->C/C++->常规->附加包含目录;
选择编辑添加 plugin解压后的目录 ~\plugin\base\public
(我本地解压到E:\vs_workspace\);
这里写图片描述

2)进入 配置属性->C/C++->预处理器->预处理器定义;
选择编辑,换行添加 _X86_

这里写图片描述

3)进入 配置属性->常规->字符集;
修改为 “使用多字节字符集”,不是必须的。

这里写图片描述

3、添加现有项
项目需要依赖Plugin基础文件,进行二次开发。所以从plugin文件中复制以下文件到工程目录中。
npplat.h
pluginbase.h
np_entry.cpp
npn_gate.cpp
npp_gate.cpp

把文件添加到系统中。

这里写图片描述

添加.h现有项

这里写图片描述

添加.cpp现有项

注意:cpp文件中需要添加 #include "stdafx.h",不然会报错。

4、添加def文件

添加def

编辑def文件如下

LIBRARY "npplay"EXPORTSNP_GetEntryPoints   @1NP_Initialize       @2NP_Shutdown     @3

EXPORTS 内容是默认写法 LIBRARY 后面内容自定义。

5、添加rc文件
这里写图片描述

编写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 0x0LBEGIN    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    ENDEND

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 <Windows.h>#include <WindowsX.h>#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_classstatic 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);}// ========================================静态函数===============================================================

7、添加接口方法
plugin.h 定义接口
这里写图片描述

plugin.cpp 实现接口
这里写图片描述

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;}

以上为添加一个方法的步骤,若有多个,如此类推。

8、编译项目,生成dll文件
这里写图片描述

没有报错,则表示成功。可以在debug文件夹下查看生成的npplay.dll文件。

9、打包注册dll文件
需要把dll以及依赖文件一起打包注册,
可以参照http://blog.csdn.net/xuziyue214/article/details/56679005

注册成功后,应在注册表表看到注册信息

这里写图片描述

在火狐浏览器的插件中也应能看见插件信息

这里写图片描述

10、html测试npapi插件接口
新建html文件,代码如下

<!DOCTYPE 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,允许插件激活。刷新界面,应能跳出提示框。
这里写图片描述

这里写图片描述

提示框信息,是接口预留用于测试的,实际开发可去除。

到此,所有信息已整理完毕。

子曰:

第一篇博文就这么拼凑完啦,千里之行第一步。学无止境,乐于分享。

0 0
原创粉丝点击