一.Netscape Plugin Interface(NPAPI)javascript
大體的說明能夠看下官方文檔Pluginhtml
本文主要針對於JavaScript與插件交互部分作一些交流,好比用於數字證書的操做(淘寶和支付寶的插件),用於播放的flash player插件等java
與javascript的交互須要用到NPAPI中的npruntime Scripting pluginsgit
下面的部分將以示例的方式說明整個過程如何去實現github
在開始前須要從火狐瀏覽器源代碼中獲取接口頭文件火狐4.0.1源碼下載docker
下載後在\firefox-4.0.1.source\mozilla-2.0\modules\plugin能夠找到一些samples和頭文件windows
這裏爲方便下載,上傳了一份單獨的plugin文件夾api
另外,基於NPAPI的一個跨瀏覽器插件開發的框架FireBreath,很是容易上手並且聽說跨瀏覽器的支持很是好,可是很是笨重,有些功能不須要的也不太容易去掉數組
Firebreath,有興趣的能夠去了解下,Firebreath的源代碼也能夠做爲基於NPAPI開發的一些參考瀏覽器
還有一個基於NPAPI作的簡單的示例,結構很是簡單,不用繞來繞去,相對理解起來也簡單許多
二.插件入門開發的示例
開發工具爲visual studio 2010
1.新建一個Win32 project,命名以np開頭(目的是編譯完的Dll名必須以np開頭才能被識別爲插件)
類型爲一個DLL的空工程便可
2.右鍵選中項目的屬性,在VC++ Directories目錄下,選擇Include Directories,Edit,
將plugin/base/public和plugin/sdk/samples/include添加到include
3.新建Version資源文件
4.新建一個Module-Definition File(.def),定義入口函數
5.新建一個CPlugin類繼承nsPluginInstanceBase,做爲插件實例類(後面再說該類的做用)
肯定以後,在plugin.h中#include <pluginbase.h>
類名爲Cplugin,頭文件名爲plugin.h,(npp_gate.cpp會使用到,不一樣能夠修改)
修改構造函數的實現,帶參數NPP類型並新建一個屬性保存該參數
實現父類的三個純虛函數
6.省得作過多操做,從samples中引入已經編寫好的入口函數
從plugin\sdk\samples\npruntime路徑添加np_entry.cpp(插件入口函數),npn_gate.cpp(插件調用瀏覽器的一些方法),npp_gate.cpp(瀏覽器調用插件的一些方法)
添加後須要作一點修改,
1).np_entry.cpp和npn_gate.cpp的引用
#include "npapi.h"
#include "npfunctions.h"
換成
#include<pluginbase.h>
2).而後進入pluginbase.h,再進入npplat.h,將
#ifdef XP_WIN
#include "windows.h"
#endif
挪到
#include "npapi.h"
#include "npfunctions.h"
前面,
3).而後在項目屬性,Preprocessor,Preprocessor Definitions添加XP_WIN的定義
(這樣作的緣由是windows.h須要在npapi.h前定義,本身在全部引用了npapi.h的前面加上windows.h的引用也能夠)
4),np_entry.cpp中引入頭文件#include <stddef.h>
由於使用到offsetof
這三個文件中的函數很是重要,首先來看下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步作說明
該文件中用到的NPNetscapeFuncs NPNFuncs;在NP_Initialize中初始化完成
7.封裝一個腳本操做對象
Add一個C++類,該示例命名爲PluginObject,繼承NPObject
添加靜態方法,用於建立該腳本操做的對象
在PluginObject.h中聲明一個NPClass對象,使用上面的靜態方法將該NPClass對象初始化
在該方法中經過NPNCreateObject方法建立該對象
NPN_CreateObject會在瀏覽器中作一些操做而後回來調用objectClass中的_allocate方法
須要實現該靜態方法,new 一個PluginObject
新建一個NPP npp屬性,和一個NPP參數的構造函數
後面的操做中,瀏覽器調用了NPNFunc中以上的一些方法則會來調用這些靜態方法,並將_allocate返回的值做爲參數傳到其餘函數中
接下來的實現就相對比較隨意了,能夠直接在這些靜態方法中實現想要的效果,
也能夠在PluginObject中建立對應的成員函數實現,而後在靜態方法中經過nobj參數轉換爲(PluginObject)類型調用相應成員函數
其中幾個函數比較重要,_hasMethod判斷參見是否有該函數,_getProperty則是判斷屬性,invoke調用相應方法,
invokeDefault能夠在invoke中調用NPN_InvokeDefault來訪問,最好不要直接調用,(見API,緣由未知,通常瀏覽器都要作進一步操做)
hasMethod等方法的相似於參數methodName都是以identifier做爲判斷的,能夠調用NPN_GetStringIdentifier獲取
例如:
多說下enumerate方法或者說是NPN_XXX的方法,由於就這個東西折騰我完完整整的兩天時間...
enumerate方法的參數有個指針數組,可是他的結構是
並且初始化的時候必定要用NPN_MemAlloc來操做....API上只有關於指針數組的結構說明,並且很簡單的提了一句,折騰兩天才發現非得用NPN來分配內存- -||
弱弱的總結下,應該是須要給Firefox用到的東西或者說從參數傳進來須要你分配內存的都得用NPN_MemAlloc分配內存
若是出現Access Violation,首先想到什麼地方應該用NPN_MemAlloc....
三.註冊及安裝
1.註冊表註冊位置
HKEY_CURRENT_USER\Software\MozillaPlugins
添加一個項@whuiss.com/npTest
添加字符串值
"Description"="code project test"
"Path"="path to 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中按照上面的位置給添加上相應信息便可
四.使用插件
五.調試插件
先前一直弄錯了,覺得是指向Firefox.exe,查了很久,發現原來在Firefox4以後新建了一個plugin-Container.exe進程
調試目標指向plugin-container.exe 或者 tools->attach to process選中plugin-container.exe進程 或者debug->attach to process
六.附上示例工程
打開工程後須要修改include directory
------------------------------------------------------分割線-----------------------------------------------------
發現個新問題,NPAPI執行函數返回值不支持帶中文的麼?
調試不少次了,也不知道是配置問題仍是什麼問題,NPVariant *result中帶有值返回的
可是到瀏覽器就變成空字符串,去掉中文的就能正常顯示
Firebreath的也試過了,也不支持中文字符
沒辦法,只好將返回的值轉成base64再在瀏覽器解碼,這樣卻是能夠正常
------------------------------------------------------分割線-----------------------------------------------------
firefox新版本 彈出winform(例如訪問某些智能卡私鑰會須要輸入PIN)的時候致使假死的狀況,在火狐社區提問了,可以解決
http://mozilla.com.cn/post/31422/#reply-24747
大體意思就是修改config裏面的dom.ipc.plugins.enabled.your-plugin.dll=false
from:http://blog.csdn.net/hzzhoushaoyu/article/details/7387516