通常,在插件中如果要調用JS的函數可以使用NPN_InvokeDefault()來實現,但是調用NPN_InvokeDefault必須要在JS的調用棧中(JS線程)。
比如,JS有兩個函數j-a,j-b,在C++中有函數c-a。那麼如果要在c-a中使用NPN_InvokeDefault調用j-b,則必須是j-a調用了c-a,形成j-a -> c-a -> j-b這樣的調用鏈路。
以上的C++調用JS的方法顯然不能滿足多數時候的需求,因爲我們很多時候會執行異步操作,比如如果c-a要執行很長時間,我們不可能讓j-a等着c-a執行完,這樣的話UI就會阻塞。所以通常我們的做法是在j-a中通知c-a幹活(c-a在別的線程中),當c-a完成任務後調用j-b返回結果,這個時候,就需要用到NPN_PluginThreadAsyncCall()了。從名字就可以看出來這是個跨線程異步調用的方法。
由於這個東西的資料比較少(我當時是中文沒搜到然後英文搜索然後搞到個文檔總結完成的),所以在這裏做個總結希望能幫助大家節省時間。
NPN_PluginThreadAsyncCall()的使用方法比較簡單,就相當於做幾個配置,將NPN_PluginThreadAsyncCall()的聲明與NPAPI框架提供的功能做一個掛接。
1.其實在npapi.h中已經有NPN_PluginThreadAsyncCall()的聲明,但沒有定義,所以,我們首先給它做定義:
在npn_gate.cpp中添加NPN_PluginThreadAsyncCall()函數定義
void NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance, void (*func) (void *), void *userData)
{
NPNFuncs.pluginthreadasynccall(instance, func, userData);
}
2.大家應該知道NPNFuncs是一個結構體,其實pluginthreadasynccall是它一個函數指針(定義在npfunctions.h),既然要用這個指針,那麼肯定需要給它賦值。所以,這一步我們給NPNFuncs.pluginthreadasynccallf賦值,在np_entry.cpp的NP_Initialize()函數中添加對NPNFuncs.pluginthreadasynccallf的賦值
NPNFuncs.pluginthreadasynccall = pFuncs->pluginthreadasynccall;
其中pFuncs 和 NPNFuncs 是同一個類型的結構體(當然,pFuncs是這種類型的結構體的指針),NP_Initialize()函數中對NPNFuncs成員 的所有賦值操作就等於是將pFuncs所指向的結構體的內容存儲在了NPNFuncs中(當然是選擇性的複製,不然就memecpy了)。而看起來pFuncs 則是來自於NPAPI框架的。
從上訴的情況看來,其實一開始NPAPI框架在NP_Initialize()初始化的時候是把所有的功能都帶進來的(通過pFuncs參數帶進來),但是給NPNFuncs賦值的過程中會選擇性的屏蔽一些不需要的功能。而我們需要使用更多功能的時候就需要按照以上的方法做掛接(即將pFuncs 的功能賦值到NPNFuncs,並且爲NPNFuncs的該功能函數指針定義個調用接口函數如NPN_PluginThreadAsyncCall。而且通常來說這個接口函數在npapi.h中已經聲明)。
根據以上步驟就完成了 NPN_PluginThreadAsyncCall的掛接,那麼下面我們來看看這個函數怎麼使用。
可以看到其函數原型爲void NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance, void (*func) (void *), void *userData),其中參數instance就不說了,會用NPN_InvokeDefault
你就知道。 而參數func則是你期望的一個能夠調用JS函數的函數,通常組成爲
func()
{
... ...
NPN_InvokeDefault(instance, JS回調函數在本地的保存,參數,返回值)
... ...
}
第三個參數是傳遞給func的參數
爲了讓觀衆更直觀的理解,我把我的代碼貼出來(當然代碼裏因爲使用類,含有一些私有變量,所以並不是func裏面就調用NPN_InvokeDefault了,而是經過了一次拆包過程)
:
int PluginObject::CallJsFunAsync()//這是一個封裝,供類對象裏別的地方使用。其中NPN_PluginThreadAsyncCall()的第三個參數爲該對象
{
NPN_PluginThreadAsyncCall(npp, PluginObject::AsyncCallJsFun, this);
return 0;
}
void PluginObject::AsyncCallJsFun(void *param)//NPN_PluginThreadAsyncCall()的第二個參數
{
if(!param)
{
return ;
}
PluginObject* obj = static_cast<PluginObject*>(param);//將參數還原爲類對象,並調用類對象的方法。
obj->CallJsFun(obj->GetPicNameAndPath());
}
int PluginObject::CallJsFun(char *pStr)//在這個函數裏最終調用JS的函數(通過NPN_InvokeDefault)
{
int iRev = 0;
if (m_pJSCallbackFunObj != NULL && strlen(pStr) < FILE_PATH_LEN)
{
NPVariant result;
// 轉換參數列表
NPVariant relements[1];
char callbackParam[FILE_PATH_LEN] = "";
strcpy(callbackParam, pStr);
STRINGZ_TO_NPVARIANT(callbackParam, relements[0]);
// 調ì用JS函數
BOOL ret = NPN_InvokeDefault(npp, m_pJSCallbackFunObj, relements, 1, &result);
NPN_ReleaseVariantValue(&result);
}
return iRev;
}