本文所指的 JavaScript 為 MS Script,引入msscript.ocx 實現的,也就是ECMAScript(下載本例原始碼)。從題目咋眼看來對於沒有寫過VC調用msscript.ocx的人來說不是很好理解,因為這樣做似乎太容易了,何來難題?
例如寫JavaScript實 現數值計算,例如: _variant_t outpar=pScriptControl->Eval(_bstr_t("1+4*5")); 這樣的數值計算不涉及js呼叫指令碼外部的對象,例子到處可見,但是應用範圍非常窄小。也就是說,從現有的文獻來看,用VC調用 JavaScript 都是 JavaScript 單向的,但是從來沒見過把VC中的現有的對象交給 JavaScript 反過來調用(也就是雙向調用)。有些人已經實現或者看到, JavaScript 可以通過 obj = new ActiveXObject(...);的方式,把用VC編寫COM,然後讓 JavaScript 建立調用,但是,這樣new出來的對象,仍然不是VC應用的現有對象。如果要調用現有對象,需要通過被new的COM對象間接調用才行,而且應用程式被調 用的對象也是COM規範。如果通過COM來實現這個難題,應用程式結構比較複雜,JavaScript 建立COM,所建立的COM能訪問應用程式物件。
所以要擴大 JavaScript 的應用範圍,必須實現這樣的核心問題:雙向調用。
雙向調用的一個分解問題是,VC對象如何進入指令碼呢?下面介紹一種實現方法。
一、介面:
二、主要代碼
1 聲明定義可以被JavaScript調用的類和對象
//聲明可以被JavaScript調用的類並建立一個轉接對象g_Dialogimpl
BEGIN_DSRE_POPULAR_OBJECT(CCppCallJavaScriptDlg)
DEFINE_POPULAR_METHOD(CCppCallJavaScriptDlg,Rectangle);
DEFINE_POPULAR_METHOD(CCppCallJavaScriptDlg,MoveTo);
DEFINE_POPULAR_METHOD(CCppCallJavaScriptDlg,LineTo);
DEFINE_POPULAR_METHOD(CCppCallJavaScriptDlg,TextOut);
END_DSRE_POPULAR_OBJECT()g_Dialogimpl;
//定義可以被JavaScript調用的函數,分別是Rectangle, MoveTo, LineTo, TextOut
DEFINE_DSRE_FUNCTION(CCppCallJavaScriptDlg,Rectangle)
{
int x,y,cx,cy;
x=(*args)[0]->AsInt();
y=(*args)[1]->AsInt();
cx=(*args)[2]->AsInt();
cy=(*args)[3]->AsInt();
::Rectangle(m_hDC,x,y,cx,cy);
}
DEFINE_DSRE_FUNCTION(CCppCallJavaScriptDlg,MoveTo)
{
int x,y;
x=(*args)[0]->AsInt();
y=(*args)[1]->AsInt();
::MoveToEx(m_hDC,x,y,NULL);
}
DEFINE_DSRE_FUNCTION(CCppCallJavaScriptDlg,LineTo)
{
int x,y;
x=(*args)[0]->AsInt();
y=(*args)[1]->AsInt();
::LineTo(m_hDC,x,y);
}
DEFINE_DSRE_FUNCTION(CCppCallJavaScriptDlg,TextOut)
{
int x,y;
x=(*args)[0]->AsInt();
y=(*args)[1]->AsInt();
wchar_t *text=(*args)[2]->AsString()->GetText();
::TextOutW(m_hDC,x,y,text,(*args)[2]->AsString()->GetLength());
}
2 向msscript.ocx添加代碼
code_w=L"function OnDialogPaint(dialog){dialog.Rectangle(20,20,220,220);dialog.MoveTo(270,20);dialog.LineTo(300,120);dialog.TextOut(280,150,\"Text from JavaScript\");}";
code=code_w.GetText();
JScriptWrapper->Invoke(NULL,L"AddCode",&code,&ret);
3 在VC的 OnPaint 事件調用 JavaScript
LWideString code_w=L"OnDialogPaint(theCppDialog);";
code=code_w.GetText();
JScriptWrapper->Invoke(NULL,L"Eval",&code,&ret);
這樣就完成了一下調用過程:
為真正的雙向調用。
後記:
如果有了雙向調用技術,不難想象Flash的ActionScript的實現方法,也不難想象Maxthon的Plug-in可以用MS Script來做。如果不能實現雙向,只能像WPS那樣,Script只能作為Add-on,而不是Plug-in(沒有貶低WPS之意)。