• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數據加載中……

            在C++中應用Google Chrome腳本引擎——V8

            原文地址:http://www.codeproject.com/KB/library/Using_V8_Javascript_VM.aspx

            clip_image001

            介紹

            誰不想知道虛擬機是怎樣工作的?不過,比起自己寫一個虛擬機,更好的辦法是使用大公司的產品。在這篇文章中,我將介紹如何在你的程序中使用V8——谷歌瀏覽器(Chrome)所使用的開源JavaScript引擎。

            背景

            這里的代碼使用V8作為嵌入庫來執行JavaScript代碼。要取得庫源碼和其它信息,可以瀏覽V8開發者頁面。想有效地應用V8,你需要了解C/C++JavaScript

            使用

            我們來看看演示中有哪些東西:

            ·                     如何使用V8API來執行JavaScript腳本。

            ·                     如何存取腳本中的整數和字符串。

            ·                     如何建立可被腳本調用的自定義函數。

            ·                     如何建立可被腳本調用的自定義類。

            首先,我們一起了解一下怎樣初始化V8。這是嵌入V8引擎的簡單例子:

            1.                #include <v8.h>

            2.                using namespace v8;

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

            4.                  // Create a stack-allocated handle scope.

            5.                  HandleScope handle_scope;

            6.                  // Create a new context.

            7.                  Handle<Context> context = Context::New();

            8.                  // Enter the created context for compiling and

            9.                  // running the hello world script.

            10.              Context::Scope context_scope(context);

            11.              // Create a string containing the JavaScript source code.

            12.              Handle<String> source = String::New("'Hello' + ', World!'");

            13.              // Compile the source code.

            14.              Handle<Script> script = Script::Compile(source);

            15.              // Run the script to get the result.

            16.              Handle<Value> result = script->Run();

            17.              // Convert the result to an ASCII string and print it.

            18.              String::AsciiValue ascii(result);

            19.              printf("%s ", *ascii);

            20.              return 0;

            21.            }

            好了,不過這還不能說明怎樣讓我們控制腳本中的變量和函數。

            全局模型(The Global Template

            首先,我們需要一個全局模型來掌控我們所做的修改:

            1.                v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();

            這里建立了一個新的全局模型來管理我們的上下文(context)和定制。在V8里,每個上下文是分開的,它們有自己的全局模型。一個上下文就是一個獨立的執行環境,相互之間沒有關聯,JavaScript運行于其中一個實例之中。

            自定義函數

            接下來,我們加入一個名為"plus"的自定義函數:

            1.                // plus function implementation - Add two numbers

            2.                v8::Handle<v8::Value> Plus(const v8::Arguments& args)

            3.                {

            4.                    unsigned int A = args[0]->Uint32Value();

            5.                    unsigned int B = args[1]->Uint32Value();

            6.                    return v8_uint32(A +  B);

            7.                }

            8.                //...

            9.                //associates plus on script to the Plus function

            10.            global->Set(v8::String::New("plus"), v8::FunctionTemplate::New(Plus));

            自定義函數必須以const v8::Arguments&作為參數并返回v8::Handle<v8::Value>。我們把這個函數加入到模型中,關聯名稱"plus"到回調Plus?,F在,在腳本中每次調用"plus",我們的Plus函數就會被調用。這個函數只是返回兩個參數的和。

            現在我們可以在JavaScript里使用這個自定義函數了:

            plus(120,44); 

            在腳本里也可以得到函數的返回值:

            x = plus(1,2);

            if( x == 3){

               // do something important here!

            }

            訪問器(Accessor)——存取腳本中的變量

            現在,我們可以建立函數了...不過如果我們可以在腳本外定義一些東西豈不是更酷?Let's do it! V8里有個東東稱為存取器(Accessor),使用它,我們可以關聯一個名稱到一對Get/Set函數上,V8會用它來存取腳本中的變量。

            1.                global->SetAccessor(v8::String::New("x"), XGetter, XSetter);

            這行代碼關聯名稱"x"XGetterXSetter函數。這樣在腳本中每次讀取到"x"變量時都會調用XGetter,每次更新"x"變量時會調用XSetter。下面是這兩個函數的代碼:

            1.                //the x variable!

            2.                int x;

            3.                //get the value of x variable inside javascript

            4.                static v8::Handle<v8::Value> XGetter( v8::Local<v8::String> name,

            5.                                  const v8::AccessorInfo& info) {

            6.                  return  v8::Number::New(x);

            7.                }

            8.                //set the value of x variable inside javascript

            9.                static void XSetter( v8::Local<v8::String> name,

            10.                   v8::Local<v8::Value> value, const v8::AccessorInfo& info) {

            11.              x = value->Int32Value();

            12.            }

            XGetter里我們把"x"轉換成V8喜歡的數值類型。XSetter里,我們把傳入的參數轉換成整數,Int32Value是基本類型轉換函數的一員,還有NumberValue對應double、BooleanValue對應bool,等。

            現在,我們可以為字符串做相同的操作:

            1.                //the username accessible on c++ and inside the script

            2.                char username[1024];

            3.                //get the value of username variable inside javascript

            4.                v8::Handle<v8::Value> userGetter(v8::Local<v8::String> name,

            5.                           const v8::AccessorInfo& info) {

            6.                    return v8::String::New((char*)&username,strlen((char*)&username));

            7.                }

            8.                //set the value of username variable inside javascript

            9.                void userSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value,

            10.                const v8::AccessorInfo& info) {

            11.                v8::Local<v8::String> s = value->ToString();

            12.                s->WriteAscii((char*)&username);

            13.            }

            對于字符串,有一點點不同,"userGetter"XGetter做的一樣,不過userSetter要先用ToString方法取得內部字符串,然后用WriteAscii函數把內容寫到我們指定的內存中。現在,加入存取器:

            1.                //create accessor for string username

            2.                global->SetAccessor(v8::String::New("user"),userGetter,userSetter);

            打印輸出

            "print"函數是另一個自定義函數,它通過"printf"輸出所有的參數內容。和之前的"plus"函數一樣,我們要在全局模型中注冊這個函數:

            1.                //associates print on script to the Print function

            2.                global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));

            實現"print"函數

            1.                // The callback that is invoked by v8 whenever the JavaScript 'print'

            2.                // function is called. Prints its arguments on stdout separated by

            3.                // spaces and ending with a newline.

            4.                v8::Handle<v8::Value> Print(const v8::Arguments& args) {

            5.                    bool first = true;

            6.                    for (int i = 0; i < args.Length(); i++)

            7.                    {

            8.                        v8::HandleScope handle_scope;

            9.                        if (first)

            10.                    {

            11.                        first = false;

            12.                    }

            13.                    else

            14.                    {

            15.                        printf(" ");

            16.                    }

            17.                    //convert the args[i] type to normal char* string

            18.                    v8::String::AsciiValue str(args[i]);

            19.                    printf("%s", *str);

            20.                }

            21.                printf(" ");

            22.                //returning Undefined is the same as returning void...

            23.                return v8::Undefined();

            24.            }

            這里,為每個參數都構建了v8::String::AsciiValue對象:數據的char*表示。通過它,我們就可以把所有類型都轉換成字符串并打印出來。

            JavaScript演示

            在演示程序里,我們有一個簡單的JavaScript腳本,調用了迄今為止我們建立的所有東西:

            print("begin script");

            print(script executed by  + user);

            if ( user == "John Doe"){

                print("\tuser name is invalid. Changing name to Chuck Norris");

                user = "Chuck Norris";

            }

            print("123 plus 27 = " + plus(123,27));

            x = plus(3456789,6543211);

            print("end script");

             

            存取C++對象

            clip_image002

            為我們的類準備環境

            如果用C++把一個類映射到JavaScript中去?放一個演示用的類上來先:

            1.                //Sample class mapped to v8

            2.                class Point

            3.                {

            4.                public:

            5.                    //constructor

            6.                    Point(int x, int y):x_(x),y_(y){}

            7.                 

            8.                    //internal class functions

            9.                    //just increment x_

            10.                void Function_A(){++x_;    }

            11.             

            12.                //increment x_ by the amount

            13.                void Function_B(int vlr){x_+=vlr;}

            14.             

            15.                //variables

            16.                int x_;

            17.            };

            為了把這個類完全嵌入腳本中,我們需要映射類成員函數和類成員變量。第一步是在我們的上下文中映射一個類模型(class template):

            1.                Handle<FunctionTemplate> point_templ = FunctionTemplate::New();

            2.                point_templ->SetClassName(String::New("Point"));

            我們建立了一個"函數"模型[FunctionTemplate],但這里應該把它看成類。

            然后,我們通過原型模型(Prototype Template)加入內建的類方法:

            1.                Handle<ObjectTemplate> point_proto = point_templ->PrototypeTemplate();

            2.                point_proto->Set("method_a", FunctionTemplate::New(PointMethod_A));

            3.                point_proto->Set("method_b", FunctionTemplate::New(PointMethod_B));

            接下來,類有了兩個方法和對應的回調。但它們目前只在原型中,沒有類實例訪問器我們還不能使用它們。

            1.                Handle<ObjectTemplate> point_inst = point_templ->InstanceTemplate();

            2.                point_inst->SetInternalFieldCount(1);

            SetInternalFieldCount函數為C++類建立一個空間(后面會用到)。

            現在,我們有了類實例,加入訪問器以訪問內部變量:

            1.                point_inst->SetAccessor(String::New("x"), GetPointX, SetPointX);

            接著,土壤準備好了,開始播種:

            1.                Point* p = new Point(0, 0);

            新對象建立好了,目前只能在C++中使用,要放到腳本里,我們還要下面的代碼:

            1.                Handle<Function> point_ctor = point_templ->GetFunction();

            2.                Local<Object> obj = point_ctor->NewInstance();

            3.                obj->SetInternalField(0, External::New(p));

            好了,GetFunction返回一個point構造器(JavaScript方面), 通過它,我們可以用NewInstance生成一個新的實例。然后,用Point對象指針設置我們的內部域(我們前面用SetInternalFieldCount建立的空間),JavaScript可以通過這個指針存取對象。

            還少了一步,我們只有類模型和實例,但還缺一個名字來存取它:

            1.                context->Global()->Set(String::New("point"), obj);

            JavaScript里訪問類方法

            最后,我們還要解釋一下怎樣在Point類中訪問Function_A...

            讓我們看看PointMethod_A回調:

            1.                Handle<Value> PointMethod_A(const Arguments& args)

            2.                {

            3.                    Local<Object> self = args.Holder();

            4.                    Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));

            5.                    void* ptr = wrap->Value();

            6.                    static_cast<Point*>(ptr)->Function_A();

            7.                    return Integer::New(static_cast<Point*>(ptr)->x_);

            8.                }

            和普通訪問器一樣,我們必須處理參數。要訪問我們的類,必須從內部域(第一個)中取得類指針。把內部域映射到"wrap"之后,我們使用它的"value"方法取得類指針。

            其它

            希望這篇文章對你有所幫助,如果發現文章有誤,請不吝賜教。

            Google的V8參考文檔

            許可

            This article, along with any associated source code and files, is licensed under A Public Domain dedication

            關于作者

            GabrielWF

            posted on 2010-05-17 12:25 肥仔 閱讀(6657) 評論(1)  編輯 收藏 引用 所屬分類: 腳本語言

            評論

            # re: 在C++中應用Google Chrome腳本引擎&mdash;&mdash;V8  回復  更多評論   

            怎樣輸出中文?
            2010-11-10 17:06 | tttt
            久久综合给久久狠狠97色| 亚洲国产精品综合久久网络| 日韩久久久久久中文人妻 | 91久久国产视频| 午夜天堂av天堂久久久| 日本久久中文字幕| 久久精品国产99久久丝袜| 大香网伊人久久综合网2020| 狠狠色婷婷综合天天久久丁香| 久久亚洲日韩精品一区二区三区| 国产香蕉久久精品综合网| 久久久久一级精品亚洲国产成人综合AV区| AAA级久久久精品无码片| 99久久精品日本一区二区免费 | 久久发布国产伦子伦精品| 久久亚洲国产成人精品性色| 亚洲va中文字幕无码久久不卡| 2021最新久久久视精品爱| 久久精品国产亚洲av麻豆色欲| 久久精品国产久精国产思思| 久久99精品久久久久子伦| 丰满少妇人妻久久久久久| 国产精品久久成人影院| 日本精品久久久久中文字幕| 久久成人永久免费播放| 三级韩国一区久久二区综合| 区久久AAA片69亚洲| 久久婷婷五月综合97色| 91久久福利国产成人精品| 亚洲七七久久精品中文国产| 一本一本久久A久久综合精品| 亚洲AV无码久久精品色欲| 狠狠色丁香久久婷婷综| 久久伊人影视| 久久天天躁狠狠躁夜夜96流白浆 | 一本色道久久综合狠狠躁| 久久精品国产第一区二区三区| 国产成人精品久久一区二区三区| 久久高清一级毛片| 色欲综合久久中文字幕网| 国产精品综合久久第一页|