NPAPI插件開發學習:NPAPI的運行流程

http://blog.csdn.net/zssureqh/article/details/9455855

轉載一篇介紹NPAPI運行流程的博文,原文出處:

http://hxis9e2q.i.sohu.com/blog/view/208654665.htm

Netscape Plugin Interface(NPAPI)

大致的說明可以看下官方文檔Plugin

本文主要針對於javascript與插件交互部分做一些交流,比如用於數字證書的操作(淘寶和支付寶的插件),用於播放的flashplayer插件等

javascript的交互需要用到NPAPI中的npruntime Scriptingplugins

下面的部分將以示例的方式說明整個過程如何去實現

 在開始前需要從火狐瀏覽器源代碼中獲取接口頭文件火狐4.0.1源碼下載

下載後在\firefox-4.0.1.source\mozilla-2.0\modules\plugin可以找到一些samples和頭文件,這裏爲方便下載,上傳了一份單獨的plugin文件夾

另外,基於NPAPI的一個跨瀏覽器插件開發的框架FireBreath,非常容易上手而且據說跨瀏覽器的支持非常好,但是非常笨重,有些功能不需要的也不太容易去掉,有興趣的可以去了解下,Firebreath的源代碼也可以作爲基於NPAPI開發的一些參考,還有一個基於NPAPI做的簡單的示例,結構非常簡單,不用繞來繞去,相對理解起來也簡單許多(npsimple

插件入門開發的示例 

可以參考的資料很多,這裏刪除了原文中的實例,相關的例子很多,此處僅提供參考地址:

http://hxis9e2q.i.sohu.com/blog/view/208654665.htm

http://www.cnblogs.com/chingliu/archive/2011/12/03/2288635.html

http://blog.csdn.net/z6482/article/details/7660748

分析np_entry.cppnpp_gate.cppnpn_gate.cpp三個文件

這三個文件中的函數非常重要。

 首先來看下np_entry.cpp中的函數

NP_GetEntryPoints函數,爲插件入口的函數,插件初始化將會首先調用該函數

該函數用於初始化瀏覽器調用插件的函數表,NPP(np plugin)開頭,

後面的插件的一些事件(new)發生時將會以這裏初始化的函數作爲入口,比如

 pFuncs->newp = NPP_New;初始化後將會在創建插件實例時調用NPP_New的實現來創建.

NP_Initialize函數,初始化插件時,NP_GetEntryPoints後調用,

該函數用於初始化插件調用瀏覽器的函數表,參數pFuncs帶有該函數表信息,

我們自定義一個對象保存這些信息,今後就可通過該對象調用方法來實現對瀏覽器的一些操作

NP_Shutdown函數,NP_Initialize對應,主要釋放資源等操作

 再來看下npp_gate.cpp

這個文件中的函數都以NPP開頭,用於定義瀏覽器調用插件的方法

經過NP_GetEntryPoints的初始化後,當特定事件發生時,瀏覽器將會調用這些方法

然後需要注意的是該文件引用了plugin.h,是我們第5步創建的文件,名字不同可以改改

NPP_New方法,用於創建插件實例CPlugin * pPlugin = new CPlugin(instance);這句話爲創建一個我們定義的CPlugin類對象,構造函數爲NPP類型

NPP_Destroy方法,用於銷燬插件實例,刷新頁面,關閉頁面等操作會觸發該方法會調用CPluginshut方法再delete掉實例

NPP_SetWindow方法,插件窗口發生任何變化都會調用該方法window創建時會調用一次,如果初始化失敗則delete掉實例然後返回錯誤

NPP_GetValue方法,當獲取插件有關的一些信息時會觸發該方法調用(如獲取插件名,插件實例)

javascript操作插件對象時,該方法調用CPluginGetScriptableObject方法,需要自己實現,返回一個腳本操作對象(NPObject)。在這裏返回到CPlugin,添加GetScriptableObject方法並實現(見第7步操作)

NPP_HandleEvent方法,處理事件,該方法調用CPluginhandleEvent方法,繼續添加實現吧

該文件中其他方法暫時沒什麼可說的,需要用到的可以查下API並實現出來就行了.

再看下npn_gate.cpp

該文件實現了對瀏覽器的一些操作的函數,都以NPN(np netscape)開頭其中有一些帶有NPObject*參數的與GetScriptableObject方法創建的腳本操作對象有關,將在第7步做說明

該文件中用到的NPNetscapeFuncsNPNFuncs;

NP_Initialize中初始化完成

封裝一個腳本操作對象

Add一個C++,該示例命名爲PluginObject,繼承NPObject

添加靜態方法,用於創建該腳本操作的對象

public: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);staticbool _removeProperty(NPObject *npobj, NPIdentifier name);static bool_enumerate(NPObject *npobj, NPIdentifier **identifier,uint32_t *count);staticbool _construct(NPObject *npobj, const NPVariant *args,uint32_t argCount,NPVariant *result);
PluginObject.h中聲明一個NPClass對象,使用上面的靜態方法將該NPClass對象初始化

