如何将C ++类返回给NODE.JS

设置:
我有一个NODE.JS应用程序,它必须以低延迟执行一些计算
我决定使用N-API和node-gyp在NODE.JS应用程序中包含一个本机C ++模块

当前状态:
到了工具链可以工作的地步,我可以将C ++源代码编译成二进制文件,将二进制模块包含在NODE.JS应用程序中,然后执行NODE.JS应用程序
我可以从NODE.JS调用具有标准NODE.JS类型的C ++方法,并且在执行完成后这些方法可以将标准NODE.JS类型返回到NODE.JS。

问题:
我不知道如何将自定义类型/对象从C ++返回到NODE.JS
目前,我想基本上返回一个具有多个类型的结构,以便在单个NODE.JS调用中将复杂解析的结果返回给NODE.JS

最小代码输出:
我做了一个最小的实现来演示我想做的事情。 如果您注释#define ENABLE_RETURN_CLASS,则代码仅使用标准的NODE.JS类型,并且一切正常。在输出图像下方,显示了工具链和执行按预期方式进行的操作:

如何将C ++类返回给NODE.JS

如果您离开#define ENABLE_RETURN_CLASS,则代码将无法编译。据我所知,它不理解如何从C ++对象转换为NODE.JS对象。这是错误:

如何将C ++类返回给NODE.JS

最小代码:
初始化NODE.JS应用程序

npm init
npm install node-gyp --save-dev
npm install node-addon-api

将C ++二进制文件编译为NODE.JS模块

npm run build

启动NODE.JS应用程序

node main.js

此代码位于以下存储库中:
https://github.com/OrsoEric/2020-01-18-Test-NODEJS-Return-Class
找到解决方案后,我打算对其进行更新。

我想返回到NODE.JS应用程序的类的代码:

my_class.h

namespace User
{
    //Class I want to return to NODE.JS
    class My_class
    {
        public:
            //Constructor
            My_class( void );
            //Public references
            float &my_float( void );
            int &my_int( void );
        private:
            //Private class vars
            float g_my_float;
            int g_my_int;
    };
}   //End namestace: User

my_class.cpp

#include <iostream>
//Class header
#include "my_class.h"

namespace User
{
    //Constructor
    My_class::My_class( void )
    {
        this -> g_my_float = (float)1.001;
        this -> g_my_int = (int)42;
    }
    //Public Reference
    float &My_class::my_float( void )
    {
        return this -> g_my_float;
    }
    //Public Reference
    int &My_class::my_int( void )
    {
        return this -> g_my_int;
    }
}   //End namestace: User

C ++和NODE.JS之间绑定的代码。 #define ENABLE_RETURN_CLASS启用返回类的代码。此示例中的实例是全局变量。

node_bindings.cpp

//NODE bindings
#include <napi.h>
//C++ Class I want to return to NODE.JS
#include "my_class.h"

//Comment to disable the code that return the class instance
//#define ENABLE_RETURN_CLASS

//Instance of My_class I want to return to NODE.JS
User::My_class g_instance;

//Prototype of function called by NODE.JS that initializes this module
extern Napi::Object init(Napi::Env env,Napi::Object exports);
//Prototype of function that returns a standard type: WORKS
extern Napi::Number get_my_float(const Napi::CallbackInfo& info);

#ifdef ENABLE_RETURN_CLASS
//Prototype of function that returns My_class to NODE.JS: DOES NOT WORK!!!
extern Napi::Object get_my_class(const Napi::CallbackInfo& info);
#endif // ENABLE_RETURN_CLASS

//Initialize instance
Napi::Object init(Napi::Env env,Napi::Object exports)
{
    //Construct the instance of My_class I want to return to NODE.JS
    g_instance = User::My_class();
        //Register methods accessible from the outside in the NODE.JS environment
    //Return a standard type
    exports.Set( "get_my_float",Napi::Function::New(env,get_my_float) );
    #ifdef ENABLE_RETURN_CLASS
    //Return the whole class
    exports.Set( "get_my_class",get_my_class) );
    #endif

    return exports;
}   //End function: init | Napi::Env | Napi::Object

//Interface between function and NODE.JS
Napi::Number get_my_float(const Napi::CallbackInfo& info)
{
    Napi::Env env = info.Env();
    //Check arguments
    if (info.Length() != 0)
    {
        Napi::TypeError::New(env,"ERR: Expecting no arguments").ThrowAsJavaScriptException();
    }
    //Get the return value
    float tmp = g_instance.my_float();
    //Return a NODE.JS number
    return Napi::Number::New(env,(float)tmp);
} //End Function: get_my_float | Napi::CallbackInfo&

