由于公司要开发跨浏览器的多窗格播放器,比如4*4,3*3,这类的,IE下比较好解决,我采用的activex,但是却无法在chrome,和firefox下使用,需要使用npapi开发才行。最近研究了几天,把一些成果共享出来给大家。
其实在chrome和firefox下运行播放器有其他几个方法,比如使用ff-ativex,是chrome下的actviex插件;还有就是使用firebreath将actviex转换成npapi;当然我更喜欢来研究下基本的npapi的东西。
我基于的是
http://www.codeproject.com/Articles/92787/Working-on-an-NPAPI-browser-plugin 的 代码来进一步开发的,由于无法共享代码,所以我对一些问题可能描述的不是很清楚,但保证是可行的。
一般遇到的问题如下:
一:无法在chrome上运行
二:如何创建dialog
三:如何响应鼠标事件
四:接口调用
五:如何上报事件给web
一:无法在chrome上运行
在基于这个demo开发时,我一般想测试的时,这个dll库是否真的可以在chrome和firefox上运行,实际上他只能在firefox上运行,所以我首先就需要解决chrome上无法使用的问题。
其实你只要知道如何调试chrome的插件,其实发现问题也不难。chrome的调试方式是这样的:
1)将chrome的路径加入到环境变量 path中;
2)执行命令行(cmd),输入 chrome.exe --plugin-startup-dialog
3)将要执行的插件页面拖入chrome,这时会谈出一个进程框,然后用vs2008 attach上去即可。
经过调试,你会发现,其实在chrome中这个demo 会出现异常,大概在这里
NPString str;
str.UTF8Characters = "document.getElementById('result').innerHTML += '<p>' + 'NPN_Evaluate() test, document = ' + this + '</p>';";
str.UTF8Length = strlen(str.UTF8Characters);
NPN_Evaluate(m_pNPInstance, doc, &str, NULL);
NPN_Evaluate的最后一个参数不能为NULL,所以你只要自己添加一个变量即可。
二:如何创建dialog
因为要设计播放器窗口,那么dlg是必须的,不让我怎么哪来的显示句柄呢?查过不少资料,才发现,创建dlg应该使用 CreateDialog函数,在res资源文件中创建一个dlg资源,然后CreateDialog一个dlg,需要注意的是资源中dlg的任何影响事件都不会被捕获,原因我不知道,没具体研究过。所以考虑到这个问题,我就有必要重新考虑整个播放器设计的架构了。
npapi对dlg支持的有缺陷,那不用dlg是否可行呢? 我后来整改了设计,使用CStatic 替代了dlg,一切都很顺利。
设计架构大致如下:
一个基础dlg,里面放16个CStatic , 因为dlg作为容器是必须的,但是容器的却使用CStatic(当然我重载了CStatic);
高兴的是,如果自己重载CStaticEX,并创建可捕获消息的CStatic,那么就可以把CStatic当成一个dlg来使用,鼠标左键,右键事件,鼠标移动事件都可以捕获,和Activex开发一模一样,真是太好了。
三:如何响应鼠标事件
四:接口调用
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;
}
五:如何上报事件给web
有时候函数调用不是单向的,也需要插件上报消息给web, activex使用的是事件机制, 而NPAPI则采用函数调用。你可以参考demo中的例子OBJECT_TO_NPVARIANT(doc, v);
NPN_SetProperty(m_pNPInstance, sWindowObj, n, &v);
NPString str;
str.UTF8Characters = "document.getElementById('result').innerHTML += '<p>' + 'NPN_Evaluate() test, document = ' + this + '</p>';";
str.UTF8Length = strlen(str.UTF8Characters);
NPN_Evaluate(m_pNPInstance, doc, &str, NULL);
NPN_ReleaseObject(doc);
你看NPN_Evaluate 的目的是什么? 其实就是将str的字符串通过这个接口在web上调用。 所以你可以将str写成一个js函数,然后将参数转换成xml字符串作为函数参数,通过NPN_Evaluate来执行,而js只要在js函数中解析该xml参数就可以了。