现在的位置: 首页 > 综合 > 正文

Google V8 编程入门(三) – 使用js访问c++宿主对象

2013年06月21日 ⁄ 综合 ⁄ 共 6894字 ⁄ 字号 评论关闭

1, 导出全局函数到脚本环境

// v8test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <v8.h>
#pragma comment(lib, "v8_base.lib")
#pragma comment(lib, "v8_snapshot.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "winmm.lib")
using namespace v8;

// 在宿主环境中实现一个常规的println()函数
v8::Handle<v8::Value> HostPrint(const v8::Arguments& args) {
	for (int i = 0; i < args.Length(); i++)
	{
		v8::HandleScope handle_scope;
		// 转换成字符串用于打印
		v8::String::AsciiValue str(args[i]);
		printf("%s", *str);
	}
	printf("\n");
	// 返回Undefined, 类似于返回void
	return v8::Undefined();
}

int main(int argc, char* argv[]) {

	// Create a stack-allocated handle scope.
	HandleScope handle_scope;

	// 创建一个全局模板用于修改脚本对象 
	v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New();

	// 把宿主的HostPrint函数注册到脚本环境
	globalTemplate->Set(v8::String::New("println"), v8::FunctionTemplate::New(HostPrint));

	// Create a new context.
	v8::ExtensionConfiguration * extConfig = NULL;
	// 并且把自定义的全局模板globalTemplate作为参数传入
	Handle<Context> context = Context::New(extConfig, globalTemplate);

	// Enter the created context for compiling and
	// running the hello world script. 
	Context::Scope context_scope(context);

	// Create a string containing the JavaScript source code.
	Handle<String> source = String::New(""
		"println('Hello ', 'world ', 1, ' ', 2, ' ', Math.PI);" // 在脚本环境中调用宿主函数
		""
		);

	String * str = *source;

	// Compile the source code.
	Handle<Script> script = Script::Compile(source);

	// Run the script to get the result.
	Handle<Value> result = script->Run();

	// Dispose the persistent context.
	(Persistent<Context>(context)).Dispose();

	return 0;
}

2, 运行结果:

Hello world 1 2 3.141592653589793
请按任意键继续. . .

3, 导出静态变量到脚本环境

// v8test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <v8.h>
#pragma comment(lib, "v8_base.lib")
#pragma comment(lib, "v8_snapshot.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "winmm.lib")
using namespace v8;

// 在宿主环境中定义一个全局变量
static int globalVarInV8Host = 0;

static Handle<Value> XGetter(Local<String> key,const AccessorInfo& info) 
{
	return Integer::New(globalVarInV8Host);
}

static void XSetter(Local<String> key, Local<Value> value,const AccessorInfo& info) 
{
	globalVarInV8Host = value->Int32Value();
}

// 在宿主环境中实现一个常规的println()函数
v8::Handle<v8::Value> HostPrint(const v8::Arguments& args) {
	for (int i = 0; i < args.Length(); i++)
	{
		v8::HandleScope handle_scope;
		// 转换成字符串用于打印
		v8::String::AsciiValue str(args[i]);
		printf("%s", *str);
	}
	printf("\n");
	// 返回Undefined, 类似于返回void
	return v8::Undefined();
}

int main(int argc, char* argv[]) {

	// Create a stack-allocated handle scope.
	HandleScope handle_scope;

	// 创建全局模板globalTemplate
	v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New();

	// 注册globalVarInV8Host变量的访问器
	globalTemplate->SetAccessor(v8::String::New("globalVarInV8Host"), XGetter, XSetter);

	// 为了查看变量,把HostPrint也注册进去
	globalTemplate->Set(v8::String::New("println"), v8::FunctionTemplate::New(HostPrint));

	// Create a new context.
	Handle<Context> context = Context::New(NULL, globalTemplate);

	// Enter the created context for compiling and
	// running the hello world script. 
	Context::Scope context_scope(context);

	// Create a string containing the JavaScript source code.
	Handle<String> source = String::New(""
		"var v1 = globalVarInV8Host;"
		"v1 = 100;"
		"println('v1=', v1, ';', 'globalVarInV8Host=', globalVarInV8Host);"

		"var v2 = globalVarInV8Host;"
		"v2 = 200;"
		"println('v2=', v2, ';', 'globalVarInV8Host=', globalVarInV8Host);"

		"globalVarInV8Host = 300;"
		"println('v1=', v1, ';', 'v2=', v2, ';', 'globalVarInV8Host=', globalVarInV8Host);"
		);

	String * str = *source;

	// Compile the source code.
	Handle<Script> script = Script::Compile(source);

	// Run the script to get the result.
	Handle<Value> result = script->Run();

	// Dispose the persistent context.
	(Persistent<Context>(context)).Dispose();

	return 0;
}

