20

我有一段 C++ 代码通过 Emscripten 转换为 JavaScript。我希望转换后的 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);
}

cbTest C++ 函数接受一个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);

您应该会看到一条带有“In JS: XOXOXO”的警报。

于 2016-07-25T19:35:58.183 回答