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

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


支持传统C++开发及运行的跨平台的Web服务器端环境,建立在Apache平台上,knewcode0.91a版。 测试运行:(测试环境,Windows7) 1、将本目录拷贝到D盘根目录;(如果需要拷贝到其他目录,请自行修改Apache的配置文件“debug\httpd-2.2.25-win32\Apache22\conf\httpd.conf”) 2、运行“D:\knewcode0.91a\StartDebug.bat”启动Apache及knewcode运行环境; 3、在浏览器中,输入“http://127.0.0.1:8090/hello_world.kc”,测试“hello_world_cpp”例子; 4、在浏览器中,输入“http://127.0.0.1:8090/”,测试“exam_blog”例子; 5、“D:\mycode\knewcode\release\0.91a\sample\src\webservice_client(c#)”是C#的Webservice客户端例子。 Linux下安装:(目前只在Ubuntu14.04 32位版下测试通过,目前只支持32位版的Linux) 1、将本目录拷贝到“/home”目录下;(如果需要拷贝到其他目录,请自行修改“kc_apache_mod.conf”和“kc_apache_mod.load”文件) 2、使用超级管理员权限,运行“/home/knewcode0.91a/debug/linux_apache_setup/setup.sh”脚步,拷贝2个配置文件到Apache环境下; 3、修改Apache的相关配置文件,将“/home/knewcode0.91a/sample”目录设置为Apache的主页目录,并设置权限; 4、修改目录权限,设置“/home/knewcode0.91a”目录为可运行和可读写,“/home/knewcode0.91a/sample”目录的所有者改为“www-data”。 目前处于测试阶段,如遇任何问题,请反馈到如下邮箱,谢谢! zogy@163.com
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值