我有一段通过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!");
}
这有可能吗?
答案 0 :(得分:15)
我认为接受的答案有点过时了。
请参阅this bullet point in the "Interacting with code" emscripten tutorial。
E.g。 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控制。
(代码入侵消息编写器;可能包含错误)
答案 1 :(得分: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!" );
}
当然,你可以添加一些胶水代码,这样就可以非常无缝。
答案 2 :(得分:4)
通过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);
P.S这个api仍在建设中。
答案 3 :(得分: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上找到这样的example code。
答案 4 :(得分:0)
以下是我从几个帖子中收集的内容以及查看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);
你应该看到一个警告&#34;在JS:XOXOXO&#34;。