#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回到第6步中在CPlugin類中實現的GetScriptableObject方法

在該方法中通過NPNCreateObject方法創建該對象

NPObject*CPlugin::GetScriptableObject(){return NPN_CreateObject(this->instance,&objectClass);}this->instance在構造函數時獲取並保存下來的NPP對象.

NPN_CreateObject會在瀏覽器中做一些操作然後回來調用objectClass中的_allocate方法

需要實現該靜態方法,new 一個PluginObject

新建一個NPP npp屬性,和一個NPP參數的構造函數

NPObject*PluginObject::_allocate(NPP npp,NPClass* aClass){return new PluginObject(npp);}

後面的操作中,瀏覽器調用了NPNFunc中以上的一些方法則會來調用這些靜態方法,並將_allocate返回的值作爲參數傳到其他函數中

接下來的實現就相對比較隨意了,可以直接在這些靜態方法中實現想要的效果,

也可以在PluginObject中創建對應的成員函數實現,然後在靜態方法中通過nobj參數轉換爲(PluginObject)類型調用相應成員函數

其中幾個函數比較重要,_hasMethod判斷參見是否有該函數,_getProperty則是判斷屬性,invoke調用相應方法,

invokeDefault可以在invoke中調用NPN_InvokeDefault來訪問,最好不要直接調用,(API,原因未知,一般瀏覽器都要做進一步操作)

hasMethod等方法的類似於參數methodName都是以identifier作爲判斷的,可以調用NPN_GetStringIdentifier獲取

例如:

PluginObject::PluginObject(NPPnpp){this->npp = npp;id_func_add =NPN_GetStringIdentifier("add");id_property_version =NPN_GetStringIdentifier("version");}boolPluginObject::hasMethod(NPObject* obj, NPIdentifiermethodName){if(methodName==this->id_func_add)return true;return false;}
多說下enumerate方法或者說是NPN_XXX的方法,因爲就這個東西折騰我完完整整的兩天時間...

enumerate方法的參數有個指針數組,但是他的結構是

而且初始化的時候一定要用NPN_MemAlloc來操作....API上只有關於指針數組的結構說明,而且很簡單的提了一句,折騰兩天才發現非得用NPN來分配內存- -||

boolPluginObject::enumerate(NPIdentifier **identifier,uint32_t *count){ *count = 1;NPIdentifier *outList(NULL);outList =(NPIdentifier*)NPN_MemAlloc((uint32_t)(sizeof(NPIdentifier) * *count));outList[0] = id_property_version; *identifier = outList; return true;}測試的時候在firebug的控制檯輸入plugin. 就會去調用enumerate

註冊及安裝

1.註冊表註冊位置

HKEY_CURRENT_USER\Software\MozillaPlugins

添加一個項@whuiss.com/npTest

添加字符串值

"Description"="code projecttest"
"Path"="
pathto npTest.dll"
"ProductName"="npdemo Dynamic Library"
"Vendor"="zsy"
"Version"="1.0.0.1"

添加子項MIMETypes

添加MIMETypes的子項application/x-npTest

但是實際上只需要一個項@whuiss.com/npTest以及一個Path字符串值,其他可有可無

firefox地址欄輸入about:plugins可查到你的插件了

2.使用安裝文件註冊

visual studio新建一個set up project

FileSystem View中選中dll或者某個工程的輸出

Registry View中按照上面的位置給添加上相應信息即可

使用插件

<html><head><script>window.onready= function(){}function toDoSt(){var plugin =document.getElementById("plugin");alert(plugin.version);}</script><embedid="plugin" type="application/x-npTest" src="file:///pathto npTest.dll" pluginspage="http://xxxx"></head><body><inputtype="button" οnclick="toDoSt()"value="test"></body></html>其中embedsrcpluginspage可有可無

調試插件

先前一直弄錯了,以爲是指向Firefox.exe,查了好久,發現原來在Firefox4之後新建了一個plugin-container.exe進程

調試目標指向plugin-container.exe或者tools->attach to process選中plugin-container.exe進程或者debug->attachto process

參考:http://blog.csdn.net/z6482/article/details/7664789


發佈了7 篇原創文章 · 獲贊 6 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章