程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 重溫delphi之如何快速開發原生ActiveX控件

重溫delphi之如何快速開發原生ActiveX控件

編輯:Delphi

 ActiveX技術雖然是一項古老的技術,但是卻有著廣泛的應用,支付寶的密碼輸入控件,各大銀行的密碼輸入控件,網頁聊天室中的截屏功能,網頁播放器中的p2p播放...甚至Flash,Silverlight等等,在IE中都表現為ActiveX。雖然c#也能開發"用於網頁的com應用",能達到類似ActiveX的效果,但是有一個要命的問題是必須得安裝幾百M的.Net framework框架,如果僅僅為了安全的輸入一個密碼,而要用戶下載幾百M的安裝程序,這是很多人不能接受的,delphi做為win32下的原生開發工具,能很好的支持微軟各種"古老"的經典技術。(再做點小廣告:Delphi的kyrix版本還能編譯跨平台的應用哦!) 

  ok,開工吧:

  開發工具:推薦用Delphi 2010(d7也可以,不過添加屬性,方法等過程要手動,稍微麻煩點) 

  1.啟用Delphi2010-->File->New->Other-->Active Library

重溫delphi之如何快速開發原生ActiveX控件

  查看原圖(大圖)

  2.項目命名為MyActiveX

重溫delphi之如何快速開發原生ActiveX控件

  查看原圖(大圖)

  3.File-->Save All 全部保存

 實際上這樣就能編譯了,不過只是空的dll

  4.File-->New-->Other-->Active Form

重溫delphi之如何快速開發原生ActiveX控件

  查看原圖(大圖)

  改名為MyForm

重溫delphi之如何快速開發原生ActiveX控件

  將對應的單元文件,保存為UMyForm.pas

  5.打開MyAcitveX.ridl文件,切換到design視圖,選中IMyForm接口,右擊New-->Property 添加一個屬性Msg

重溫delphi之如何快速開發原生ActiveX控件

  查看原圖(大圖)

  將Msg屬性的Type改為BSTR 即WideString類型

重溫delphi之如何快速開發原生ActiveX控件

  查看原圖(大圖)

  完了之後,點擊工具欄中的Refresh Implementation(即上圖中工具欄中圈起來的部分)--這一步很重要,點擊之後,它將自動生成屬性Msg對應的聲明和實現代碼模板


6.打開UMyForm.pas--即ActiveForm對應的單元,找到Set_Msg以及Get_Msg的實現部分,補充代碼如下:

function TMyForm.Get_Msg: WideString;
begin
    result:=_msg;
end;
procedure TMyForm.Set_Msg(const Value: WideString);
begin
  _msg := value;
end;

  當然TMyForm的private部分,得先加一個私有成員 

type
  TMyForm = class(TActiveForm, IMyForm)
  private
    { Private declarations }
    _msg:WideString;
...

  這樣我們就為即將生成的ActiveX控件,添加了一個字符串類型的屬性Msg,下面來測試一下:

  7.編譯項目,會生成一個MyActiveX.ocx,在運行欄裡輸入

  regsvr32 C:\Users\jimmy.yang\Desktop\Delphi_activex\MyActiveX\MyActiveX.ocx

  注:這裡ocx的路徑,請各位根據自己的實際路徑修改

  這樣就完成了ocx的注冊。

  8.放到Html裡測試一下:

<OBJECT ID='x' name='x' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<script type='text/Javascript'>
var x = document.getElementById("x");
alert(x.Msg);
</script>

  關於CLSID在哪裡查看,打開:MyActiveX_TLB.pas文件,定位到下面這裡:

const
  // TypeLibrary Major and minor versions
  MyActiveXMajorVersion = 1;
  MyActiveXMinorVersion = 0;
  LIBID_MyActiveX: TGUID = '{49138437-8265-4B1A-9EAE-D0F615D68464}';
  IID_IMyForm: TGUID = '{54A20855-29A3-4C92-85DE-A419DA457C7A}';
  DIID_IMyFormEvents: TGUID = '{60BBC967-E1E6-4E98-BAE5-776BFD06E9CC}';
  CLASS_MyForm: TGUID = '{52D17094-0687-4A2F-B2DB-30F3189AC659}';

