chrome NPAPI插件和扩展

最近没什么事情,随便整点什么。

插件功能是提高QVOD 的chrome支持。好像已经有好的了,只是想学习下怎么写插件。

这里记录下学到的几个知识点。

1、因为有的网页会动态刷新,因此选择执行插件的时机和重新执行很重要。

1)页面更新是执行某js或js代码

function InsertFunc(tabId,changeInfo,tab)
{
chrome.tabs.executeScript(tabId,{file : “q.js”,allFrames :true});
return true;
}

//注册事件的响应函数
chrome.tabs.onUpdated.addListener(InsertFunc);  页面更新时,执行一个js文件。

2)js执行时间

“content_scripts”: [ {
“js”: [ “q.js” ],

“matches”: [ “http://*/*”, “https://*/*”,”file://*/*” ],

“run_at”: “document_end”,//start”,//”document_end”, // 共三个选项,还有一个 document_idle。
“all_frames”: true //在所有的iframe 中起作用 作用于有多个 iframe的网页。

3、NPAPI插件开发模型:

很简单,但是各个浏览器不太一样,在chrome中,如果 hasProperty  、getProperty 没有实现,需要返回 false,而不是 ture。

其他函数 都很简单,看例子就可以明白。

#include <stdio.h>
#include <windows.h>
#include <npapi.h>
#include <npfunctions.h>
#include <npruntime.h>
static NPNetscapeFuncs Browser;
NPNetscapeFuncs * browser=&Browser;

char * MIMEtype=”application/xl_qvod_plugin”;

static const char *plugin_method_name_open = “GetQvodPlayerStart”;

char processpath[256] = “”;//”D:\\Program Files\\QvodPlayer\\QvodPlayer.exe”;

char processpath_1[] = “D:\\Program Files\\QvodPlayer\\QvodPlayer.exe”;

bool plugin_has_method(NPObject *obj, NPIdentifier methodName);
bool plugin_invoke(NPObject *obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result);
bool hasProperty(NPObject *obj, NPIdentifier propertyName);
bool getProperty(NPObject *obj, NPIdentifier propertyName, NPVariant *result);
bool invokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result);
static struct NPClass scriptablePluginClass = {
NP_CLASS_STRUCT_VERSION,
NULL,
NULL,
NULL,
plugin_has_method,
plugin_invoke,
invokeDefault,
hasProperty,
getProperty,
NULL,
NULL,
NULL,
NULL,
};
bool plugin_has_method(NPObject *obj, NPIdentifier methodName)
{

NPUTF8 *name = browser->utf8fromidentifier(methodName);

return true;
}

bool plugin_invoke(NPObject *obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
{

NPUTF8 *name = browser->utf8fromidentifier(methodName);

if (strcmp(name,”QvodPlayerStart”) == 0 && processpath && argCount == 1)
{

char * fileurl = (char *)NPVARIANT_TO_STRING(args[0]).UTF8Characters;
char qvodcmd[2048] = “”;
sprintf_s(qvodcmd,”%s%s%s”,processpath,” -qvodurl “,fileurl);
system(qvodcmd);
}
return true;

}

bool invokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result)
{

result->type = NPVariantType_Int32;
result->value.intValue = 42;
return true;
}
bool hasProperty(NPObject *obj, NPIdentifier propertyName)
{

return false;
}

bool getProperty(NPObject *obj, NPIdentifier propertyName, NPVariant *result)
{

return false;
}
//接口的实现

/*
在此函数获得快播地址
*/
NPError OSCALL NP_Initialize(NPNetscapeFuncs * aNPNFuncs)
{

if(aNPNFuncs)
{
browser=aNPNFuncs;
char regkey[] = “CLSID\\{F3D0D36F-23F8-4682-A195-74C92B03D4AF}\\InprocServer32″;//”Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders”;

ULONG dType = REG_SZ;
char cachepath[128];
DWORD siz = 128;
HKEY hKey;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, regkey, 0, KEY_QUERY_VALUE, &hKey)==0)
{
RegQueryValueEx(hKey, NULL, 0, &dType,(LPBYTE) cachepath, &siz);
if(siz != 0)
{
for(int i = siz -1;i >= 0 ;i –)
{
if (cachepath[i] == ‘\\’)
{
cachepath[i+1] = ”;
sprintf_s(processpath,”%s%s”,cachepath,”QvodPlayer.exe”);

break;
}
}
}

RegCloseKey(hKey);
}

return NPERR_NO_ERROR;
}
else
{
return NPERR_INVALID_FUNCTABLE_ERROR;
}

}
NPError OSCALL NP_GetEntryPoints(NPPluginFuncs * pluginFuncs)
{
pluginFuncs->version = 1;
pluginFuncs->size = sizeof(NPPluginFuncs);
pluginFuncs->newp = NPP_New;
pluginFuncs->destroy = NPP_Destroy;
pluginFuncs->setwindow = NPP_SetWindow;
pluginFuncs->newstream = NPP_NewStream;
pluginFuncs->destroystream = NPP_DestroyStream;
pluginFuncs->asfile = NPP_StreamAsFile;
pluginFuncs->writeready = NPP_WriteReady;
pluginFuncs->write = NPP_Write;
pluginFuncs->print = NPP_Print;
pluginFuncs->event = NPP_HandleEvent;
pluginFuncs->urlnotify = NPP_URLNotify;
pluginFuncs->getvalue = NPP_GetValue;
pluginFuncs->setvalue = NPP_SetValue;
pluginFuncs->javaClass=NULL;

return NPERR_NO_ERROR;
}

