NPAPI 原本是由 Netscape 所制定的一組單純的 C Plugin API,起初是無法支持 Scriptability;於是到了 2004 年底,各家 Browser ( IE , Opera, Mozilla 等) 都同意支持NPRuntime 延伸 API 以支持 Scriptability,所以目前若是想寫 Plugin則應該以 NPRuntime API 才能跨不同的 Browsers。
先介紹下瀏覽器的生命週期。
1.瀏覽器搜索加載DLL文件。
2.瀏覽器調用NP_GetEntryPoints, NP_Initialize()來初始化瀏覽器和插件的函數映射表。
i.調用瀏覽器端的 NP_Initialize,將函數傳給插件的函數表。
ii.插件將定義好的函數通過NP_GetEntryPoints,傳遞到NPPluginFuncs中,讓瀏覽器可以調用。
3.瀏覽器調用插件的NPP_GetValue,得到插件的對象,若支持js交互,則通過NPPVpluginScriptableNPObject來判斷創建m_pScriptableObject對象。
4.瀏覽器通過HTML中的MIMTYPE,調用插件的NP_New來創建插件實例。然後對插件進行業務處理。
5.瀏覽器關閉頁面時,調用插件的NPP_Destory來銷燬插件實例。
6.瀏覽器關閉時,調用NP_shutdown關閉所有的資源。
以上就是瀏覽器插件的生命週期。
下面來看下NPRuntime的執行過程。
瀏覽器調用插件的方法的順序,基本上爲: NP_GetEntryPoints 、 NP_Initialize 、 NPP_New 、 NPP_SetWindow 、 NPP_GetValue 。在 NPP_New 中,我們需要創建插件對象的實例, NPP_SetWindow 中,瀏覽器會傳入插件窗口的信息,最後一個 NPP_GetValue ,是瀏覽器來獲取一些插件信息的。 NPP_GetValue 函數的結構是這樣的:
NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value);
· instance 包含着插件對象實例;
· variable 表示瀏覽器要獲取的信息的類型 ;
· value 表示返回給瀏覽器的值
i.瀏覽器會傳入NPPVpluginScriptableNPObject(作爲variable參數)來查詢插件是否支持Scriptable功能(即和腳本語言交互的功能)
ii.可以利用NPN_CreateObject方法來創建一個NPObject對象,並且作爲value返回給瀏覽器。
iii.瀏覽器就通過這個NPObject對象和我們的插件建立了連接。
V.當頁面上Javascript調用了我們插件對象的某個方法時,瀏覽器會調用該NPObject對象的HasMethod方法來查詢是否支持這個方法,
VI.如果支持,則會調用NPObject對象的Invoke方法,傳入方法名、參數等信息。
VII.這樣,我們就可以讓網頁上的腳本語言來執行我們編寫的函數了。
VIII.在Windows上,我們編寫的函數就如同編寫普通的應用程序一樣,可以使用很多Windows API來完成許多複雜的工作。
如下圖。
其中NPRuntime插件對象如下圖:
插件和js交互時,js調用插件的屬性和方法,調用getProperty,hasMethod,invoke方法即可。
如何定義一個方法(或屬性)?
1、添加一個方法(或屬性)很簡單,先定義一個靜態NPIdentifier類型的變量,例如:
static NPIdentifier s_idSetArgs;
2、在插件對象構造函數中,使用NPN_GetStringIdentifier方法來設置該方法的名稱,例如:
s_idSetArgs = NPN_GetStringIdentifier(“SetArgs”);
其中,SetArgs就是我們提供給腳本語言調用的方法名稱。
3、在ScriptablePluginObject的HasMethod方法中,判斷傳入的方法名:
bool ScriptablePluginObject::HasMethod(NPIdentifier name)
{
char *pProp = NPN_UTF8FromIdentifier(name);
//Check which Properties are available
if( !strcmp( "Add", pProp ) )
{
return true;
}
if(name == s_idSetArgs)
{
printf("method name = SetArgs\n");
return true;
}
return false;
}
4.在Plugin的Invoke方法中,判斷如果傳入的方法名稱等於我們定義的方法名,則做你想要做得事情:
bool
ScriptablePluginObject::Invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
//kk
char *pFunc = NPN_UTF8FromIdentifier(name);
if( !strcmp( "Add", pFunc ) )
{
int sum = 0;
for( unsigned int i = 0; i < argCount; i++ )
{
if( args[i].type == NPVariantType_Int32 )
{
sum += args[i].value.intValue;
}
else if( args[i].type == NPVariantType_String )
{
CNPString s(args[i].value.stringValue);
sum += atoi( s );
}
else
return false;//an error happenend
}
//value for GUI output
sprintf( m_szTextGui, "Sum = %ld", sum );
//triggering
::InvalidateRect( m_hWnd, 0, true );
//nice and handy little helpers, there are more of it
INT32_TO_NPVARIANT( sum,*result);
return true;
}
return false;
}
在HTML中調用方法如下。
<embed type="application/npruntime" width=600 height=200 id="plugin">
JS調用Add方法如下:
function Add()
{
try
{
//if( CheckBrowser() ) return;
var a1 = document.getElementById("f1").value;
var a2 = document.getElementById("f2").value;
alert("test");
var res = PLUGIN.Add(a1,a2);//we can also add numbers and strings (because of the plugin implementation)
alert( "Plugin Added result is: " + res );
}
catch (err) { alert(err); }
}
這裏就可以JS和瀏覽器插件進行交互了。