Calling a v8 javascript function from c++ with an argument

2023-11-20

I am working with c++ and v8, and have run into the following challenge: I want to be able to define a function in javascript using v8, then call the function later on through c++. Additionally, I want to be able to pass an argument to the javascript function from c++. I think the following sample source code would explain it best. Check towards the end of the sample code to see what I am trying to accomplish.

#include <v8.h>
#include <iostream>
#include <string>
#include <array>

using namespace v8;

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

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

    // Create a new context.
    Persistent<Context> context = Context::New();
    Context::Scope context_scope(context);
    Handle<String> source;
    Handle<Script> script;
    Handle<Value> result;

    // Create a string containing the JavaScript source code.
    source = String::New("function test_function(test_arg) { var match = 0;if(test_arg[0] == test_arg[1]) { match = 1; }");

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

    // What I want to be able to do (this part isn't valid code..
    // it just represents what I would like to do.
    // An array is defined in c++ called pass_arg,
    // then passed to the javascript function test_function() as an argument
    std::array< std::string, 2 > pass_arg = {"value1", "value2"};
    int result = script->callFunction("test_function", pass_arg);

}

Any tips?

UPDATE:

Based on the advice given, I have been able to put together the following code. It has been tested and works:

#include <v8.h>
#include <iostream>
#include <string>

using namespace v8;

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

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

// Create a new context.
Persistent<Context> context = Context::New();

//context->AllowCodeGenerationFromStrings(true);

// Enter the created context for compiling and
// running the hello world script.
Context::Scope context_scope(context);
Handle<String> source;
Handle<Script> script;
Handle<Value> result;


// Create a string containing the JavaScript source code.
source = String::New("function test_function() { var match = 0;if(arguments[0] == arguments[1]) { match = 1; } return match; }");

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

// Run the script to get the result.
result = script->Run();
// Dispose the persistent context.
context.Dispose();

// Convert the result to an ASCII string and print it.
//String::AsciiValue ascii(result);
//printf("%s\n", *ascii);

Handle<v8::Object> global = context->Global();
Handle<v8::Value> value = global->Get(String::New("test_function"));
Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
Handle<Value> args[2];
Handle<Value> js_result;
int final_result;

args[0] = v8::String::New("1");
args[1] = v8::String::New("1");

js_result = func->Call(global, 2, args);
String::AsciiValue ascii(js_result);

final_result = atoi(*ascii);

if(final_result == 1) {

    std::cout << "Matched\n";

} else {

    std::cout << "NOT Matched\n";

}

return 0;

}
asked  Jul 8 '12 at 21:53
user396404
1,151 5 19 33
 
 
I assume that IsInt32 returns true, but Int32Value returns 0? –  Nate Kohl  Jul 10 '12 at 19:36
 
Check out my edit -- maybe we're not passing enough parameters... –  Nate Kohl  Jul 10 '12 at 19:52
 
You have a mistake in your code: you dispose the current context and after you are using it. You must put the dispose line at the end of your program. –  banuj  Jun 5 '13 at 8:20 

2 Answers

up vote 11 down vote accepted

I haven't tested this, but it's possible that something like this will work:

// ...define and compile "test_function"

Handle<v8::Object> global = context->Global();
Handle<v8::Value> value = global->Get(String::New("test_function")); 

if (value->IsFunction()) {
    Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value);
    Handle<Value> args[2];
    args[0] = v8::String::New("value1");
    args[1] = v8::String::New("value2");

    Handle<Value> js_result = func->Call(global, 2, args);

    if (js_result->IsInt32()) {
        int32_t result = js_result->ToInt32().Value();
        // do something with the result
    }
}

Edit:

It looks like your javascript function expects a single argument (consisting of an array of two values), but it kinda looks like we're calling func by passing in two arguments.

To test this hypothesis, you could change your javascript function to take two arguments and compare them, e.g.:

function test_function(test_arg1, test_arg2) { 
  var match = 0; 
  if (test_arg1 == test_arg2) { 
    match = 1; 
  } else { 
    match = 0; 
  } 
  return match; 
}
answered  Jul 8 '12 at 23:58
Nate Kohl
18.4k 7 33 46
 
 
It seems to be working. I'm having trouble using js_result though. The part where it says if(js_result.IsInt32) is giving the following error during compile time: error: ‘class v8::Handle<v8::Value>’ has no member named ‘Int32’| –  user396404  Jul 10 '12 at 0:36 
1  
@user396404: maybe try js_result->IsInt32() instead? –  Nate Kohl  Jul 10 '12 at 11:26
 
That did work. The code compiles, but it is not returning a value of 1 even if the values match :/ –  user396404  Jul 10 '12 at 19:20
 
Thanks for all the help. It turns out I had to reference the variables using the arguments array, instead of test_arg1 and test_arg2. For anyone reading this in the future, the part where it says Call(global, 2, args), the 2 represents the length of the args array. I posted the revised and working code in my original answer. Thanks for all the help! –  user396404  Jul 10 '12 at 23:00

Another simpler method is as follows:

Handle<String> code = String::New(
  "(function(arg) {\n\
     console.log(arg);\n\
    })");
Handle<Value> result = Script::Compile(code)->Run();
Handle<Function> function = Handle<Function>::Cast(result);

Local<Value> args[] = { String::New("testing!") };
func->Call(Context::GetCurrent()->Global(), 1, args);

Essentially compile some code that returns an anonymous function, then call that with whatever arguments you want to pass.

answered  Jun 4 '13 at 17:50
jkp
33.7k 18 83 95
 
 
v8::ScriptCompiler::CompileFunctionInContext does the "wrap your code in a function" bit for you. –  xaxxon Oct 11 at 21:19
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Calling a v8 javascript function from c++ with an argument 的相关文章

