Собственное дополнение nodejs: как изменить значение члена объекта C++, содержащегося в другом встроенном дополнении

Сначала немного контекста, я получил два ноджинских аддона Первый содержит статический объект 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);

}

Затем я запускаю сеанс 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 ответ

Решение

Я отвечаю на свой вопрос. На самом деле, я глуп, но, по крайней мере, моя глупость заставила меня научиться некоторым странным вещам 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)
  • Нативные аддоны живут в своем собственном vm, статические поля не делятся между vms.
Другие вопросы по тегам