其中 CLASS_MyForm: TGUID對應的就是ClassID

  運行後,除了彈出一個空白的警告框,暫時看不到其它:)(可不就是這樣麼?Msg屬性沒給任何初始值,當然是空字符串,所以彈出一個空的警告框是正常的)

  9.我們再來添加一些控件和方法,以驗證剛才設置的屬性確實有效

  在MyForm上添加一個文件框,一個按鈕

重溫delphi之如何快速開發原生ActiveX控件 

  按鈕的事件如下:

procedure TMyForm.Button1Click(Sender: TObject);
begin
  _msg:= self.Edit1.Text;
end;

  即把文本框的值賦給屬性Msg

  再繼續定位到Set_Msg,略做修改

procedure TMyForm.Set_Msg(const Value: WideString);
begin
  _msg := value;
  self.Edit1.Text := _msg;
end;

  即設置Msg屬性時,同時也把值顯示在文本框裡,以便等會兒我們好測試在JS中給activeX屬性賦值的效果

  ok了,再來測試一下,編譯一下,如果通不過,請先運行

  regsvr32 C:\Users\jimmy.yang\Desktop\Delphi_activex\MyActiveX\MyActiveX.ocx /u

  將剛才注冊的ocx反注冊,同時關掉浏覽器,不然該ocx文件一直被占用,無法更新.

  修改一下Html的代碼:

<OBJECT ID='x' name='x' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<hr />
<input type='button' value='顯示Msg屬性的值' onclick='ShowMsg()'/>
<input type='button' value='設置Msg屬性的值' onclick='SetMsg()'/>
<script type='text/Javascript'>
var x = document.getElementById("x");
var ShowMsg = function(){
    alert(x.Msg);
}
var SetMsg = function(){
    x.Msg = 'JS傳過來的值';
}
</script>

 運行效果:

重溫delphi之如何快速開發原生ActiveX控件

  10.添加Method

  我們已經知道了如何給ActiveX添加對外公開的屬性,但是光有屬性顯然不夠,我們再添加一個Method,參考第5步中的截圖,選擇new-->Method,添加

  一個方法,命名為ShowMsg,Return參數項用默認值HRESULT,然後Parameters添加一個參數,如下圖:

重溫delphi之如何快速開發原生ActiveX控件

  查看原圖(大圖)

  同樣不要忘記了點擊工具欄中的更新按鈕,再打開UMyForm.pas,會發現自動添加了一個過程的定義:

  procedure ShowMsg(const p: WideString); safecall;

  轉到它的實現部分,寫幾行測試代碼:

