利用Delphi的ActiveForm,可以很方便地開發(fā)出可以嵌入IE的ActiveX組件,無需知道太多幕后的COM知識(shí)。如何使得OCX可以很方便地調(diào)用Web上的JavaScript函數(shù)呢,研究了一個(gè)下午,使用ActvieForm的Events接口搞定。說穿了不值錢,只要一句代碼就搞定,但是Google半天,琢磨了N久,看來還是基本功不扎實(shí)。
首先在ActiveForm的項(xiàng)目中找到ridl文件,打開它,選擇ActiveForm的Events接口,點(diǎn)擊右鍵,建立一個(gè)新的方法,方法名為我需要調(diào)用javascript的函數(shù)名。這里我要調(diào)用一個(gè)JS的上傳圖片腳本,所以將其命名為“OnUploadPic”。得到這個(gè)事件的ID,這里是209。
來到xxx_TLB.pas文件中(xxx為你的項(xiàng)目名),在ActiveForm中Events接口中將這個(gè)OnUploadPic方法的聲明加進(jìn)去。
1
|
procedure OnUploadPic; dispid 209;
|
然后HTML頁面中建立這個(gè)事件函數(shù),注意event字段寫入事件名,for字段寫入你給OCX取的名字,也就<object>把OCX包進(jìn)去的時(shí)候取的name值:
1
2
3
|
<script language="javascript" event="OnUploadPic" for="OcxName">
alert("hello Delphi!");
</script>
|
然后在Delphi中需要調(diào)用這個(gè)函數(shù)的地方,加入代碼:
1
|
if FEvents <> nil then FEvents.OnUploadPic;
|
搞定。
深層挖掘:
==========================================================================
ActiveX組件與JavaScript交互
1.建立ActiveXForm工程,添加對(duì)SHDocVw,MSHTML單元的引用;
2.在類中聲明如下私有函數(shù):
private
FWebBrowser: IWebBrowser2;
function FindIEWebBrowser: IWebBrowser2;
function FindIEWindow(ParentHandle,
ChildHandle: HWND): Boolean;
function CallScript: Boolean;
end;
3.按Ctrl + Shift +
C生成程序體代碼,完善代碼如下:
function
TActiveFormX.FindIEWebBrowser: IWebBrowser2;
var
tmpShell: IShellWindows;
tmpIntf: IDispatch;
tmpIE: IWebBrowser2;
i, Count: Integer;
begin
try
if FWebBrowser = nil then
begin
Count := 0;
repeat
tmpSHell :=
CoShellWindows.Create;
for i := 0 to
tmpShell.Count - 1 do
begin
tmpIntf
:= tmpShell.Item(i);
if
tmpIntf = nil then continue;
tmpIntf.QueryInterface(IID_IWebBrowser2,
tmpIE);
if
tmpIE = nil then Continue;
if
(Integer(Handle) = tmpIE.HWND) or FindIEWindow(Integer(tmpIE.HWND),
Handle) then
FWebBrowser
:= tmpIE;
end;
Inc(Count);
Sleep(50);
Application.ProcessMessages;
until (FWebBrowser
<> nil) or (Count >
50);
end;
Result := FWebBrowser;
except
end;
end;
function
TActiveFormX.FindIEWindow(ParentHandle,
ChildHandle: HWND): Boolean;
var
tmpHandle : HWND;
begin
tmpHandle := GetParent(ChildHandle);
if tmpHandle = 0 then
begin
Result := False;
Exit;
end else
begin
if tmpHandle = ParentHandle then
begin
Result := True;
Exit;
end else
begin
Result :=
FindIEWindow(ParentHandle, tmpHandle);
end;
end;
end;
function
TActiveFormX.CallScript: Boolean;
var
tmpDocument2: IHTMLDocument2;
tmpDispID: Integer;
tmpScriptName: WideString;
tmpDispParams: TDispParams;
tmpResult: Variant;
tmpParam1Value, tmpParam2Value: WideString;
tmpExcepInfo: TExcepInfo;
begin
try
tmpDocument2 := FindIEWebBrowser.Document as
IHTMLDocument2;
//獲取角本函數(shù)的指針,角本函數(shù)名為"CallScript"
tmpScriptName := 'CallScript';
OleCheck(tmpDocument2.Script.GetIDsOfNames(GUID_NULL,
@tmpScriptName, 1, LOCALE_SYSTEM_DEFAULT, @tmpDispID));
//設(shè)置參數(shù)個(gè)數(shù)
tmpDispParams.cArgs := 2;
//設(shè)置參數(shù)值
New(tmpDispParams.rgvarg);
tmpParam1Value := 'Hello';
tmpDispParams.rgvarg[0].bstrVal :=
PWideChar(tmpParam1Value);
tmpDispParams.rgvarg[0].vt := VT_BSTR;
tmpParam2Value := 'World';
tmpDispParams.rgvarg[1].bstrVal :=
PWideChar(tmpParam2Value);
tmpDispParams.rgvarg[1].vt := VT_BSTR;
tmpDispParams.cNamedArgs := 0;
//調(diào)用腳本函數(shù)
OleCheck(tmpDocument2.Script.Invoke(tmpDispID,
GUID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, tmpDispParams,
@tmpResult, @tmpExcepInfo, nil));
ShowMessage(tmpResult);
Result := true;
except
Result := false;
end;
end;
4.在Type
Library中對(duì)IActiveFormX添加一個(gè)新方法,后面會(huì)在JavaScript中調(diào)用該函數(shù),函數(shù)體代碼如下:
function
TActiveFormX.CallActiveX(const Param1,
Param2: WideString): WideString;
begin
Result := Param1 + ' ' + Param2;
ShowMessage('ActiveX: ' +
Result);
end;
5.在窗體上添加一個(gè)Button,命名為btnCallScript,完成其Onclick事件的響應(yīng)代碼:
procedure
TActiveFormX.btnCallScriptClick(Sender: TObject);
begin
CallScript;
end;
6.發(fā)布該工程,修改網(wǎng)頁文件內(nèi)容如下:
<HTML>
<H1> Delphi
6 ActiveX Test Page
</H1><p>
You should see your Delphi
6 forms or controls embedded
in the form
below.
<HR><center><P>
<script language="javascript">
function CallScript(Param1,
Param2)
{
tmpMsg
= Param1
+ "
"
+
Param2;
alert("JavaScript:
" +
tmpMsg);
return
"ActiveX:
" +
tmpMsg;
}
function
CallActiveX(Param1,
Param2)
{
tmpMsg
= document.getElementByIdx_x_xx("ActiveX1").CallActiveX(Param1,
Param2);
alert("JavaScript:"
+
tmpMsg);
}
</script>
<input id="input1" value="CallActiveX" type="button" onclick="CallActiveX('Hello',
'World')">
<br>
<OBJECT id="ActiveX1"
classid="clsid:3CA0A261-4183-4630-A280-6F616196514D"
codebase="ActiveFormProj1.cab#version=1,0,0,0"
width=690
height=450
align=center
hspace=0
vspace=0
>
</OBJECT>
</HTML>
7.發(fā)布網(wǎng)頁和打包的程序,在IE中輸入相應(yīng)路徑,正確執(zhí)行界面如圖,分別點(diǎn)擊網(wǎng)頁按鈕和ActiveX組件窗體內(nèi)的按鈕可以觀察交互情況。值得注意的是,由ActiveX調(diào)用JavaScript時(shí)參數(shù)的傳遞順序正好逆轉(zhuǎn)過來(個(gè)人以為應(yīng)該是C++編譯器和Delphi編譯器對(duì)參數(shù)的壓棧順序不同),在開發(fā)項(xiàng)目時(shí)要注意該問題。