轉 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.cpp、npp_gate.cpp、npn_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方法,用於銷燬插件實例,刷新頁面,關閉頁面等操作會觸發該方法會調用CPlugin的shut方法再delete掉實例
NPP_SetWindow方法,插件窗口發生任何變化都會調用該方法window創建時會調用一次,如果初始化失敗則delete掉實例然後返回錯誤
NPP_GetValue方法,當獲取插件有關的一些信息時會觸發該方法調用(如獲取插件名,插件實例)
當javascript操作插件對象時,該方法調用CPlugin的GetScriptableObject方法,需要自己實現,返回一個腳本操作對象(NPObject)。在這裏返回到CPlugin類,添加GetScriptableObject方法並實現(見第7步操作)
NPP_HandleEvent方法,處理事件,該方法調用CPlugin的handleEvent方法,繼續添加實現吧
該文件中其他方法暫時沒什麼可說的,需要用到的可以查下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>其中embed的src和pluginspage可有可無
調試插件
先前一直弄錯了,以爲是指向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