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