const char * NP_GetMIMEDescription()
{
return “application/xl_qvod_chrome:.QvodPlayer:qvod_chrome”;
}
NPError OSCALL NP_Shutdown(void)
{
return NPERR_NO_ERROR;

}

NPError NPP_New(NPMIMEType pluginType,
NPP instance, uint16_t mode,
int16_t argc, char* argn[],
char* argv[], NPSavedData* saved)
{
if(!instance->pdata)
{
NPObject * NPO;
if(!(NPO = browser->createobject(instance, &scriptablePluginClass)))
return NPERR_INVALID_INSTANCE_ERROR;
else
{
instance->pdata = NPO;
return NPERR_NO_ERROR;

}
}
return NPERR_INVALID_INSTANCE_ERROR;

}

NPError NPP_Destroy(NPP instance, NPSavedData **save)
{
NPObject *pluginInstance=(NPObject *)instance->pdata;
if(!pluginInstance)
{
browser->releaseobject(pluginInstance);
pluginInstance = NULL;
}
return NPERR_NO_ERROR;
}
BOOL _stdcall DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{

return true;
}
NPError NPP_SetWindow(NPP instance, NPWindow* window)
{
return NPERR_NO_ERROR;
}
NPError NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
{
*stype = NP_ASFILEONLY;
return NPERR_NO_ERROR;
}

NPError NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
{
return NPERR_NO_ERROR;
}

int NPP_WriteReady(NPP instance, NPStream* stream)
{
return 0;
}

int NPP_Write(NPP instance, NPStream* stream, int offset, int len, void* buffer)
{
return 0;
}

void NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
{
}

void NPP_Print(NPP instance, NPPrint* platformPrint)
{

}
int16_t NPP_HandleEvent(NPP instance, void* event)
{
return 0;
}

void NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
{

}

NPError NPP_GetValue(NPP instance, NPPVariable variable, void *value)
{

NPObject *pluginInstance=NULL;
switch(variable) {
case NPPVpluginScriptableNPObject:

pluginInstance=(NPObject *)instance->pdata;
if (pluginInstance)
{
browser->retainobject(pluginInstance);
}
*(NPObject **)value = pluginInstance;
break;
default:
return NPERR_GENERIC_ERROR;
}

return NPERR_NO_ERROR;
}

NPError NPP_SetValue(NPP instance, NPNVariable variable, void *value)
{
return NPERR_GENERIC_ERROR;
}

4、 js调用方法:

<script type=”text/javascript”>

function InvokeQvodPlayer(url)
{
var xl_plugin = document.getElementById(“xl_qvod_chrome”);
xl_plugin.QvodPlayerStart(“\”” + url + “\””);

}

其中 QvodPlayerStart 是自己实现的方法,浏览器调用 invoke函数,QvodPlayerStart 作为参数传递进去。url也是参数。

其他:

插件的background.html 的console.log 不会显示在网页的 console台。

MIMEType 的类型要在 rc文件里面指定,格式可以使用 npruntime 提供的例子里面的,修改MIMEType 类型就可以了。

最后的功能基本都实现了。小实验到此为止。学了很多。

留下评论