NPAPI 開發, C++跨線程回調JS函數

通常,在插件中如果要調用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;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章