1.建立ActiveXForm工程,添加对SHDocVw,MSHTML单元的引用;
2.在类中声明如下私有函数:
private
FWebBrowser: IWebBrowser2;
function FindIEWebBrowser: IWebBrowser2;
function FindIEWindow(ParentHandle, ChildHandle: HWND): Boolean;
function CallScript: Boolean;
end;
3.按Ctrl + Shift + C生成程序体代码,完善代码如下(关于获取组件所在IE窗口的IWebBrowser2接口,在我的另一篇文章里有详细介绍:http://blog.csdn.net/reonlyrun/archive/2006/12/15/1444635.aspx):
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;
//获取角本函数的指针,角本函数名为"CallScript"
tmpScriptName := 'CallScript';
OleCheck(tmpDocument2.Script.GetIDsOfNames(GUID_NULL, @tmpScriptName, 1, LOCALE_SYSTEM_DEFAULT, @tmpDispID));
//设置参数个数
tmpDispParams.cArgs := 2;
//设置参数值
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;
//调用脚本函数
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中对IActiveFormX添加一个新方法,后面会在JavaScript中调用该函数,函数体代码如下:
function TActiveFormX.CallActiveX(const Param1,
Param2: WideString): WideString;
begin
Result := Param1 + ' ' + Param2;
ShowMessage('ActiveX: ' + Result);
end;
5.在窗体上添加一个Button,命名为btnCallScript,完成其Onclick事件的响应代码:
procedure TActiveFormX.btnCallScriptClick(Sender: TObject);
begin
CallScript;
end;
6.发布该工程,修改网页文件内容如下:
<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.getElementById("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.发布网页和打包的程序,在IE中输入相应路径,正确执行界面如图,分别点击网页按钮和ActiveX组件窗体内的按钮可以观察交互情况。值得注意的
是,由ActiveX调用JavaScript时参数的传递顺序正好逆转过来(个人以为应该是C++编译器和Delphi编译器对参数的压栈顺序不同),
在开发项目时要注意该问题。