How to pass web assembly c++ objects to javascript callback with Emscripten

问题描述 投票:0回答:1

我使用 Emscripten 将 C++ 代码编译为 Web 程序集。使用 Emscripten 可以通过绑定器之一 - Embind 或 WebIdl-binder 将 c++ 对象公开给 javascript。我正在使用 Embind。当我们想要将 c++ 对象返回到 javascript 作为 web 程序集调用的返回值或直接创建它们时,绑定工作得很好。

在我的例子中,我的 web assembly 代码需要回调 javascript 以获得一些数据,然后恢复 web assembly 流程。在这种情况下,在 c++ 的 javascript 回调中,我需要传递一个结构,js 代码应在其中填充数据。但是,当我这样做而不是 js 回调中的 c++ 对象时,我收到一个数字。我猜这个数字是 c++ 对象的地址,而不是对象本身。

我的问题是——我是不是遗漏了什么,或者无法将 C++ 对象作为参数传递给 javascript 回调。这是示例代码:

C++

#include "emscripten/bind.h"

using emscripten::class_;

class TestClass
{
public:
    int a;
    int b;

    int GetA() { return a; }
    int GetB() { return b; }
};


extern "C" {
  extern void testCallback(TestClass testClass);
}

void testFunction() {
    TestClass testClass;
    testClass.a = 5;
    testClass.b = 10;

    std::cout << "Calling js callback" << std::endl;
    testCallback(testClass);
    std::cout << "Js callback called!" << std::endl;
}

EMSCRIPTEN_BINDINGS(test_project)
{
    class_<TestClass>("TestClass")
        .constructor()
        .function("GetB", &TestClass::GetB)
        .function("GetA", &TestClass::GetA);

    emscripten::function("testFunction", &testFunction);
};

JS:

mergeInto(LibraryManager.library, {
    testCallback: function(testClass) {
        console.log(testClass);        // prints 65496
        console.log(testClass.GetA()); // error: TypeError: testClass.GetA is not a function
    }
});
javascript c++ webassembly emscripten embind
1个回答
0
投票

当将 C++ 对象作为参数传递给 JavaScript 函数时,Emscripten 绑定将自动创建一个表示 C++ 对象的 JavaScript 对象,并将其地址作为整数传递给 JavaScript 函数。这称为对象引用编组。

为了在 JavaScript 函数中访问 C++ 对象的方法和属性,您需要创建一个代表 C++ 对象的 JavaScript 对象。为此,您可以使用 Embind 库提供的 register_class 函数。以下是如何修改代码以使用 register_class 的示例:

C++:

#include "emscripten/bind.h"

using emscripten::class_;
using emscripten::register_class;

class TestClass {
 public:
  int a;
  int b;

  int GetA() { return a; }
  int GetB() { return b; }
};

void testFunction() {
  TestClass testClass;
  testClass.a = 5;
  testClass.b = 10;

  std::cout << "Calling js callback" << std::endl;
  testCallback(testClass);
  std::cout << "Js callback called!" << std::endl;
}

EMSCRIPTEN_BINDINGS(test_project) {
  class_<TestClass>("TestClass")
    .constructor()
    .function("GetB", &TestClass::GetB)
    .function("GetA", &TestClass::GetA);

  function("testFunction", &testFunction);
}

extern "C" {
  extern void testCallback(TestClass* testClass);
}

JS:

mergeInto(LibraryManager.library, {
  testCallback: function(testClassPtr) {
    var TestClass = Module.TestClass;
    var testClass = new TestClass(testClassPtr);
    console.log(testClass.GetA());
    console.log(testClass.GetB());
  }
});

在此修改后的代码中,testCallback 函数现在采用指向 TestClass 对象的指针而不是对象本身。在 JavaScript 函数中,我们使用 Embind 库提供的 register_class 函数创建一个新的 TestClass 对象,传入 C++ 对象的地址。然后我们可以像往常一样在 JavaScript 函数中访问 TestClass 对象的方法和属性。

请注意,在 C++ 代码中,我们还更新了 testCallback 函数以获取指向 TestClass 对象的指针,并修改了 testFunction 函数以使用指向对象的指针而不是对象本身来调用 testCallback。

© www.soinside.com 2019 - 2024. All rights reserved.