随机推荐

  • 项目中:Json文件的读取

    项目中 Json文件的读取 读Json文件 取Json文件中内容 举例 举例 Json文件内容如下 Flickr8k images sentids 39300 39301 39302 39303 39304 imgid 7860 sente
  • C++11中 std::bind 的两种用法

    概述 std bind的头文件是
  • hadoop环境搭建之关闭防火墙和SELinux

    每一台服务器上都要做1 2 1 关闭防火墙 查看防火墙状态 systemctl status firewalld 关闭防火墙 systemctl disable firewalld systemctl stop firewalld 查看防火
  • iOS 获取系统键盘UIKeyboard方法

    公司项目需求 需要让弹窗显示在键盘所在的图层之上 而不是在弹窗出现的时候消失 如图1 系统弹窗出现的时候会使键盘暂时不显示 而这种效果显然不符合要求的 由于没想到更好的办法 只好从键盘自身的UIKeyboard做文章了 通过获取当前键盘的U
  • 【Java多线程批量数据导入的方法】

    前言 当遇到大量数据导入时 为了提高处理的速度 可以选择使用多线程来批量处理这些处理 常见的场景有 大文件导入数据库 这个文件不一定是标准的CSV可导入文件或者需要在内存中经过一定的处理 数据同步 从第三方接口拉取数据处理后写入自己的数据库
  • 按装完mysql怎么启动_mysql安装完怎么启动服务器?

    mysql安装完启动服务器的方法 1 打开 开始 菜单 依次点击 管理工具 服务 打开系统服务窗口 2 在 服务 窗口中找到 MySQL 右击选择 启动 命令就可以启动mysql服务器了 mysql 是世界流行的开源数据库系统 下面本篇文章
  • 关于TypeScript和React的使用

    TS和React的使用 接口与类型 type与interface 内置的语法糖 Partial和Required Readonly Omit Exclude 继承 接口与类型 type与interface 内置的语法糖 Partial和Re
  • ffmpeg错误码

    cpp view plain copy AVERROR BSF NOT FOUND 1179861752 AVERROR BUG 558323010 AVERROR DECODER NOT FOUND 1128613112 AVERROR
  • 数字化转型中的国产化替代之路

    引言 数字经济浪潮席卷全球 我国数字经济已进入快速发展阶段 加快推进企业数字化转型 已成为共识 同时有利于构建全产业链数字化生态 增强产业链上下游的自主可控能力 为数字经济社会发展 构建数智化生态注入新动能 在此过程中 国产软件企业作为数字
  • python利用tushare下载数据并计算当日收益率

    python利用tushare下载数据并计算当日收益率 计算股票收益率的程序主要有以下几部分构成 1 获取股票接口数据函数 pro daily stock 2 计算收益率函数 cal stock 里面有两种计算式 你可以根据自己字典写入建仓
  • 堆排序的topk问题+归并排序+六大排序总结

    回忆一下堆排序 思路 sift函数 调整 将父亲和孩子 左孩子和右孩子中最大的那个数 然后和父亲比较 如果孩子大就将孩子的位子变为下一个父亲 往下拉 并且将孩子的值赋给他的父亲 j lt high 条件认可 防止父亲在最后一层 魔法般的对应
  • Tensorflow的Win10、CPU版本安装

    1 Anaconda的安装 Miniconda的安装 Anaconda的安装链接 https www anaconda com products distribution 如图所示 点击箭头所指 可以安装anaconda的最新版本 Mini
  • elementui 禁止浏览器自动填充用户名密码

    浏览器这功能在登录的时候挺好用的 但是在注册和管理的时候就很难受了 所以 在普通的input上直接off就行了
  • 华为虚拟机服务器怎么使用教程,虚拟机装服务器教程

    虚拟机装服务器教程 内容精选 换一换 应用容器化改造有三种方式 您可单击这里查看 本教程以某游戏为例 将该游戏进行微服务的架构改造 再进行容器化 本教程不对改造细节做深度讲解 仅讲解大致的建议 如需要详细了解容器化改造的过程 请单击服务咨询
  • 攻防世界adworld-hit-the-core

    hit the core 题目来源 CTF 题目描述 暂无 题目附件 下载附件 kwkl kwkl strings home kwkl 桌面 8deb5f0c2cd84143807b6175f58d6f3f core CORE code c
  • 【视频流上传播放功能】前后端分离用springboot-vue简单实现视频流上传和播放功能【详细注释版本,包含前后端代码】

    前言 我是前端程序猿一枚 不是后端的 如有写的有不规范的地方别介意哈 自己摸索了两天算是把这个功能做出来了 网上看了很多帖子没注释说实话 我看的基本是懵逼的 毕竟没有系统学过 所以现在做出来了就总结一下 自己多写点注释解释一下逻辑 让前端的
  • SpringBoot+MyBatisPlus+Thymeleaf+AdminLTE增删改查实战

    说明 AdminLTE是网络上比较流行的一款Bootstrap模板 包含丰富的样式 组件和插件 非常适用于后端开发人员做后台管理系统 因为最近又做了个后台管理系统 这次就选的是AdminLTE做主题模板发现效果不错 这里我把最核心的Spri
  • 华为机考练习python

    HJ108 求最小公倍数 while True try a b map int input split for i in range 1 b 1 if a i b 0 print a i break except break HJ107 求
  • linux中256错误,YUM安装遭遇: [Errno 256] No more mirrors to try

    把YUM配置好后 使用yum命令进行安装时 出现了如下错误 Downloading Packages ftp 192 168 220 46 RHEL6 2 x64 Server libaio devel 0 3 107 10 el6 x86
  • Calling a v8 javascript function from c++ with an argument

    Calling a v8 javascript function from c with an argument up vote 18 down vote favorite 8 I am working with c and v8 and