1.准备导出C++类
class Point
{
public:
Point(int x, int y) : x_(x), y_(y) { }
int x_, y_;
};
2.设置JS访问类成员函数
void GetPointX(Local<String> property,
const PropertyCallbackInfo<Value>& info)
{
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
int value = static_cast<Point*>(ptr)->x_;
info.GetReturnValue().Set(value);
}
void SetPointX(Local<String> property, Local<Value> value,
const PropertyCallbackInfo<void>& info)
{
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
static_cast<Point*>(ptr)->x_ = value->Int32Value();
}
void GetPointY(Local<String> property,
const PropertyCallbackInfo<Value>& info)
{
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
int value = static_cast<Point*>(ptr)->y_;
info.GetReturnValue().Set(value);
}
void SetPointY(Local<String> property, Local<Value> value,
const PropertyCallbackInfo<void>& info)
{
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
static_cast<Point*>(ptr)->y_ = value->Int32Value();
}
3.定义导出C++对象函数
void AddPointObj(Isolate *isolate, Handle<Context> &context)
{
Handle<FunctionTemplate> point_templ = FunctionTemplate::New();
Handle<ObjectTemplate> point_inst = point_templ->InstanceTemplate();
point_inst->SetInternalFieldCount(1);;
point_inst->SetAccessor(String::New("x"), GetPointX, SetPointX);
point_inst->SetAccessor(String::New("y"), GetPointY, SetPointY);
Handle<Function> point_ctor = point_templ->GetFunction();
Local<Object> obj = point_ctor->NewInstance();
Point *pt = new Point(15, 20);
obj->SetInternalField(0, External::New(pt));
context->Global()->Set(String::NewFromUtf8(isolate, "point"), obj);
}
4.调用导出对象函数
int main(int argc, char* argv[])
{
V8::InitializeICU();
//V8::SetFlagsFromCommandLine(&argc, argv, true);
Isolate* isolate = Isolate::GetCurrent();
run_shell = (argc == 1);
int result;
{
HandleScope handle_scope(isolate);
Handle<Context> context = CreateShellContext(isolate);
if (context.IsEmpty())
{
fprintf(stderr, "Error creating context\n");
return 1;
}
context->Enter();
//调用导出对象函数
AddPointObj(isolate, context);
result = RunMain(isolate, argc, argv);
if (run_shell) RunShell(context);
context->Exit();
}
V8::Dispose();
return 0;
}
5.完整代码
#include "v8/include/v8.h"
#include <assert.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "v8/lib/v8")
using namespace v8;
Handle<Context> CreateShellContext(Isolate* isolate);
void RunShell(Handle<Context> context);
int RunMain(Isolate* isolate, int argc, char* argv[]);
bool ExecuteString(Isolate* isolate,
Handle<String> source,
Handle<Value> name,
bool print_result,
bool report_exceptions);
void Print(const FunctionCallbackInfo<Value>& args);
void Read(const FunctionCallbackInfo<Value>& args);
void Load(const FunctionCallbackInfo<Value>& args);
void Quit(const FunctionCallbackInfo<Value>& args);
void Version(const FunctionCallbackInfo<Value>& args);
Handle<String> ReadFile(const char* name);
void ReportException(Isolate* isolate, TryCatch* handler);
void AddPointObj(Isolate *isolate, Handle<Context> &context);
static bool run_shell = false;
int main(int argc, char* argv[])
{
V8::InitializeICU();
//V8::SetFlagsFromCommandLine(&argc, argv, true);
Isolate* isolate = Isolate::GetCurrent();
run_shell = (argc == 1);
int result;
{
HandleScope handle_scope(isolate);
Handle<Context> context = CreateShellContext(isolate);
if (context.IsEmpty())
{
fprintf(stderr, "Error creating context\n");
return 1;
}
context->Enter();
AddPointObj(isolate, context);
result = RunMain(isolate, argc, argv);
if (run_shell) RunShell(context);
context->Exit();
}
V8::Dispose();
return 0;
}
class Point
{
public:
Point(int x, int y) : x_(x), y_(y) { }
int x_, y_;
};
void GetPointX(Local<String> property,
const PropertyCallbackInfo<Value>& info)
{
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
int value = static_cast<Point*>(ptr)->x_;
info.GetReturnValue().Set(value);
}
void SetPointX(Local<String> property, Local<Value> value,
const PropertyCallbackInfo<void>& info)
{
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
static_cast<Point*>(ptr)->x_ = value->Int32Value();
}
void GetPointY(Local<String> property,
const PropertyCallbackInfo<Value>& info)
{
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
int value = static_cast<Point*>(ptr)->y_;
info.GetReturnValue().Set(value);
}
void SetPointY(Local<String> property, Local<Value> value,
const PropertyCallbackInfo<void>& info)
{
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
void* ptr = wrap->Value();
static_cast<Point*>(ptr)->y_ = value->Int32Value();
}
void AddPointObj(Isolate *isolate, Handle<Context> &context)
{
Handle<FunctionTemplate> point_templ = FunctionTemplate::New();
Handle<ObjectTemplate> point_inst = point_templ->InstanceTemplate();
point_inst->SetInternalFieldCount(1);;
point_inst->SetAccessor(String::New("x"), GetPointX, SetPointX);
point_inst->SetAccessor(String::New("y"), GetPointY, SetPointY);
Handle<Function> point_ctor = point_templ->GetFunction();
Local<Object> obj = point_ctor->NewInstance();
Point *pt = new Point(15, 20);
obj->SetInternalField(0, External::New(pt));
context->Global()->Set(String::NewFromUtf8(isolate, "point"), obj);
}
// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const String::Utf8Value& value)
{
return *value ? *value : "<string conversion failed>";
}
// Creates a new execution environment containing the built-in
// functions.
Handle<Context> CreateShellContext(Isolate* isolate)
{
// Create a template for the global object.
Handle<ObjectTemplate> global = ObjectTemplate::New();
// Bind the global 'print' function to the C++ Print callback.
global->Set(String::New("print"), FunctionTemplate::New(Print));
// Bind the global 'read' function to the C++ Read callback.
global->Set(String::New("read"), FunctionTemplate::New(Read));
// Bind the global 'load' function to the C++ Load callback.
global->Set(String::New("load"), FunctionTemplate::New(Load));
// Bind the 'quit' function
global->Set(String::New("quit"), FunctionTemplate::New(Quit));
// Bind the 'version' function
global->Set(String::New("version"), FunctionTemplate::New(Version));
return Context::New(isolate, NULL, global);
}
// The callback that is invoked by v8 whenever the JavaScript 'print'
// function is called. Prints its arguments on stdout separated by
// spaces and ending with a newline.
void Print(const FunctionCallbackInfo<Value>& args)
{
bool first = true;
for (int i = 0; i < args.Length(); i++)
{
HandleScope handle_scope(args.GetIsolate());
if (first)
{
first = false;
}
else
{
printf(" ");
}
String::Utf8Value str(args[i]);
const char* cstr = ToCString(str);
printf("%s", cstr);
}
printf("\n");
fflush(stdout);
}
// The callback that is invoked by v8 whenever the JavaScript 'read'
// function is called. This function loads the content of the file named in
// the argument into a JavaScript string.
void Read(const FunctionCallbackInfo<Value>& args)
{
if (args.Length() != 1)
{
ThrowException(String::New("Bad parameters"));
return;
}
String::Utf8Value file(args[0]);
if (*file == NULL)
{
ThrowException(String::New("Error loading file"));
return;
}
Handle<String> source = ReadFile(*file);
if (source.IsEmpty())
{
ThrowException(String::New("Error loading file"));
return;
}
args.GetReturnValue().Set(source);
}
// The callback that is invoked by v8 whenever the JavaScript 'load'
// function is called. Loads, compiles and executes its argument
// JavaScript file.
void Load(const FunctionCallbackInfo<Value>& args)
{
for (int i = 0; i < args.Length(); i++)
{
HandleScope handle_scope(args.GetIsolate());
String::Utf8Value file(args[i]);
if (*file == NULL)
{
ThrowException(String::New("Error loading file"));
return;
}
Handle<String> source = ReadFile(*file);
if (source.IsEmpty())
{
ThrowException(String::New("Error loading file"));
return;
}
if (!ExecuteString(args.GetIsolate(),
source,
String::New(*file),
false,
false))
{
ThrowException(String::New("Error executing file"));
return;
}
}
}
// The callback that is invoked by v8 whenever the JavaScript 'quit'
// function is called. Quits.
void Quit(const FunctionCallbackInfo<Value>& args)
{
// If not arguments are given args[0] will yield undefined which
// converts to the integer value 0.
int exit_code = args[0]->Int32Value();
fflush(stdout);
fflush(stderr);
exit(exit_code);
}
void Version(const FunctionCallbackInfo<Value>& args)
{
args.GetReturnValue().Set(String::New(V8::GetVersion()));
}
// Reads a file into a v8 string.
Handle<String> ReadFile(const char* name)
{
FILE* file = fopen(name, "rb");
if (file == NULL) return Handle<String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '\0';
for (int i = 0; i < size;)
{
int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
i += read;
}
fclose(file);
Handle<String> result = String::New(chars, size);
delete[] chars;
return result;
}
// Process remaining command line arguments and execute files
int RunMain(Isolate* isolate, int argc, char* argv[])
{
for (int i = 1; i < argc; i++)
{
const char* str = argv[i];
if (strcmp(str, "--shell") == 0)
{
run_shell = true;
}
else if (strcmp(str, "-f") == 0)
{
// Ignore any -f flags for compatibility with the other stand-
// alone JavaScript engines.
continue;
}
else if (strncmp(str, "--", 2) == 0)
{
fprintf(stderr,
"Warning: unknown flag %s.\nTry --help for options\n", str);
}
else if (strcmp(str, "-e") == 0 && i + 1 < argc)
{
// Execute argument given to -e option directly.
Handle<String> file_name = String::New("unnamed");
Handle<String> source = String::New(argv[++i]);
if (!ExecuteString(isolate, source, file_name, false, true)) return 1;
}
else
{
// Use all other arguments as names of files to load and run.
Handle<String> file_name = String::New(str);
Handle<String> source = ReadFile(str);
if (source.IsEmpty())
{
fprintf(stderr, "Error reading '%s'\n", str);
continue;
}
if (!ExecuteString(isolate, source, file_name, false, true)) return 1;
}
}
return 0;
}
// The read-eval-execute loop of the shell.
void RunShell(Handle<Context> context)
{
fprintf(stderr, "V8 version %s [sample shell]\n", V8::GetVersion());
static const int kBufferSize = 256;
// Enter the execution environment before evaluating any code.
Context::Scope context_scope(context);
Local<String> name(String::New("(shell)"));
while (true)
{
char buffer[kBufferSize];
fprintf(stderr, "> ");
char* str = fgets(buffer, kBufferSize, stdin);
if (str == NULL) break;
HandleScope handle_scope(context->GetIsolate());
ExecuteString(context->GetIsolate(),
String::New(str),
name,
true,
true);
}
fprintf(stderr, "\n");
}
// Executes a string within the current v8 context.
bool ExecuteString(Isolate* isolate,
Handle<String> source,
Handle<Value> name,
bool print_result,
bool report_exceptions)
{
HandleScope handle_scope(isolate);
TryCatch try_catch;
Handle<Script> script = Script::Compile(source, name);
if (script.IsEmpty())
{
// Print errors that happened during compilation.
if (report_exceptions)
ReportException(isolate, &try_catch);
return false;
}
else
{
Handle<Value> result = script->Run();
if (result.IsEmpty())
{
assert(try_catch.HasCaught());
// Print errors that happened during execution.
if (report_exceptions)
ReportException(isolate, &try_catch);
return false;
}
else
{
assert(!try_catch.HasCaught());
if (print_result && !result->IsUndefined())
{
// If all went well and the result wasn't undefined then print
// the returned value.
String::Utf8Value str(result);
const char* cstr = ToCString(str);
printf("%s\n", cstr);
}
return true;
}
}
}
void ReportException(Isolate* isolate, TryCatch* try_catch)
{
HandleScope handle_scope(isolate);
String::Utf8Value exception(try_catch->Exception());
const char* exception_string = ToCString(exception);
Handle<Message> message = try_catch->Message();
if (message.IsEmpty())
{
// V8 didn't provide any extra information about this error; just
// print the exception.
fprintf(stderr, "%s\n", exception_string);
}
else
{
// Print (filename):(line number): (message).
String::Utf8Value filename(message->GetScriptResourceName());
const char* filename_string = ToCString(filename);
int linenum = message->GetLineNumber();
fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
// Print line of source code.
String::Utf8Value sourceline(message->GetSourceLine());
const char* sourceline_string = ToCString(sourceline);
fprintf(stderr, "%s\n", sourceline_string);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
for (int i = 0; i < start; i++)
{
fprintf(stderr, " ");
}
int end = message->GetEndColumn();
for (int i = start; i < end; i++)
{
fprintf(stderr, "^");
}
fprintf(stderr, "\n");
String::Utf8Value stack_trace(try_catch->StackTrace());
if (stack_trace.length() > 0)
{
const char* stack_trace_string = ToCString(stack_trace);
fprintf(stderr, "%s\n", stack_trace_string);
}
}
}
代码下载
文件源代码
注意:源代码使用CodeBlocks建立的工程使用VS2005/VS2008编译环境进行编译,如需要VS工程请手动生成。
参考文献
Using V8 - Google’s Chrome JavaScript Virtual Machine
使用 Google V8 引擎开发可定制的应用程序
GoogleV8Tutorials
V8Demo