2012-07-08 15 views
25

Ich arbeite mit C++ und V8, und bin in der folgenden Herausforderung gelaufen: Ich möchte eine Funktion in Javascript mit v8 definieren, dann rufen Sie die Funktion später durch C++. Außerdem möchte ich in der Lage sein, ein Argument an die JavaScript-Funktion von C++ zu übergeben. Ich denke, der folgende Beispielquellcode würde es am besten erklären. Überprüfen Sie gegen Ende des Beispielcodes, um zu sehen, was ich zu erreichen versuche.Eine v8 JavaScript-Funktion aus C++ mit einem Argument aufrufen

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

} 

Irgendwelche Tipps?

UPDATE:

Basierend auf den Rat gegeben, konnte ich zusammen den folgenden Code setzen. Es wurde getestet und funktioniert:

#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

Ich nehme an, dass IsInt32 true zurückgibt, aber Int32Value gibt 0 zurück? –

+0

Überprüfen Sie meine Bearbeitung - vielleicht sind wir nicht genug Parameter übergeben ... –

+0

Sie haben einen Fehler in Ihrem Code: Sie verfügen über den aktuellen Kontext und nachdem Sie es verwenden. Sie müssen die Entsorgungslinie am Ende Ihres Programms platzieren. – banuj

Antwort

13

ich nicht getestet haben, aber es ist möglich, dass so etwas wie dies funktionieren wird:

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

Es Es sieht so aus, als ob Ihre JavaScript-Funktion ein einzelnes Argument erwartet (bestehend aus einem Array von zwei Werten), aber es sieht so aus, als würden wir func aufrufen, indem wir es übergeben in zwei Argumenten.

Um diese Hypothese zu testen, können Sie Ihre Javascript-Funktion zwei Argumente zu nehmen und sie vergleichen, ändern könnte, zum Beispiel:

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

Es scheint zu funktionieren. Ich habe Probleme mit js_result obwohl. Der Teil, wo es heißt, wenn (js_result.IsInt32) gibt den folgenden Fehler während der Kompilierzeit: Fehler: 'Klasse v8 :: Handle ' hat kein Mitglied namens 'Int32' | – user396404

+1

@ user396404: vielleicht versuchen Sie 'js_result-> IsInt32()' stattdessen? –

+0

Das hat funktioniert. Der Code wird kompiliert, liefert aber keinen Wert 1, auch wenn die Werte übereinstimmen:/ – user396404

2

Eine weitere einfachere Methode ist wie folgt:

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

Im Wesentlichen einige Code kompilieren Diese Funktion gibt eine anonyme Funktion zurück und ruft sie dann mit den Argumenten auf, die Sie übergeben möchten.

+0

v8 :: ScriptCompiler :: CompileFunctionInContext macht das "wickeln Sie Ihren Code in einer Funktion" für Sie. – xaxxon

Verwandte Themen