Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4027912
  • 博文数量: 1099
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 13169
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1099)

文章存档

2019年(75)

2018年(81)

2017年(80)

2016年(70)

2015年(52)

2014年(41)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(288)

分类: WINDOWS

2010-07-18 17:07:56

利用Delphi的ActiveForm,可以很方便地开发出可以嵌入IE的ActiveX组件,无需知道太多幕后的COM知识。如何使得OCX可以很方便地调用Web上的JavaScript函数呢,研究了一个下午,使用ActvieForm的Events接口搞定。说穿了不值钱,只要一句代码就搞定,但是Google半天,琢磨了N久,看来还是基本功不扎实。

首先在ActiveForm的项目中找到ridl文件,打开它,选择ActiveForm的Events接口,点击右键,建立一个新的方法,方法名为我需要调用javascript的函数名。这里我要调用一个JS的上传图片脚本,所以将其命名为“OnUploadPic”。得到这个事件的ID,这里是209。

来到xxx_TLB.pas文件中(xxx为你的项目名),在ActiveForm中Events接口中将这个OnUploadPic方法的声明加进去。

1
  procedure OnUploadPic; dispid 209;

然后HTML页面中建立这个事件函数,注意event字段写入事件名,for字段写入你给OCX取的名字,也就把OCX包进去的时候取的name值:

1
2
3
  

然后在Delphi中需要调用这个函数的地方,加入代码:

1
  if FEvents <> nil then FEvents.OnUploadPic;

搞定。

 

深层挖掘:

==========================================================================

ActiveX组件与JavaScript交互

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生成程序体代码,完善代码如下:

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.发布该工程,修改网页文件内容如下:


 

 

<HTML>
<H1> Delphi ActiveX Test Page H1><p>
You should see your Delphi 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("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编译器对参数的压栈顺序不同),在开发项目时要注意该问题。

 

阅读(3201) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册