2012-09-10 90 views
15

我有一段C++代码通过Emscripten转换为JavaScript。我希望转换后的C++代码能够回调调用它的JavaScript代码。喜欢的东西:将JS函数传递给Emscripten生成的代码

的JavaScript:

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

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

C++:

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

这可能不知?

回答

13

我相信接受的答案有点过时。请参阅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); 

这样的,它是transpiled到JS和所需的任何桥梁,可以纯粹地从JS控制的C代码并不需要知道。

(代码侵入消息作曲家,可能包含错误)

+0

一个重要的事情是,同时有效的函数指针的数量是固定的,并由'emcc ... -s RESERVED_FUNCTION_POINTERS = 20 ...'指定。' –

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!"); 
} 

和当然,你可以添加一些胶水代码,所以这会非常无缝的。

+3

+1为了避免C++名称的损坏。 – Eonil

+0

你能看看这个相关的问题:http://stackoverflow.com/questions/33673575/where-should-i-defined-emscripten-extern-functions-in-js?noredirect=1#comment55119884_33673575 –

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

+0

链接提供了接近没有附加信息。 –

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

一个重要的事情,这是在其他岗位缺失,是编译C++与RESERVED_FUNCTION_POINTERS = ...标志,如:

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

您应该看到“在JS的警告:XOXOXO ”。

2

有一种新方法可以通过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仍在建设中。