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
查看原圖(大圖)
2.項目命名為MyActiveX
查看原圖(大圖)
3.File-->Save All 全部保存
實際上這樣就能編譯了,不過只是空的dll
4.File-->New-->Other-->Active Form
查看原圖(大圖)
改名為MyForm
將對應的單元文件,保存為UMyForm.pas
5.打開MyAcitveX.ridl文件,切換到design視圖,選中IMyForm接口,右擊New-->Property 添加一個屬性Msg
查看原圖(大圖)
將Msg屬性的Type改為BSTR 即WideString類型
查看原圖(大圖)
完了之後,點擊工具欄中的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上添加一個文件框,一個按鈕
按鈕的事件如下:
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>
運行效果:
10.添加Method
我們已經知道了如何給ActiveX添加對外公開的屬性,但是光有屬性顯然不夠,我們再添加一個Method,參考第5步中的截圖,選擇new-->Method,添加
一個方法,命名為ShowMsg,Return參數項用默認值HRESULT,然後Parameters添加一個參數,如下圖:
查看原圖(大圖)
同樣不要忘記了點擊工具欄中的更新按鈕,再打開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>
運行看下:
類似的,我們還可以為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調試功能,也能看到剛才定義的那些方法和屬性:
查看原圖(大圖)
注意一下這裡還有其它很多屬性,比如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
本文示例源代碼或素材下載