从JavaScript异步调用C ++函数使用Emscripten [英] Call C++ function from JavaScript asynchronously using Emscripten

查看:1650
本文介绍了从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>

使用命名空间emscripten;
class MyClass {
public:
void sayHi(){
printf(Hello!\\\
);
};
};
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;
}

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



未捕获的BindingError:无法将删除的对象作为MyClass类型的指针传递

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

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


解决方案

由于某种原因,当您调用

  window.call< void& (sendRequest,myObj); 

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



第二个问题是,即使Emscripten / embind didn' t做这个,当你做

  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仍在内存中
//一定要删除它
return 0;
}

和Javascript

  Module = {
noExitRuntime:true
};

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


I have a small question about Emscripten. How can I call C++ callback asynchronously from JavaScript?

This is my JS code:

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

This is my C++ code:

#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;
}

When I execute this code it fails with error:

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

I use emcc 1.35.22 and compile it with this command:

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

解决方案

For some reason, when you call

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

by the time the stack has cleared from the above line, Emscripten/embind deletes myObj (You can see this if you add a destructor to MyClass).

A secondary issue is that even if Emscripten/embind didn't do this, when you do

auto myObj = MyClass();

in main, myObj is created on the stack, and so it would be deleted at the end of main, which is before the asynchronous callback.

A way around both of these is to create the object on the heap, pass it to Javascript as a raw pointer, along with a function pointer to a static callback. You can use EM_ASM_ARGS to call out from C++, and then use a dynCall_* function to call from the function pointer from Javascript.

For example, the C++ would be like

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;
}

and the Javascript

Module = {
  noExitRuntime: true
};

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

这篇关于从JavaScript异步调用C ++函数使用Emscripten的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