在 oop 应用程序 c++ 中使用 V8 引擎
Use V8 engine in oop application c++
我想在 C++ 中基于 oop 的应用程序中使用 v8,但是我的代码中的 v8 对象范围存在一些问题,当我在一个函数中编写所有代码时,它工作得很好,但是当我将class(甚至一个名字space)一些对象将被破坏。
这段代码可以正常运行:
//#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <v8.h>
#include <libplatform.h>
using namespace v8;
Handle<v8::Object> g_global;
// Reads a file into a v8 string.
v8::Handle<v8::String> _ReadFile(const char* name)
{
#pragma warning(disable : 4996)
FILE* file = fopen(name, "rb");
if (file == NULL) return v8::Handle<v8::String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '[=10=]';
for (int i = 0; i < size;)
{
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
v8::Handle<v8::String> result = v8::String::NewFromUtf8(g_global->GetIsolate(), chars);
delete[] chars;
return result;
}
Handle<v8::Value> CallJSFunction( std::string funcName, Handle<Value> argList[], unsigned int argCount) {
Handle<v8::Object> global = g_global;
// Create value for the return of the JS function
Handle<Value> js_result;
// Grab JS function out of file
Handle<v8::Value> value = global->Get(String::NewFromUtf8(global->GetIsolate(), funcName.c_str()));
// Cast value to v8::Function
Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
// Call function with all set values
js_result = func->Call(global, argCount, argList);
// Return value from function
return js_result;
}
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
virtual void *Allocate(size_t length) {
void *data = AllocateUninitialized(length);
return data == NULL ? data : memset(data, 0, length);
}
virtual void *AllocateUninitialized(size_t length) { return malloc(length); }
virtual void Free(void *data, size_t) { free(data); }
};
int main(int argc, char* argv[])
{
// Initialize V8.
V8::InitializeICU();
V8::InitializeExternalStartupData(argv[0]);
Platform* platform = platform::CreateDefaultPlatform();
V8::InitializePlatform(platform);
V8::Initialize();
// Create a new Isolate and make it the current one.
ArrayBufferAllocator allocator;
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
Isolate* isolate = Isolate::New(create_params);
Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
HandleScope handle_scope(isolate);
// Create a new context.
Local<Context> context = Context::New(isolate);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(context);
g_global = context->Global();
// Try to include this js file into current context
Local<String> source = _ReadFile(R"(somjsfile.js)");
Local<Script> script = Script::Compile(context, source).ToLocalChecked();
script->Run();
//
// functionName is a valid js code inside somjsfile.js file i test it and it's ok.
//
Handle<Value> js_result = CallJSFunction("functionName", nullptr, 0);
String::Utf8Value utf8(js_result);
printf("%s\n", *utf8);
}
// Dispose the isolate and tear down V8.
isolate->Dispose();
V8::Dispose();
V8::ShutdownPlatform();
delete platform;
return 0;
}
但是如果我像这样把代码放在 class 中,我就不能调用 CallJSFunction()
:
因为某些对象无法访问或为空
#pragma once
#include "Common.h"
#include <v8.h>
#include <libplatform.h>
using namespace v8;
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
virtual void *Allocate(size_t length) {
void *data = AllocateUninitialized(length);
return data == NULL ? data : memset(data, 0, length);
}
virtual void *AllocateUninitialized(size_t length) { return malloc(length); }
virtual void Free(void *data, size_t) { free(data); }
};
class JSUtil
{
private:
v8::Isolate * m_Isolate;
v8::Handle<v8::Object> m_global;
v8::Local<v8::Context> m_Context;
v8::Platform* m_platform;
std::string LoadFileAsString(const char* name)
{
#pragma warning(disable : 4996)
FILE* file = fopen(name, "rb");
if (file == nullptr)
return nullptr;
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '[=11=]';
for (int i = 0; i < size;)
{
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
std::string result = std::string(chars);
delete[] chars;
return result;
}
bool InitV8Engine()
{
std::string exepath = R"(fullpath_of_exename)";
// Initialize V8.
v8::V8::InitializeICU();
v8::V8::InitializeExternalStartupData(exepath.c_str());
m_platform = v8::platform::CreateDefaultPlatform();
v8::V8::InitializePlatform(m_platform);
v8::V8::Initialize();
// Create a new Isolate and make it the current one.
ArrayBufferAllocator allocator;
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
m_Isolate = v8::Isolate::New(create_params);
v8::Isolate::Scope isolate_scope(m_Isolate);
// Create a stack-allocated handle scope.
v8::HandleScope handle_scope(m_Isolate);
// Create a new context.
m_Context = v8::Context::New(m_Isolate);
// Enter the context for compiling and running the hello world script.
v8::Context::Scope context_scope(m_Context);
IncludeJSFile(m_Context->Global());
return true;
}
bool Shutdown()
{
// Dispose the isolate and tear down V8.
m_Isolate->Dispose();
V8::Dispose();
V8::ShutdownPlatform();
delete m_platform;
}
bool IncludeJSFile(v8::Handle<v8::Object> global)
{
//
// Try to include this js file into current context
//
// Create a string containing the JavaScript source code.
std::string FileBuff = LoadFileAsString(R"(somjsfile.js)");
v8::Local<v8::String> source = v8::String::NewFromUtf8(global->GetIsolate(), FileBuff.c_str());
// Compile the source code.
v8::Local<v8::Script> script = v8::Script::Compile(m_Context, source).ToLocalChecked();
// Run the script to get the result.
script->Run();
return true;
}
v8::Handle<v8::Value> CallJSFunction(std::string funcName, v8::Handle<v8::Value> argList[], unsigned int argCount)
{
v8::Handle<v8::Object> global = m_global;
// Create value for the return of the JS function
v8::Handle<v8::Value> js_result;
v8::Local<v8::String> tmp = v8::String::NewFromUtf8(global->GetIsolate(), funcName.c_str());
// Grab JS function out of file
v8::Handle<v8::Value> value = global->Get(tmp);
// Cast value to v8::Function
v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
// Call function with all set values
js_result = func->Call(global, argCount, argList);
// Return value from function
return js_result;
}
public:
JSUtil()
{
InitV8Engine();
}
~JSUtil()
{
Shutdown();
}
};
您将 v8::Local<...>
个对象放入 class,但 v8::Local
对象仅在 HandleScope
中有效。 HandleScope
消失后,您的 Local
也会消失。
相反,如果您想长期保存物品,则需要将它们变成 v8::Global<...>
。随着事物的移动,它们会由垃圾收集器不断更新,因此它们的成本更高,这就是为什么一切都不是全局的。
正在创建全局:
v8::Global<v8::Value> my_global(isolate, my_local);
让本地人退出:
v8::Local<v8::Value> my_local = my_global.Get(isolate);
需要注意的一点是,全局变量只能移动,因此您必须像处理 std::unique_ptr
.
一样处理它们
我想在 C++ 中基于 oop 的应用程序中使用 v8,但是我的代码中的 v8 对象范围存在一些问题,当我在一个函数中编写所有代码时,它工作得很好,但是当我将class(甚至一个名字space)一些对象将被破坏。
这段代码可以正常运行:
//#include "stdafx.h"
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <v8.h>
#include <libplatform.h>
using namespace v8;
Handle<v8::Object> g_global;
// Reads a file into a v8 string.
v8::Handle<v8::String> _ReadFile(const char* name)
{
#pragma warning(disable : 4996)
FILE* file = fopen(name, "rb");
if (file == NULL) return v8::Handle<v8::String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '[=10=]';
for (int i = 0; i < size;)
{
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
v8::Handle<v8::String> result = v8::String::NewFromUtf8(g_global->GetIsolate(), chars);
delete[] chars;
return result;
}
Handle<v8::Value> CallJSFunction( std::string funcName, Handle<Value> argList[], unsigned int argCount) {
Handle<v8::Object> global = g_global;
// Create value for the return of the JS function
Handle<Value> js_result;
// Grab JS function out of file
Handle<v8::Value> value = global->Get(String::NewFromUtf8(global->GetIsolate(), funcName.c_str()));
// Cast value to v8::Function
Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
// Call function with all set values
js_result = func->Call(global, argCount, argList);
// Return value from function
return js_result;
}
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
virtual void *Allocate(size_t length) {
void *data = AllocateUninitialized(length);
return data == NULL ? data : memset(data, 0, length);
}
virtual void *AllocateUninitialized(size_t length) { return malloc(length); }
virtual void Free(void *data, size_t) { free(data); }
};
int main(int argc, char* argv[])
{
// Initialize V8.
V8::InitializeICU();
V8::InitializeExternalStartupData(argv[0]);
Platform* platform = platform::CreateDefaultPlatform();
V8::InitializePlatform(platform);
V8::Initialize();
// Create a new Isolate and make it the current one.
ArrayBufferAllocator allocator;
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
Isolate* isolate = Isolate::New(create_params);
Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
HandleScope handle_scope(isolate);
// Create a new context.
Local<Context> context = Context::New(isolate);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(context);
g_global = context->Global();
// Try to include this js file into current context
Local<String> source = _ReadFile(R"(somjsfile.js)");
Local<Script> script = Script::Compile(context, source).ToLocalChecked();
script->Run();
//
// functionName is a valid js code inside somjsfile.js file i test it and it's ok.
//
Handle<Value> js_result = CallJSFunction("functionName", nullptr, 0);
String::Utf8Value utf8(js_result);
printf("%s\n", *utf8);
}
// Dispose the isolate and tear down V8.
isolate->Dispose();
V8::Dispose();
V8::ShutdownPlatform();
delete platform;
return 0;
}
但是如果我像这样把代码放在 class 中,我就不能调用 CallJSFunction()
:
因为某些对象无法访问或为空
#pragma once
#include "Common.h"
#include <v8.h>
#include <libplatform.h>
using namespace v8;
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
virtual void *Allocate(size_t length) {
void *data = AllocateUninitialized(length);
return data == NULL ? data : memset(data, 0, length);
}
virtual void *AllocateUninitialized(size_t length) { return malloc(length); }
virtual void Free(void *data, size_t) { free(data); }
};
class JSUtil
{
private:
v8::Isolate * m_Isolate;
v8::Handle<v8::Object> m_global;
v8::Local<v8::Context> m_Context;
v8::Platform* m_platform;
std::string LoadFileAsString(const char* name)
{
#pragma warning(disable : 4996)
FILE* file = fopen(name, "rb");
if (file == nullptr)
return nullptr;
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '[=11=]';
for (int i = 0; i < size;)
{
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
std::string result = std::string(chars);
delete[] chars;
return result;
}
bool InitV8Engine()
{
std::string exepath = R"(fullpath_of_exename)";
// Initialize V8.
v8::V8::InitializeICU();
v8::V8::InitializeExternalStartupData(exepath.c_str());
m_platform = v8::platform::CreateDefaultPlatform();
v8::V8::InitializePlatform(m_platform);
v8::V8::Initialize();
// Create a new Isolate and make it the current one.
ArrayBufferAllocator allocator;
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
m_Isolate = v8::Isolate::New(create_params);
v8::Isolate::Scope isolate_scope(m_Isolate);
// Create a stack-allocated handle scope.
v8::HandleScope handle_scope(m_Isolate);
// Create a new context.
m_Context = v8::Context::New(m_Isolate);
// Enter the context for compiling and running the hello world script.
v8::Context::Scope context_scope(m_Context);
IncludeJSFile(m_Context->Global());
return true;
}
bool Shutdown()
{
// Dispose the isolate and tear down V8.
m_Isolate->Dispose();
V8::Dispose();
V8::ShutdownPlatform();
delete m_platform;
}
bool IncludeJSFile(v8::Handle<v8::Object> global)
{
//
// Try to include this js file into current context
//
// Create a string containing the JavaScript source code.
std::string FileBuff = LoadFileAsString(R"(somjsfile.js)");
v8::Local<v8::String> source = v8::String::NewFromUtf8(global->GetIsolate(), FileBuff.c_str());
// Compile the source code.
v8::Local<v8::Script> script = v8::Script::Compile(m_Context, source).ToLocalChecked();
// Run the script to get the result.
script->Run();
return true;
}
v8::Handle<v8::Value> CallJSFunction(std::string funcName, v8::Handle<v8::Value> argList[], unsigned int argCount)
{
v8::Handle<v8::Object> global = m_global;
// Create value for the return of the JS function
v8::Handle<v8::Value> js_result;
v8::Local<v8::String> tmp = v8::String::NewFromUtf8(global->GetIsolate(), funcName.c_str());
// Grab JS function out of file
v8::Handle<v8::Value> value = global->Get(tmp);
// Cast value to v8::Function
v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
// Call function with all set values
js_result = func->Call(global, argCount, argList);
// Return value from function
return js_result;
}
public:
JSUtil()
{
InitV8Engine();
}
~JSUtil()
{
Shutdown();
}
};
您将 v8::Local<...>
个对象放入 class,但 v8::Local
对象仅在 HandleScope
中有效。 HandleScope
消失后,您的 Local
也会消失。
相反,如果您想长期保存物品,则需要将它们变成 v8::Global<...>
。随着事物的移动,它们会由垃圾收集器不断更新,因此它们的成本更高,这就是为什么一切都不是全局的。
正在创建全局:
v8::Global<v8::Value> my_global(isolate, my_local);
让本地人退出:
v8::Local<v8::Value> my_local = my_global.Get(isolate);
需要注意的一点是,全局变量只能移动,因此您必须像处理 std::unique_ptr
.