代码之家  ›  专栏  ›  技术社区  ›  Mumrah81

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

  •  1
  • Mumrah81  · 技术社区  · 6 年前

    首先,在一些上下文中,我得到了两个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对象的成员似乎会产生错误并导致节点会话崩溃。节点会话在崩溃之前不会输出任何消息。

    有人能告诉我为什么吗?

    和/或

    如何获取错误消息?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Mumrah81    6 年前

    我在回答我自己的问题。事实上,我很愚蠢,但至少我的愚蠢让我学到了一些奇怪的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));
    

    为什么使用

    本地自我=信息。支架();

    而不是callResult。正确的代码应该是

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

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

    • 仔细阅读代码(显而易见)
    • 如果函数中没有任何成员访问权限,那么在nullptr上执行成员函数实际上是可行的(对于有经验的cpp开发人员来说,这可能是显而易见的)
    • 本机加载项位于自己的vm中,vm之间不共享静态字段。