2012-07-08 14 views
25

Estoy trabajando con C++ y v8, y me he encontrado con el siguiente desafío: quiero poder definir una función en javascript usando v8, luego llamar a la función más adelante C++. Además, quiero poder pasar un argumento a la función javascript desde C++. Creo que el siguiente código fuente de muestra lo explicaría mejor. Compruebe hacia el final del código de muestra para ver lo que estoy tratando de lograr.Llamar a una función v8 javascript desde C++ con un argumento

#include <v8.h> 
#include <iostream> 
#include <string> 
#include <array> 

using namespace v8; 

int main(int argc, char* argv[]) { 

    // Create a stack-allocated handle scope. 
    HandleScope handle_scope; 

    // Create a new context. 
    Persistent<Context> context = Context::New(); 
    Context::Scope context_scope(context); 
    Handle<String> source; 
    Handle<Script> script; 
    Handle<Value> result; 

    // Create a string containing the JavaScript source code. 
    source = String::New("function test_function(test_arg) { var match = 0;if(test_arg[0] == test_arg[1]) { match = 1; }"); 

    // Compile the source code. 
    script = Script::Compile(source); 

    // What I want to be able to do (this part isn't valid code.. 
    // it just represents what I would like to do. 
    // An array is defined in c++ called pass_arg, 
    // then passed to the javascript function test_function() as an argument 
    std::array< std::string, 2 > pass_arg = {"value1", "value2"}; 
    int result = script->callFunction("test_function", pass_arg); 

} 

¿Algún consejo?

ACTUALIZACIÓN:

Basado en el consejo dado, he sido capaz de armar el siguiente código. Se ha probado y funciona:

#include <v8.h> 
#include <iostream> 
#include <string> 

using namespace v8; 

int main(int argc, char* argv[]) { 

// Create a stack-allocated handle scope. 
HandleScope handle_scope; 

// Create a new context. 
Persistent<Context> context = Context::New(); 

//context->AllowCodeGenerationFromStrings(true); 

// Enter the created context for compiling and 
// running the hello world script. 
Context::Scope context_scope(context); 
Handle<String> source; 
Handle<Script> script; 
Handle<Value> result; 


// Create a string containing the JavaScript source code. 
source = String::New("function test_function() { var match = 0;if(arguments[0] == arguments[1]) { match = 1; } return match; }"); 

// Compile the source code. 
script = Script::Compile(source); 

// Run the script to get the result. 
result = script->Run(); 
// Dispose the persistent context. 
context.Dispose(); 

// Convert the result to an ASCII string and print it. 
//String::AsciiValue ascii(result); 
//printf("%s\n", *ascii); 

Handle<v8::Object> global = context->Global(); 
Handle<v8::Value> value = global->Get(String::New("test_function")); 
Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value); 
Handle<Value> args[2]; 
Handle<Value> js_result; 
int final_result; 

args[0] = v8::String::New("1"); 
args[1] = v8::String::New("1"); 

js_result = func->Call(global, 2, args); 
String::AsciiValue ascii(js_result); 

final_result = atoi(*ascii); 

if(final_result == 1) { 

    std::cout << "Matched\n"; 

} else { 

    std::cout << "NOT Matched\n"; 

} 

return 0; 

} 
+0

Supongo que IsInt32 devuelve cierto, pero Int32Value devuelve 0? –

+0

Eche un vistazo a mi edición - tal vez no estamos pasando suficientes parámetros ... –

+0

Tiene un error en el código: descarta el contexto actual y después de usarlo. Debe colocar la línea de eliminación al final de su programa. – banuj

Respuesta

13

no he probado esto, pero es posible que algo como esto funcionará:

// ...define and compile "test_function" 

Handle<v8::Object> global = context->Global(); 
Handle<v8::Value> value = global->Get(String::New("test_function")); 

if (value->IsFunction()) { 
    Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(value); 
    Handle<Value> args[2]; 
    args[0] = v8::String::New("value1"); 
    args[1] = v8::String::New("value2"); 

    Handle<Value> js_result = func->Call(global, 2, args); 

    if (js_result->IsInt32()) { 
     int32_t result = js_result->ToInt32().Value(); 
     // do something with the result 
    } 
} 

Editar:

se parece que su función javascript espera un único argumento (que consiste en una matriz de dos valores), pero parece que estamos llamando al func pasando en dos argumentos.

Para probar esta hipótesis, se podría cambiar su función javascript que tomar dos argumentos y compararlas, por ejemplo:

function test_function(test_arg1, test_arg2) { 
    var match = 0; 
    if (test_arg1 == test_arg2) { 
    match = 1; 
    } else { 
    match = 0; 
    } 
    return match; 
} 
+0

Parece estar funcionando. Sin embargo, tengo problemas para usar js_result. La parte donde dice si (js_result.IsInt32) está dando el siguiente error durante el tiempo de compilación: error: 'class v8 :: Handle ' no tiene ningún miembro llamado 'Int32' | – user396404

+1

@ user396404: tal vez intente 'js_result-> IsInt32()' en su lugar? –

+0

Eso funcionó. El código se compila, pero no devuelve un valor de 1, incluso si los valores coinciden:/ – user396404

2

Otro método más simple es el siguiente:

Handle<String> code = String::New(
    "(function(arg) {\n\ 
    console.log(arg);\n\ 
    })"); 
Handle<Value> result = Script::Compile(code)->Run(); 
Handle<Function> function = Handle<Function>::Cast(result); 

Local<Value> args[] = { String::New("testing!") }; 
func->Call(Context::GetCurrent()->Global(), 1, args); 

compilar Esencialmente algo de código que devuelve una función anónima, luego llámala con los argumentos que quieras aprobar.

+0

v8 :: ScriptCompiler :: CompileFunctionInContext hace que el bit "ajuste su código en una función" para usted. – xaxxon

Cuestiones relacionadas