2016-03-04 2 views
0

У меня есть небольшой вопрос о Emscripten. Как я могу вызвать обратный вызов C++ асинхронно с JavaScript?Вызов функции C++ из JavaScript асинхронно с использованием Emscripten

Это мой 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 
+0

ли работа, если код не является асинхронным? – Louis

+0

Да, если я вызываю callback ["sayHi"](); перед setTimeout он работает. – AndriiHeonia

ответ

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); 
} 
+0

Привет, Михал, Спасибо за ваш ответ! Но в реальном мире мое «sendRequest» не является глобальной функцией. Можно ли каким-либо образом вызвать метод объекта JS (метод emscripten :: val) внутри блока EM_ASM_ARGS? Что-то вроде [этого] (https://github.com/AndriiHeonia/async-emcc/blob/84cfd6d0d6368616953ea7903daf9870893214e4/main.cpp#L41)? – AndriiHeonia

+0

@AndriiHeonia Существует как минимум один способ вызова неглобальных функций JavaScript из C++. Я не уверен, применим ли это к вашему делу, поэтому мое подозрение состоит в том, что, вероятно, лучше разместить другой вопрос со спецификой, чем пытаться его сортировать в комментариях. –

+0

Я создал новый вопрос: http://stackoverflow.com/questions/35846606/call-method-of-the-emscriptenval-inside-em-asm-args-block И я был бы рад прочитать ваши идеи :) Спасибо авансовый. – AndriiHeonia

Смежные вопросы