4, 运行结果:

v1=100;globalVarInV8Host=0
v2=200;globalVarInV8Host=0
v1=100;v2=200;globalVarInV8Host=300
请按任意键继续. . .

5, 导出动态对象到脚本环境

// v8test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <v8.h>
#pragma comment(lib, "v8_base.lib")
#pragma comment(lib, "v8_snapshot.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "winmm.lib")
using namespace v8;

// 在宿主环境中实现一个常规的println()函数
v8::Handle<v8::Value> HostPrint(const v8::Arguments& args) {
	for (int i = 0; i < args.Length(); i++)
	{
		v8::HandleScope handle_scope;
		// 转换成字符串用于打印
		v8::String::AsciiValue str(args[i]);
		printf("%s", *str);
	}
	printf("\n");
	// 返回Undefined, 类似于返回void
	return v8::Undefined();
}

// 定义一个简单的c++类
class CUser {
public:
	int uid_;
public:
	CUser(int uid)
		: uid_(uid){

	}
	virtual ~CUser() { }

	static Handle<Value> GetUID(Local<String> property,
		const AccessorInfo &info) {
			Local<Object> self = info.Holder();
			Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
			void* ptr = wrap->Value();
			int value = static_cast<CUser*>(ptr)->uid_;
			return Integer::New(value);
	}

	static void SetUID(Local<String> property, Local<Value> value,
		const AccessorInfo& info) {
			Local<Object> self = info.Holder();
			Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
			void* ptr = wrap->Value();
			static_cast<CUser*>(ptr)->uid_ = value->Int32Value();
	}
};

/**
* Utility function that wraps a C++ object in a
* JavaScript object.
* 封装c++对象成为一个js对象
*/
Handle<Object> WrapUserObject(CUser * pUser) {
	// Handle scope for temporary handles.
	HandleScope handle_scope;

	Handle<ObjectTemplate> templ = ObjectTemplate::New();

	// 设置内部插槽个数为1,分配一个内部存储区域
	templ->SetInternalFieldCount(1);

	// 设置访问器
	templ->SetAccessor(String::New("uid"), CUser::GetUID, CUser::SetUID);

	// Create an empty http request wrapper.
	Handle<Object> result = templ->NewInstance();

	// Store the request pointer in the JavaScript wrapper.
	result->SetInternalField(0, External::New(pUser));

	// Return the result through the current handle scope.  Since each
	// of these handles will go away when the handle scope is deleted
	// we need to call Close to let one, the result, escape into the
	// outer handle scope.
	return handle_scope.Close(result);
}

int main(int argc, char* argv[]) {

	// Create a stack-allocated handle scope.
	HandleScope handle_scope;

	// 创建全局模板globalTemplate
	v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New();

	// 为了查看变量,把HostPrint也注册进去
	globalTemplate->Set(v8::String::New("println"), v8::FunctionTemplate::New(HostPrint));
	
	// Create a new context.
	Handle<Context> context = Context::New(NULL, globalTemplate);

	// Enter the created context for compiling and
	// running the hello world script. 
	Context::Scope context_scope(context);

	// 创建一个本地对象
	CUser * pUser = new CUser(12345);
	// 封装成一个JS脚本对象
	Handle<Object> userObject = WrapUserObject(pUser);

	// 使用以下方式注册user对象到全局范围
	context->Global()->Set(String::New("user"), userObject);

	// 以下方式是错误的, TODO: 全局对象和代理(proxy)全局对象的区别
	// http://bespin.cz/~ondras/html/classv8_1_1Context.html
	// https://wiki.mozilla.org/Gecko:SplitWindow
	// globalTemplate->Set(String::New("user"), userObject);

	// Create a string containing the JavaScript source code.
	Handle<String> source = String::New(""
		"println(user.uid);"
		);

	String * str = *source;

	// Compile the source code.
	Handle<Script> script = Script::Compile(source);

	// Run the script to get the result.
	Handle<Value> result = script->Run();

	// Dispose the persistent context.
	(Persistent<Context>(context)).Dispose();

	return 0;
}

6, 运行结果

12345
请按任意键继续. . .

7, 参考:

https://code.google.com/p/cproxyv8/wiki/Usage

http://iammr.7.blog.163.com/blog/static/49102699201201565822189/

https://developers.google.com/v8/embed

https://wiki.mozilla.org/Gecko:SplitWindow

http://bespin.cz/~ondras/html/classv8_1_1Context.html

抱歉!评论已关闭.