20

Emscriptenを介してJavaScriptに変換されたC++コードがあります。変換されたC++コードを、それを呼び出すJavaScriptコードにコールバックしたいと思います。何かのようなもの:

JavaScript:

function callback(message) {
    alert(message);
}

ccall("my_c_function", ..., callback);

C ++:

void my_c_function(whatever_type_t *callback) {
    callback("Hello World!");
}

これはどういうわけか可能ですか?

4

5 に答える 5

16

受け入れられた答えは少し時代遅れだと思います。

「コードとの相互作用」emscriptenチュートリアルのこの箇条書きを参照してください。

例C:

void invoke_function_pointer(void(*f)(void)) {
  (*f)();
}

JS:

var pointer = Runtime.addFunction(function() { 
  console.log('I was called from C world!'); 
});
Module.ccall('invoke_function_pointer', 'number', ['number'], [pointer]);
Runtime.removeFunction(pointer);

このように、CコードはJSにトランスパイルされていることを認識する必要はなく、必要なブリッジはJSから純粋に制御できます。

(メッセージコンポーザーにハッキングされたコード。エラーが含まれている可能性があります)

于 2013-11-07T22:46:28.480 に答える
13

embindを介して、要件を達成するための新しい方法があります。

次のC++コードについて考えてみます。

#include <emscripten/bind.h>
using namespace emscripten;

void cbTest(emscripten::val cb)
{
    cb();
}

EMSCRIPTEN_BINDINGS(my_module) {
    function("cbTest", &cbTest);
}

cbTestC++関数はemscripten::valを取ります。これは、あらゆる種類のオブジェクトにすることができます。私たちにとって、これは関数オブジェクトです。これがJSからの呼び方です

var cbFunc = function() {
    console.log("Hi, this is a cb");
}

Module.cbTest(cbFunc);

PSこのAPIはまだ作成中です。

于 2016-08-07T11:56:15.270 に答える
10

Emscriptenで頻繁に行われることは、強い型を単純な型にマッピングすることです。

JS:

function callback(message) {
    alert(message);
}

var func_map = {
    0: callback
};

// C/C++ functions get a _ prefix added
function _invoke_callback(callback_id, text_ptr) {
    func_map[callback_id](Pointer_stringify(text_ptr));
}

ccall("my_c_function", ..., 0);

C ++:

// In C/C++ you only need to declare the func signature and
// make sure C is used to prevent name mangling
extern "C" void invoke_callback(int callback_id, const char* text);

void my_c_function(int callback_id) {
    invoke_callback( callback_id, "Hello World!" );
}

そしてもちろん、グルーコードを追加できるので、これは非常にシームレスになります。

于 2012-09-10T21:03:45.007 に答える
1

質問で説明されているものと非常によく似たものを書く必要がありました。私のコードは次のようになりました:

C:

void call(void (*back)(char*)){
    back("Hello!");
}

JS:

function back(text){
    alert(Pointer_stringify(text));
}
var pointer = Runtime.addFunction(back);
var call = Module.cwrap('call', 'void', ['pointer']);
call(pointer);
Runtime.removeFunction(pointer);

コールバックに返されるポインターは、Pointer_stringifyで逆参照する必要があることに注意してください。

このようなサンプルコードはGitHubにあります。

于 2014-09-11T10:13:06.317 に答える
1

これが私がいくつかの投稿から集めたものであり、Emscriptenのバンドルされたコードを見ることによって:

C ++の場合:

#include <iostream>
#include <functional>

extern "C" {
  void registerCallback(void(*back)(const char*));
  void triggerCallback(char* message); // for invoking it from JS, just for this example
}

// global
std::function<void(const char*)> gCallback;

void registerCallback(void(*back)(const char*)){
    gCallback = back;
}

void triggerCallback(char* message){
  if (gCallback) {
    gCallback(message);
  } else {
    std::cerr << "Cannot pass '"<< message <<"' to undefined callback\n";
  }
}

他の投稿にはなかった重要なことは、RESERVED_FUNCTION_POINTERS =...フラグを使用してC++をコンパイルすることです。例:

em++ -std=c++11 -s RESERVED_FUNCTION_POINTERS=20 source.cpp -s EXPORTED_FUNCTIONS="['_registerCallback','_triggerCallback']" -o try.html

try.htmlをブラウザにロードした後、コンソールで次のJSコードを実行できます。

// Register a callback function
function callback(text){ alert("In JS: "+Pointer_stringify(text)); }
var cb = Runtime.addFunction(callback);
_registerCallback(cb);

// Invoke it with some "C string"
var jsStr = "XOXOXO";
var cStr = allocate(intArrayFromString(jsStr), 'i8', ALLOC_NORMAL)
_triggerCallback(cStr);

// Free Emscripten heap and release the function pointer
_free(cStr);
Runtime.removeFunction(cb);

「InJS:XOXOXO」というアラートが表示されます。

于 2016-07-25T19:35:58.183 に答える