procedure TMyForm.ShowMsg(const p: WideString);
begin
  showmessage('Msg屬性的值為:' + _msg + #13 + '傳入的參數為:' + p);
end;

  再編譯,Html代碼中添加一些代碼:

<OBJECT ID='x' name='x' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<hr />
<input type='button' value='顯示Msg屬性的值' onclick='ShowMsg()'/>
<input type='button' value='設置Msg屬性的值' onclick='SetMsg()'/>
<input type='button' value='調用ShowMsg方法' onclick='CallShowMsg()'/>
<script type='text/Javascript'>
var x = document.getElementById("x");
var ShowMsg = function(){
    alert(x.Msg);
}
var SetMsg = function(){
    x.Msg = 'JS傳過來的值';
}
var CallShowMsg = function(){
    x.ShowMsg('這是JS傳過來的參數');
}
</script>


 運行看下:

重溫delphi之如何快速開發原生ActiveX控件

  類似的,我們還可以為ActiveX添加帶返回值的function,而非過程procedure,但是比較郁悶的是,我試了半天,delphi中編譯正常後,但是在Javascript中就是無法取得返回值,估計是Delphi的變量類型與Javascript的變量類型不匹配引起的,哪位 Delphi高人如果知道原因,還請指點一二,在此先謝過.

  11.深入看下ActiveX中到底有哪些玩意兒?

  既然ActiveX能加載到網頁中,肯定也是dom樹的一份子了,想知道ActiveX到底提供了哪些其它屬性或方法嗎?以下的JS代碼可以測試出來:

<div id="info"></div>
<script type="text/Javascript">
var _info="";
for(var p in x){
    _info += p + ":" + x[p] + "<br/>";
}
document.getElementById("info").innerHtml = _info;
</script>

  當然如果你用IE8的JS調試功能,也能看到剛才定義的那些方法和屬性:

重溫delphi之如何快速開發原生ActiveX控件

  查看原圖(大圖)

  注意一下這裡還有其它很多屬性,比如Caption,所以你在js中用alert(x.Caption)也能彈出ActiveForm的標題,這是我們通過IE/JS從外部來看ActiveX的,其實也能換個角度從delphi內部看下activex的結構,com技術號稱就是一組通用的接口規范,所以我們在Delphi內部確實也能發現不少接口:

 MyActiveX.ridl中可以看到

library MyActiveX
{
  ...
  interface IMyForm;
  ...
...

  表明IMyForm就是一個接口,再定位到MyActiveX_TLB.pas可以發現:

type
...
  IMyForm = interface;
  ...
  MyForm = IMyForm;
IMyForm = interface(IDispatch)
   ...

  說明MyForm就是從IDispatch繼承下來的一個接口

  最後再到UMyForm.pas中可以看到

type
  TMyForm = class(TActiveForm, IMyForm)
    Edit1: TEdit;
...

  說明最終的運行窗口,就是繼承自TActiveForm並實現了IMyForm的一個類

  12.事件支持

  打開MyActiveX.ridl,查看IMyFormEvents部分,可以看到Delphi生成的ActiveX控件中已經預置了很多事件

dispinterface IMyFormEvents
  {
    propertIEs:
    methods:
    [id(0x000000C9)]
    void OnActivate(void);
    [id(0x000000CA)]
    void OnClick(void);
    [id(0x000000CB)]
    void OnCreate(void);
    [id(0x000000CC)]
    void OnDblClick(void);
    [id(0x000000CD)]
    void OnDestroy(void);
    [id(0x000000CE)]
    void OnDeactivate(void);
    [id(0x000000CF)]
    void OnKeyPress([in, out] short* Key);
    [id(0x000000D0)]
    void OnMouseEnter(void);
    [id(0x000000D1)]
    void OnMouseLeave(void);
    [id(0x000000D2)]
    void OnPaint(void);
  };

  我們可以用Javascript來響應這些事件,比如就拿我們最熟悉的OnClick事件,JS中要這麼處理:

<OBJECT ID='x' name='a' CLASSID='CLSID:52D17094-0687-4A2F-B2DB-30F3189AC659' align=center hspace=0 vspace=0 ></OBJECT>
<script type="text/Javascript" event="OnClick" for="a">
 alert('你點擊了ActiveX控件');
</script>

  運行後,鼠標在ActiveX的空白處點擊,會彈出一個警告框:"你點擊了ActiveX控件"

  13.其它問題

  前面提到了帶返回值的function不好弄,其實這個不是什麼大問題,完全可以迂回用procedure與屬性解決

  比如我們可以定義一個帶參數的procedure,js調用時傳入參數,然後在procedure內部,對參數進行處理後,將其賦值為 ActiveX的任何一個類型匹配的屬性,比如前面提到的Caption屬性,然後JS獲取Caption屬性,相當於就是ActiveX處理後的返回值了

  文章來源:http://www.cnblogs.com/yjmyzz/archive/2009/12/16/1625559.Html 

  本文示例源代碼或素材下載






  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved