Chinaunix首页 | 论坛 | 博客
  • 博客访问: 313035
  • 博文数量: 174
  • 博客积分: 3061
  • 博客等级: 中校
  • 技术积分: 1740
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-04 22:43
文章分类

全部博文(174)

文章存档

2011年(54)

2010年(14)

2009年(30)

2008年(26)

2007年(27)

2006年(23)

我的朋友

分类: WINDOWS

2011-06-08 11:04:31

这个是去年做过的一个项目,主要是通过js,html做前端,然后c++对象再后面提供服务。

比较简单的一个场景是,你可以想象为什么你在浏览器内可以写windows,document这些对象来操作一些方法和属性,本质上这些对象都是c++实现的,也可以称为预定义对象,那么我们如何将一些自定义的方法或者对象暴露给js呢?

v8中c++暴露给js的方式大体上有两种,extention 和mapping机制。

前者往往用于将一些API 暴露出去,比较全局函数,比如printlog,getpath这些全局的函数。

mapping机制,比较容易将对象暴露出去。

那么先讲讲extention机制。


首先v8中对象的执行本质上需要一个context对象,可以理解为上下文,通常浏览器的一个frame就是一个context。

那么我们假设想让某个上下文中有一个我们自定义的函数比如叫做getpath。



1。 我们需要创建一个context,这儿假定它叫做globalctx。

const char* appExtension = "Extensions/Application";

Application::Application(void) :
v8::Extension( appExtension,
 "native function GetPath();" 
 "native function include();"
 )
{
FunctionTemplate::New(Include));
}

2. 我们需要在这个globalctx中,注册extention,这个注册过程就是解决了在这个context中注入了一些我们定义的对象和方法。
void GlobalContext::Initialize( ExtensionList* extensions )
{
m_objectGlobal = v8::ObjectTemplate::New();

// register extensions in global javascript context
std::vector vecExtensions;

scoped_ptr extensionConfig;
if ( extensions && extensions->size() )
{
for ( ExtensionList::iterator iter = extensions->begin(); iter != extensions->end(); iter ++ )
{
vecExtensions.push_back( (*iter)->name() );
v8::RegisterExtension( *iter );
}

extensionConfig.reset( new v8::ExtensionConfiguration( (int)vecExtensions.size(), &vecExtensions[0] ) );
}

m_context = v8::Context::New( extensionConfig.get(), m_objectGlobal );
}


通过这个方式,将extention注入这个context,这样getpath这个方法将可以在这个context的js代码中可以访问。 再深一步说为什么,就需要看v8的source了。




我们再来看第二个问题,即如何让一个c++对象再js中可以访问,刚才的说明你会发现光通过extention模式,它只能export API 而不能暴露对象,而且API往往很多时候是无状态的,即用了就用了;但是实际上我们可能会存在一些有状态的对象,比如user对象,它是由名称和昵称的,另外或许它运行过程中间昵称会变化。

简单来说,从实际使用角度出发,我们需要在js有能力可以如下:

var obj = xxxx;  // obj hold a c++ object 

var dispname = obj.getdispname() // we can access method of obj

大致就这么个意思。。。。,而这个靠extention就不行了。


我们看看v8提供的mapping机制。。。

这儿假设extention提供了一个方法叫做GetServiceMgr,它返回一个rootobj,你明白就行。

然后这个rootobj上有很多方法。。。

贴一些代码。。。

v8::Handle IMAPIExtension::GetServiceMgr(const v8::Arguments& args)
{
using namespace ImAPI;
using namespace v8;

HandleScope handleScope;
v8::Handle context = v8::Context::GetCurrent();
if(context.IsEmpty())
{
return False();
}

v8::Context::Scope contextScope(context);

if(!m_serviceManager)
{
return v8::Null();
}

return handleScope.Close(ImMapping::CppDataToJsData(m_serviceManager));
}


v8::Handle CppDataToJsData(ImAPI::IServiceManager* pServiceMgr) { if(!pServiceMgr) { return Null(); } v8::HandleScope handleScope; v8::Handle context = v8::Context::GetCurrent(); if(context.IsEmpty()) { return False(); } Context::Scope contextScope(context); Handle retObjectValue = MapCppObjectToJs(pServiceMgr); if(retObjectValue.IsEmpty()) { return False(); } if(!FillFunction2Object("GetCurrentUserService",retObjectValue,&InvokerProc::HandleProc)) { return False(); }
......... 注册其他对象,这个就是mapping.....





这样以后,我们就可以写,如下js 。。。。

var servicemgr = GetServiceMgr();
var cus = servicemgr.GetCurrentUserService();


到了这儿已经简单的介绍了v8的c++对象扩展机制,但是还是有一些问题,没有得到很好的回到,比如这个暴露出去的对象它的生命周期如何管理?

这个是我的demo没有触及到的,demo只是假设了暴露出去的是一些全局单件对象。

其实结合qtwebkit bridge的做法,我这儿的建议是,最好还是c++方面管理这些对象的生命周期;

而不是依赖于v8的gc。 (貌似v8的gc在发生的时候可以注册回调)

然后通过显式的调用来放弃对象生命周期,比如js端不用了,就call一个uninit之类的。


下面是demo的附件。

文件:Evolution.rar
大小:238KB
下载:下载

阅读(2189) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~