nodejs 本机插件:如何修改另一个本机插件中包含的 c++ 对象成员的值

nodejs native addon : how to modify the value of c++ object's member contained in another native addon

首先是一些上下文,我有两个 nodejs 原生插件。第一个包含静态 c++ 对象 "Conn" 使用 v8 对象内部字段公开,如嵌入程序指南中所述

NAN_METHOD(cobject) {
    auto isolate = Isolate::GetCurrent();
    Conn* p = &ConnHolder::connection;
    Local<ObjectTemplate> conn_templ = ObjectTemplate::New(isolate);
    conn_templ->SetInternalFieldCount(1); 
    Local<Object> obj = conn_templ->NewInstance();
    obj->SetInternalField(0, External::New(isolate, p));
    info.GetReturnValue().Set(obj);
}

在我的另一个本地插件中,我正在使用 C++ 代码加载第一个插件,我公开了一个名为 test 的函数,其中包含对 Conn 对象的两次调用 "callToDummyFunction()" 和 "callToFunctionWithMemberAccess()"

// persistent handle for the main addon
static Persistent<Object> node_main;


void Init(v8::Local<v8::Object> exports, v8::Local<v8::Object> module) {
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    // get `require` function
    Local<Function> require = module->Get(String::NewFromUtf8(isolate, "require")).As<Function>();
    Local<Value> args[] = { String::NewFromUtf8(isolate, "path_to_my_addon\addon.node") };

    Local<Object> main = require->Call(module, 1, args).As<Object>();
    node_main.Reset(isolate, main); 
    NAN_EXPORT(exports, test);

}

NAN_METHOD(test) {
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    // get local handle from persistent
    Local<Object> main = Local<Object>::New(isolate, node_main);

    // get `cobject` function to get pointer from internal field
    Local<Function> createdMain = main->Get(String::NewFromUtf8(isolate,     "cobject")).As<Function>();

    Local<Object> callResult = createdMain->Call(main, 0, nullptr).As<Object>();
    Local<Object> self = info.Holder();
    Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
    void* ptr = wrap->Value();

    // from there i get a pointer to my Conn object
    Conn* con = static_cast<Conn*>(ptr);

    conn->callToDummyFunction();
    conn->callToFunctionWithMemberAccess();

    info.GetReturnValue().Set(10);

}

然后我使用 "node" 启动一个 nodejs 会话,我使用两个 require 调用加载第一个和第二个插件,最后我在第二个插件上调用方法测试。

方法测试已执行,对 "callToDummyFunction" 的调用已成功执行,但对 "callToFunctionWithMemberAccess" 的调用崩溃并终止了节点会话。

好的,那么 "callToDummyFunction" 和 "callToFunctionWithMemberAccess" 有什么区别?

bool Conn::callToDummyFunction()
{
    cout << "callToDummyFunction" << endl;
    return true;
}

bool Conn::callToFunctionWithMemberAccess()
{
    cout << "callToFunctionWithMemberAccess " << someIntMember << endl;
    return true;
}

因此,访问 Conn 对象的成员似乎会产生错误并使节点会话崩溃。节点会话在崩溃前不输出任何消息。

谁能告诉我为什么?

And/Or

如何获取错误消息?

我正在回答我自己的问题。事实上,我很愚蠢,但至少我的愚蠢让我学到了一些奇怪的 cpp 东西。

所以,首先是愚蠢的答案。我没有使用我返回的对象,而是使用了一个完全不相关的对象:(

Local<Object> callResult = createdMain->Call(main, 0, nullptr).As<Object>();
Local<Object> self = info.Holder();
Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));

为什么使用

Local self = info.Holder();

而不是 callResult。正确的代码是

Local<Object> callResult = createdMain->Call(main, 0, nullptr).As<Object>();
Local<External> wrap = Local<External>::Cast(callResult->GetInternalField(0));

我从这个愚蠢的错误中学到了什么:

  • 仔细阅读你的代码(显而易见)
  • 如果函数中没有任何成员访问权限,则在 nullptr 上执行成员函数实际上是有效的(对于有经验的 cpp 开发人员来说这可能是显而易见的)
  • 原生插件存在于它们自己的虚拟机中,虚拟机之间不共享静态字段。