chorme extension plugin
来源:互联网 发布:淘宝开店名称叫什么好 编辑:程序博客网 时间:2024/05/25 21:33
从火狐转用Google Chrome已经N年了,前几天偶然想用一下IRC,因为mIRC一直收费,想起来装个免费的Chrome 插件,但结果没找到。其实主要原因是因为Chrome的地址栏集成了地址输入和搜索的功能,不能实现像 irc://... 之类的自定义协议。很多开发者都在询问有没有可能实现,出于好奇,进一步研究了一下Chrome的扩展开发。在谷歌的开发网站上有详尽的API文档和示例,不过关于 NPAPI 的部分就几行文字,其实这也确实超出了其API的范畴。Extention API 主要以 javascript 实现对UI和浏览器的设置和管理,地址栏由omnibox扩展管理,主要还是适用于实现搜索功能,虽然不能有效实现自定义协议,但也可以变通一下,比如由 omnibox 注册一个 "keyword": "irc" ,当在地址栏中输入 "irc+空格" 后,地址栏呈现出自定义的搜索状态,并将输入内容管理权交给了你的扩展程序。接下来是Socket通讯,虽然说HTML5支持 socket 了,但大体了解了一下,发现这个 socket 还是基于 http 的,出于安全考虑,还增加了许多限制,以纯 js 脚本方式实现 irc telnet 等通讯协议是根本不可能的。因此,想实现通讯的话就不的不使用插件开发(Plugins)。
Chrome 的插件使用 ,想找点示例比较困难,这也许是其很少招惹木马、病毒的原因之一吧。进入正式话题:
在扩展的 manifest.json 中加入 "plugins": [{ "path": "myplugin.dll", "public": false } ] ,说明该扩展将使用文件名为myplugin.dll的插件,插件为标准windows动态库,使用 NPAPI 来开发,因为只做 js 的扩展,仅用到其中的 npapi.h nptypes.h npruntime.h npfunctions.h 四个头文件,不需要连接库,所以编译器也不限制,之要能生成 .dll 就可以。public参数说明该插件是否可被所有页面使用,默认为false,说明之能被扩展内部的页面使用。
nptypes.h : NPAPI 的变量类型定义
npapi.h : NPAPI 定义插件的接口函数说明和常用结构说明
npruntime.h : 插件与JavaScript交互的结构说明
npfunctions.h : 调用浏览器的接口函数和结构
动态库必须实现下面三个接口函数:
NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* pluginFuncs); 插件加载后第一个被调用,参数 pluginFuncs 为一个结构指针,插件代码需要实现相关调用内容,浏览器则通过该结构,调用插件的功能。
NPError WINAPI NP_Initialize(NPNetscapeFuncs* pBrowserFuncs); 插件加载后第二个被调用,参数 pBrowserFuncs 需要被插件保存为全局变量,通过此结构的函数,调用浏览器提供的功能。
NPError WINAPI NP_Shutdown(void); 插件释放前被调用。
插件通过MIME被扩展加载,在插件的 .html 中增加 <embed type="application/x-my-extension" id="myplugin"> ,浏览器会通过该 MIME 去搜索所有插件是否被支持,如果支持则加载该插件,在windows环境下MIME表述在插件的库文件的版本资源中(Unix,Linux环境通过NP_GetMIMEDescription()返回,即在.rc文件的版本信息中加入 VALUE "MIMEType", "application/x-my-extension" 。
实现插件功能:
NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* pluginFuncs)
{
pluginFuncs->version = 1;
pluginFuncs->newp = PluginNewp; // <embed type="(MIME)"> 创建插件时被调用
pluginFuncs->destroy = PluginDestroy; // 释放插件时调用
pluginFuncs->getvalue = PluginGetValue; // js 中赋值时被调用
pluginFuncs->setwindow = PluginSetWindow;
....
return NPERR_NO_ERROR;
}
NPError WINAPI NP_Initialize(NPNetscapeFuncs* pBrowserFuncs)
{
BROWSER = pBrowserFuncs; // 记录为全局变量
....
return NPERR_NO_ERROR;
}
NPError WINAPI NP_Shutdown(void)
{
....
return NPERR_NO_ERROR;
}
NPError PluginNewp(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved)
{
CMyPlugin *plugin = BROWSER->createobject(instance, &CMyPlugin::m_npClass); // 创建插件实体, 将浏览器调用 m_npClass->allocate(...);
instance->pdata = plugin; // 用 pdata 记录插件实体地址,也可在 CMyPlugin 创建时实现,释放时会用到 ...
return NPERR_NO_ERROR;
}
NPError PluginDestroy(NPP instance, NPSavedData** save)
{
BROWSER->releaseobject((CMyPlugin *) instance->pdata); // 释放,浏览器调用 m_npClass->deallocate(...);
return NPERR_NO_ERROR;
}
NPError PluginGetValue(NPP instance, NPPVariable variable, void *value)
{
if (variable==NPPVpluginScriptableNPObject) {
// javascript: var v = document.getElementById("myplugin"); 时被浏览器调用,必须 retainobject(),浏览器处理 NPObject 的内容和引用计数器
CMyPlugin *plugin = (CMyPlugin *) instance->pdata;
if (plugin)
*value = BROWSE->retainobject(plugin);
}
return NPERR_NO_ERROR;
}
struct NPClass CMyPlugin::m_npClass = {
NP_CLASS_STRUCT_VERSION,
CMyPlugin::Allocate,
CMyPlugin::Deallocate,
NULL,
CMyPlugin::HasMethod,
CMyPlugin::InvokeMethod,
NULL,
CMyPlugin::HasProperty,
CMyPlugin::GetProperty,
CMyPlugin::SetProperty,
NULL,
NULL,
NULL,
};
class CMyPlugin : public NPObject {
public:
NPP m_npp;
CMyPlugin(NPP instance) : m_npp(instance) {
m_npp->pdata = this;
};
public:
static NPClass m_npClass;
static NPObject *Allocate(NPP npp, NPClass *aClass) {
// PluginNewp 的 BROWSER->createobject(); 调用此过程
return new CMyPlugin(npp);
};
static void Deallocate(NPObject *npobj) {
// PluginDestroy 的 BROWSER->releaseobject(); 调用此过程
delete (CMyPlugin *)npobj;
};
static bool HasMethod(NPObject *obj, NPIdentifier methodName) {
// javascript: myplugin.method1(...); 时调用,返回本插件是否有此函数调用
// *obj 即 CMyPlugin 的实体指针
NPUTF8 *name = BROWSER->utf8fromidentifier(methodName);
bool rc = %是否有此函数%; // 可以用 strcmp(methodName, "?????") 你的函数列表
BROWSER->memfree(name);
return rc;
};
static bool InvokeMethod(NPObject *obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result) {
// 如果 HasMethod() 返回 true,此过程会被立即调用
// 根据 methodName 调用 obj 实现对应的功能
....
return true;
};
static bool HasProperty(NPObject *obj, NPIdentifier propertyName) {
// javascript: myplugin.property1 = xxx; 时调用,返回本插件是否有此函数调用
....
};
static bool GetProperty(NPObject *obj, NPIdentifier propertyName, NPVariant *result) {
....
};
static bool SetProperty(NPObject *obj, NPIdentifier propertyName, const NPVariant *result) {
....
};
....
// 脚本调用首先判断 HasProperty() 如果返回 true 则调用 GetProperty() 或 SetProperty()
// 否则判断 HasMethod(), 如果返回 true 则调用 InvokeMethod()
// 否则调用 Contructor()
};
至此,插件的主体就已经实现了,剩下的就是根据需要实现对脚本的解释执行了。需要注意的是与js脚本的交互都是NPVariant类型,需要调用浏览器的功能来实现,举个例子实现 js 脚本的回调处理 :
javascript: var rc = plugin.setCallback("someevent", function(msg) { alert(msg); } );
脚本向插件注册了一个回调函数,浏览器将调用插件的 InvokeMethod();
static bool InvokeMethod(NPObject *obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result) {
// *obj 为插件类实体指针
// methodName 为 "setCallback"
// args[0] 为 "someevent"
// args[1] 为 NPObject ,即回调函数的类
// argCount 为 2
// result 返回给脚本的函数调用结果
// 记录回调函数,由于脚本调用的参数是retain出来的,调用完成将被释放,因此此处必须 retainobject 后再记录。否则将出现异常 !!!!
((CMyPlugin *)obj)->m_someevent_callback = BROWSER->retainobject( args[1].value.objectValue );
BOOLEAN_TO_NPVARIANT(true, *result); // 使用 npruntime.h 提供的宏,设置返回值为 bool 类型的 true。
return true;
};
插件中需要执行脚本的回调函数时:
void invoke_script_callback(char *str)
{
NPVariant msg, res;
STRINGZ_TO_NPVARIANT(str, &msg);
BROWSER->invokeDefault(m_npp, m_someevent_callback, &msg, 1, &res);
... 此处处理脚本返回值 res
BROWSER->releasevariantvalue(&res);
}
注意: 使用字符串时应特别注意,STRINGZ_TO_NPVARIANT 转换仅适用于全局静态 char* 变量。最好使用 BROWSER->malloc 分配空间来创建PNVariant 字符串,特别是传给脚本的非 const PNVariant * 变量。
- chorme extension plugin
- Jenkins-Email Extension Plugin
- Eclipse plugin SWT Win32 Extension
- neutron plugin 与 extension 编写流程
- Jenkins 邮件配置 (使用 Jenkins Email Extension Plugin)
- Jenkins 邮件配置 (使用 Jenkins Email Extension Plugin)
- Jenkins 邮件配置 (使用 Jenkins Email Extension Plugin)
- Jenkins邮件插件的配置(Email Extension Plugin)
- Jenkins Email Extension Plugin 引用变量${FILE}时乱码
- Jenkins 邮件配置 (使用 Jenkins Email Extension Plugin)
- jenkins邮件插件Email Extension Plugin的安装与配置
- Jenkins 插件介绍 ___Email Extension Template Plugin插件
- Jenkins 邮件配置 (使用 Jenkins Email Extension Plugin)
- 使用Jenkins+Email Extension Plugin自定义Robot Framework结果报告
- Jenkins 邮件配置 (使用 Jenkins Email Extension Plugin)
- 怎样写 OpenStack Neutron 的 Extension 和plugin
- NEUTRON中的plugin和extension介绍及加载机制
- Jenkins插件使用--Email Extension Plugin(构建后邮件)
- cocos2d知识
- SAP NetWeaver Internet Sales - local file read
- 困惑: 9pitch图片显示出黑线
- opensips 安装及基本配置
- sql server行转列问题终极解决
- chorme extension plugin
- 最小点覆盖集&&http://acm.nyist.net/JudgeOnline/problem.php?pid=237
- linux内核调试技巧--current的应用
- android 自定义样式
- 利用 C# 开发工具自动完成创建一些基本的代码
- 操作系统学习之——系统分析师PV操作的典型试题
- pop imap smtp 端口
- SQL多表查询
- 一卡通收费系统丢失收费记录的原因分析