使用Emscripten异步调用JavaScript中的C ++函数

时间:2016-03-04 17:44:22

标签: javascript c++ emscripten

我对Emscripten提出了一个小问题。 如何从JavaScript中异步调用C ++回调?

这是我的JS代码:

  <script type="text/javascript">
    function sendRequest(callback) {   
      setTimeout(function(){
        callback["sayHi"]();
      }, 100);
    }
  </script>

这是我的C ++代码:

#include <emscripten/emscripten.h>
#include <emscripten/bind.h>

using namespace emscripten;   
class MyClass {
  public:
    void sayHi () {
      printf("Hello! \n");
    };
};
EMSCRIPTEN_BINDINGS(MyClass)
{
    class_<MyClass>("MyClass")
      .function("sayHi", &MyClass::sayHi);
}

int main() {
  val window = val::global("window");
  auto myObj = MyClass();
  window.call<void>("sendRequest", myObj);
  return 0;
}

当我执行此代码时,它失败并显示错误:

Uncaught BindingError: Cannot pass deleted object as a pointer of type MyClass*

我使用emcc 1.35.22并使用以下命令编译它:

~/app/emsdk_portable/emscripten/tag-1.35.22/emcc main.cpp --bind -o out.js

1 个答案:

答案 0 :(得分:1)

出于某种原因,当你打电话

window.call<void>("sendRequest", myObj);

当堆栈从上面的行中清除时,Emscripten / embind删除myObj(如果你向MyClass添加一个析构函数,你可以看到这个。)

第二个问题是,即使Emscripten / embind没有这样做,当你这样做时

auto myObj = MyClass();
main

,在堆栈上创建了myObj,因此它将在异步回调之前的main末尾被删除。

解决这两个问题的方法是在堆上创建对象,将其作为原始指针传递给Javascript,以及指向静态回调的函数指针。您可以使用EM_ASM_ARGS从C ++调用,然后使用dynCall_*函数从Javascript中调用函数指针。

例如,C ++就像

void callback(MyClass *myObj)
{
  myObj->sayHi();
}

MyClass *myObj;

int main() {
  myObj = new MyClass();

  EM_ASM_ARGS({
    sendRequest($0, $1);
  }, &callback, myObj);

  // myObj is still in memory
  // be sure to delete it
  return 0;
}

和Javascript

Module = {
  noExitRuntime: true
};

function sendRequest(callback, myObj) {   
  setTimeout(function() {
    Module.dynCall_vi(callback, myObj);
  }, 1000);
}