2012-07-08 19 views
25

Pracuję z wersją C++ i v8 i napotkam następujące wyzwanie: Chcę móc zdefiniować funkcję w javascript za pomocą v8, a następnie wywołać tę funkcję później C++. Dodatkowo, chcę móc przekazać argument funkcji javascript z C++. Myślę, że poniższy przykładowy kod źródłowy najlepiej by to wyjaśnił. Sprawdź pod koniec przykładowego kodu, aby zobaczyć, co próbuję osiągnąć.Wywołanie funkcji v5 javascript z C++ z argumentem

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

} 

Jakieś wskazówki?

UPDATE:

Na podstawie porad udzielanych, udało mi się umieścić razem następujący kod. Urządzenie zostało przetestowane i działa:

#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

Zakładam, że IsInt32 zwraca wartość true, ale Int32Value zwraca 0? –

+0

Sprawdź moją edycję - może nie przepuszczamy wystarczającej liczby parametrów ... –

+0

Masz błąd w kodzie: pozbędziesz się bieżącego kontekstu i po jego użyciu. Musisz umieścić linię utylizacji na końcu programu. – banuj

Odpowiedz

13

Nie testowałem tego, ale jest możliwe, że coś takiego będzie działać:

// ...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 
    } 
} 

EDIT:

It wygląda na to, że twoja funkcja javascript oczekuje pojedynczego argumentu (składającego się z tablicy dwóch wartości), ale wygląda na to, że wywołujemy func w dwóch argumentach.

Aby przetestować tę hipotezę, można zmienić funkcji javascript, aby wziąć dwa argumenty i je porównać, np:

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

Wydaje się działać. Mam jednak problem z użyciem polecenia js_result. Część, w której jest napisane, czy (js_result.IsInt32) podaje następujący błąd podczas kompilacji: error: 'class v8 :: Handle ' nie ma członka o nazwie 'Int32' | – user396404

+1

@ user396404: może spróbuj zamiast tego użyć 'js_result-> IsInt32()'? –

+0

To zadziałało. Kod kompiluje, ale nie zwraca wartości 1, nawet jeśli wartości są zgodne:/ – user396404

2

Inną prostsze metody jest następujący:

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

Zasadniczo kompilacji kodu która zwraca anonimową funkcję, a następnie wywołaj ją za pomocą dowolnych argumentów, które chcesz przekazać.

+0

v8 :: ScriptCompiler :: CompileFunctionInContext wykonuje dla ciebie "wrap your code in a function" bit. – xaxxon

Powiązane problemy