使用 node.js 从 C++ 调用 JavaScript

Posted

技术标签:

【中文标题】使用 node.js 从 C++ 调用 JavaScript【英文标题】:Calling JavaScript from C++ with node.js 【发布时间】:2015-05-23 18:44:58 【问题描述】:

有没有办法通过 node.js 从 C++ 调用 JS 函数(作为回调或类似的东西)? 如果是,如何? 我正在网上搜索它,但没有找到任何有用的资源。

提前致谢

【问题讨论】:

***.com/questions/9629677/… nodejs.org/api/addons.html#addons_callbacks 这些链接与 OP 所要求的完全相反。如何调用JS FROM C++. 【参考方案1】:

当然可以。例如,如果你想在C++ 中编写一个简单的阶乘函数,你可以这样做

#include <node.h>

using namespace v8;

int factorial(int n) 
    if (n == 0) return 1;
    else return n * factorial(n - 1);


void Factorial(const FunctionCallbackInfo<Value>& args) 
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    if (args.Length() != 2) 
        isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong number of arguments")));
     else 
        if (!(args[0]->IsNumber() && args[1]->IsFunction())) 
            isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, "Wrong arguments type")));
         else 
            int result = factorial(args[0]->Int32Value());

            Local<Function> callbackFunction = Local<Function>::Cast(args[1]);
            const unsigned argc = 1;
            Local<Value> argv[argc] =  Number::New(isolate, result) ;

            callbackFunction->Call(isolate->GetCurrentContext()->Global(), argc, argv);
        
    


void Init(Handle<Object> exports) 
    NODE_SET_METHOD(exports, "factorial", Factorial);


NODE_MODULE(Factorial, Init)

在你的 javascript 文件中,这样称呼它

var factorialAddon = require('./addons/Factorial');
factorialAddon.factorial(5, function (result) 
    console.log(result);
);

【讨论】:

他的意思是相反的......来自cpp调用js【参考方案2】:

答案是肯定的,这里有一个方法:

我创建了一个名为 index.js 的 js 文件,这是文件的路径

D:\NodeJS\call_js_from_cpp 

它包含以下代码

console.log("hello");

现在我有一个 C++ 代码,它执行以下 shell 命令并将输出存储在变量“输出”(它是一个字符串)中:

node D:\NodeJS\call_js_from_cpp\index.js

这里是C++代码:(注意在代码中,路径中有双\所以它变成了这个节点D:\NodeJS\call_js_from_cpp\index.js)

#include<iostream>
#include<fstream>
#include<string>
#include<cstdlib>
#include<sstream>

std::string ssystem (const char *command) 
  char tmpname [L_tmpnam];
  std::tmpnam ( tmpname );
  std::string scommand = command;
  std::string cmd = scommand + " >> " + tmpname;
  std::system(cmd.c_str());
  std::ifstream file(tmpname, std::ios::in );
  std::string result;
  if (file) 
   while (!file.eof()) result.push_back(file.get());
   file.close();
  
  remove(tmpname);
  return result;


//for cygwin

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

   std::string bash = "node D:\\NodeJS\\call_js_from_cpp\\index.js";
   std::string in;
   std::string s = ssystem(bash.c_str());
   std::istringstream iss(s);
   std::string output;
   while ( std::getline(iss, output) )
    
      std::cout << output;
    

   return 0;
 

【讨论】:

我认为 OP 是在询问是否引用了 v8 的函数并调用它,而不是从 C++ 应用程序生成节点进程。 @SigmaSoldier,您的意思是在 C++ 进程和 Nodejs 进程之间建立 IPC,C++ 将能够触发 NodeJs 的功能?或者您是否打算针对 NodeJs 进程使用 C++ 信号来触发这些功能?有很多方法可以根据要求“通过 node.js(作为回调或类似的东西)从 C++ 调用 JS 函数”,而这似乎是最简单和最直观的一种。 我认为 OP 意味着编写一个本地插件来捕获对函数的引用,然后调用它。但无论如何,这应该由 OP 澄清。【参考方案3】:

形成原生插件的一种方法是使用提供的函数作为回调,例如,假设您在原生环境中声明了一个名为 setPrintFunction() 的函数(原生插件):

(例如打电话给main.cc

#include <node.h>
#include <string>

v8::Persistent<v8::Function> fn;

// Call this at any time, but after the capture!
void printToNode(std::string msg) 
  auto isolate = fn->GetIsolate();
  // This part is the one that transforms your std::string to a javascript
  // string, and passes it as the first argument:
  const unsigned argc = 1;
  auto argv[argc] = 
      v8::String::NewFromUtf8(isolate,
                          msg.c_str(),
                          v8::NewStringType::kNormal).ToLocalChecked()
  ;
  cb->Call(context, Null(isolate), argc, argv).ToLocalChecked();


// This is your native function that captures the reference
void setPrintFunction(const v8::FunctionCallbackInfo<Value>& args) 
  auto isolate = args.GetIsolate();
  auto context = isolate->GetCurrentContext();
  auto cb = v8::Local<v8::Function>::Cast(args[0]);
  fn = v8::Persistent<v8::Function>::New(cb);


// This part exports the function
void Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module) 
  NODE_SET_METHOD(module, "exports", setPrintFunction);


NODE_MODULE(NODE_GYP_MODULE_NAME, Init)

然后,只需导入您的插件并像这样使用它:

(例如打电话给index.js

const  setPrintFunction  = require('<your path to .node file>');

function printNodeMsg(msg) 
  console.log('<msg>: ' + msg);


setPrintFunction(printNodeMsg);

因此,您基本上要做的是捕获对v8::Function 的引用(这是javascript 函数,但在本机环境中),然后调用它并将"Hello World!" 作为第一个(也是唯一的)参数传递。

关于这个主题的更多信息:https://nodejs.org/api/addons.html

【讨论】:

您能否添加一个示例如何在 C++ 中使用该解决方案?在这种情况下,将 std::string 传递给 C++ 函数,该函数将传递给对应的 Javascript。 我想我得到了你想要的:例如,可以是一个函数,它捕获对另一个函数的引用,然后根据你的意愿,在调用它的本机部分中创建一个函数。这可能是一个可能的解决方案? 好吧,当我问这个问题时,我想知道以下内容:假设我有一个 JS 函数printNodeMsg(msg),我想调用它并将msg 参数传递给它C++。插件不是问题,但我希望能够传递参数,而不仅仅是调用函数。所以基本上调用C++函数void printNodeMsg(const std::string&amp; msg)会在JS站点调用prontNodeMsg(msg),传递指定的字符串数据。 这个解决方案不是与OP的问题相反吗? @barath OP 询问如何从 C++ 上下文调用 JavaScript 创建的函数,但使用 node.据我所知,OP 想要一个可以提供 JS 函数的 C/C++ 过程,以便可以从 JS 上下文中制作它,但稍后在 C++ 程序的过程中使用。

以上是关于使用 node.js 从 C++ 调用 JavaScript的主要内容,如果未能解决你的问题,请参考以下文章

如何从 node.js 调用外部脚本/程序

是否可以使用 Emscripten 从 JavaScript 调用 C++ 函数?

使用包含来自 Node.js 的 char 数组的结构调用 C++ dll

如何使用node.js中的C ++库?

如何使用 node.js 和 javascript 模仿 Facebook 的“链接共享”功能

图书Node.js:来一打 C++ 扩展