#ifdef ENABLE_RETURN_CLASS
//Interface between function and NODE.JS
Napi::Object get_my_class(const Napi::CallbackInfo& info)
{
    Napi::Env env = info.Env();
    //Check arguments
    if (info.Length() != 0)
    {
        Napi::TypeError::New(env,"ERR: Expecting no arguments").ThrowAsJavaScriptException();
    }
    //Get the return value
    User::My_class tmp = g_instance;
    //Return a NODE.JS number
    return Napi::Object::New(env,(User::My_class)tmp);
} //End Function: get_my_float | Napi::CallbackInfo&
#endif // ENABLE_RETURN_CLASS

NODE_API_MODULE( My_cpp_module,init )

NODE.JS应用程序 main.js 包括并执行C ++模块:

//Include native C++ module
const my_custom_cpp_module = require('./build/Release/MyCustomCppModule.node');
console.log('My custom c++ module',my_custom_cpp_module);

//TEST:
tmp = my_custom_cpp_module.get_my_float();
console.log( tmp );

module.exports = my_custom_cpp_module;

绑定在文件 binding.gyp 中进行了描述:

{
    "targets": [{
        "target_name": "MyCustomCppModule","cflags!": [ "-fno-exceptions" ],"cflags_cc!": [ "-fno-exceptions" ],"sources": [
            "node_bindings.cpp","my_class.cpp"
        ],'include_dirs': [
            "<!@(node -p \"require('node-addon-api').include\")"
        ],'libraries': [],'dependencies': [
            "<!(node -p \"require('node-addon-api').gyp\")"
        ],'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
    }]
}

NODE.JS需要 package.json 来解决依赖关系,编译并运行

{
  "name": "2020-01-18-test-return-object","version": "1.0.0","description": "","main": "main.js","scripts": {
    "build": "node-gyp rebuild","clean": "node-gyp clean"
  },"author": "","license": "ISC","gypfile": true,"devDependencies": {
    "node-gyp": "^6.1.0"
  },"dependencies": {
    "node-addon-api": "^2.0.0"
  }
}

解决方案

我无法在Napi :: Object内放入自定义类,但是我可以创建一个空的Napi :: Object并逐个创建字段。 https://github.com/OrsoEric/2020-01-18-Test-NODEJS-Return-Class

node_bindings.cpp

内实现Napi :: Object的正确构造
//NODE bindings
#include <napi.h>
//C++ Class I want to return to NODE.JS
#include "my_class.h"

//Comment to disable the code that return the class instance
#define ENABLE_RETURN_CLASS

//Instance of My_class I want to return to NODE.JS
User::My_class g_instance;

//Prototype of function called by NODE.JS that initializes this module
extern Napi::Object init(Napi::Env env,"ERR: Expecting no arguments").ThrowAsJavaScriptException();
    }
    //Get a copy of the instance of the class I want to return
    User::My_class tmp = g_instance;
    //Construct empty return object in the NODE.JS environment
    Napi::Object ret_tmp = Napi::Object::New( env );
    //Manually create and fill the fields of the return object
    ret_tmp.Set("my_float",Napi::Number::New( env,(float)tmp.my_float() ));
    ret_tmp.Set("my_int",(int)tmp.my_int() ));
    //Return a NODE.JS Object
    return (Napi::Object)ret_tmp;
} //End Function: get_my_class | Napi::CallbackInfo&
#endif // ENABLE_RETURN_CLASS

NODE_API_MODULE( My_cpp_module,init )

main.js 中添加测试说明:

//Include native C++ module
const my_custom_cpp_module = require('./build/Release/MyCustomCppModule.node');
console.log('My custom c++ module',my_custom_cpp_module);

//TEST: Standard NODE.JS type
tmp = my_custom_cpp_module.get_my_float();
console.log( tmp );
//Custom NODE.JS type
class_tmp = my_custom_cpp_module.get_my_class();
console.log( class_tmp );

module.exports = my_custom_cpp_module;

输出:

如何将C ++类返回给NODE.JS

qjp1970 回答:如何将C ++类返回给NODE.JS

我认为,如Napi::Object docs中所述,您无法使用自定义类实例化对象。仅原始值。因此,我建议创建一个空的Napi::Object并使用它的Set来映射值。

Napi::Object ret = Napi::Object::New(env);

ret.Set("my_float",Napi::Number::New(env,(float)tmp.my_float()));

填充所有字段并返回对象。就像您使用exports

,

您可以在Napi :: Object中放入一个自定义类,这很容易销毁:

class MyObject : public Napi::ObjectWrap<MyObject> {
  void * inner_obj_;
}

并使用reinterpret_cast对其进行调用:

reinterpret_cast<MyClass *>(inner_obj_)->my_float();
本文链接:https://www.f2er.com/2748369.html

大家都在问