在發(fā)布使用ActiveX控件的應(yīng)用程序時(shí),應(yīng)該附帶使用到的ActiveX控件的OCX文件或DLL文件,并且在運(yùn)行應(yīng)用程序之前,必須先在系統(tǒng)注冊(cè)表中注冊(cè)ActiveX控件。注意:有些ActiveX控件會(huì)使用到其它的DLL文件,這時(shí)也要提供這些文件??梢酝ㄟ^RegSvr32.exe來注冊(cè)ActiveX控件,這個(gè)程序在Windows系統(tǒng)中可以找到。也可以使用Delphi開發(fā)環(huán)境目錄中的bin目錄中的TRegSvr.exe來注冊(cè)。另一種方法是將ActiveX控件的注冊(cè)代碼集成到應(yīng)用程序中,Delphi已提供了TRegSvr.exe的源代碼,并演示了如何注冊(cè)ActiveX控件。
ActiveX控件向?qū)?ActiveX Control Wizard)
這個(gè)向?qū)г试S把一個(gè)VCL控件轉(zhuǎn)換成一個(gè)ActiveX控件,能被轉(zhuǎn)換成ActiveX控件的VCL控件要滿足下面三個(gè)準(zhǔn)則:
. VCL控件必須在當(dāng)前安裝的設(shè)計(jì)包中(它必須在組件面板中)。
. VCL控件必須是TWinControl的派生類,當(dāng)前非窗口控件不能轉(zhuǎn)換為ActiveX控件。
. VCL控件必須是還沒有被RegisterNonActiveX()過程列出來的
許多標(biāo)準(zhǔn)的VCL控件無法轉(zhuǎn)換為ActiveX控件,是因?yàn)槠渲杏行┺D(zhuǎn)換成ActiveX控件沒有意義,或者是因?yàn)檗D(zhuǎn)
換需要大量的工作,超出了向?qū)芴峁┑墓δ堋?br>注意:雖然ActiveX向?qū)Р荒馨岩粋€(gè)非窗口的控件轉(zhuǎn)換成ActiveX控件,但能通過Delphi ActiveX(DAX)框架
來手工編寫這樣的控件。
ActiveX控件的選項(xiàng)(ActiveX Control Options):
. Make Control Licensed,選中這個(gè)選項(xiàng),一個(gè)許可證文件(LIC)就會(huì)產(chǎn)生,這是為了使其他開發(fā)者在不同
的開發(fā)環(huán)境能用這個(gè)Activex控件。
為了能使用這個(gè)控件除了ActiveX控件的ocx文件,還需要許可證文件。DAX需要把一個(gè)許可文件和ActiveX
控件的OCX文件一起發(fā)布到用戶的機(jī)器上。許可字符串是ActiveX控件類工廠構(gòu)造器的一個(gè)參數(shù)。若在向?qū)е?br>選中了Make Control Licensed,這個(gè)選項(xiàng)將生成一個(gè)GUID字符串,并把這個(gè)字符串插到類工廠構(gòu)造器的調(diào)
用中和LIC文件中。如果這個(gè)ActiveX控件要用在開發(fā)工具中,DAX就會(huì)把類工廠的許可字符串與LIC文件中許
可字符串進(jìn)行比較,如果匹配的話,才能創(chuàng)建這個(gè)控件的實(shí)例。當(dāng)編譯使用這個(gè)ActiveX控件的應(yīng)用程序時(shí),
許可字符串會(huì)嵌入到應(yīng)用程序中,但運(yùn)行這個(gè)應(yīng)用程序不再需要LIC文件。
. Include Version Information,選中這個(gè)選項(xiàng),一個(gè)VersionInfo資源將連到OCX文件中,在它的字符串
文件信息中有一個(gè)稱為OleSelfRegister的變量,它的值為1,這個(gè)變量是為了兼容老的ActiveX控件的宿主,
例如Visual Basic 4.0,在Project Options對(duì)話框的VersionInfo頁中能編輯這個(gè)變量。
. Include About Box,選中這個(gè)選項(xiàng)是為了把“About”對(duì)話框連到ActiveX控件中,在ActiveX容器應(yīng)用程
序中在ActiveX控件上單擊右鍵出現(xiàn)的菜單中能激活這個(gè)對(duì)話框,這個(gè)About對(duì)話框是一個(gè)普通的Delphi窗體。
下面簡(jiǎn)要描述ActiveX控件向?qū)О岩粋€(gè)VCL控件轉(zhuǎn)換成ActiveX控件要經(jīng)歷的步驟:
1) 向?qū)Q定是哪個(gè)單元包含了選中的VCL控件,然后經(jīng)編譯器處理,由編譯器生成與VCL控件的屬性、方法和事件相對(duì)應(yīng)的特殊符號(hào)信息。
2) 為這個(gè)項(xiàng)目創(chuàng)建一個(gè)類型庫,其中包括一個(gè)具有屬性和方法的接口、一個(gè)事件調(diào)度接口和一個(gè)表示ActiveX控件的控件類。
3) 向?qū)П闅vVCL控件的所有符號(hào)信息,把其中的屬性和方法加到接口中,把事件加到調(diào)度接口中。
注意:只有那些屬性、方法的參數(shù)和返回值、事件的類型與自動(dòng)化兼容的才能被加到類型庫中,與自動(dòng)化兼
容的數(shù)據(jù)類型有:Byte、SamllInt、Integer、Single、Double、Currency、TDataTime、WideString、
WordBool、PSafeArray、TDecimal、OleVariant、IUnknown和IDispatch。不過,這個(gè)規(guī)則也有例外,如果參
數(shù)的類型是TStrings、TPicture和TFont,也是允許的。對(duì)于這些類型,向?qū)в锰厥獾倪m配器對(duì)象將其封裝為
兼容的類型。這三個(gè)類型對(duì)應(yīng)的自動(dòng)化接口分別為:IStrings、IPicture和IFont。
4) 一旦所有的屬性、方法和事件加到類型庫中后,類型庫編輯器就產(chǎn)生一個(gè)包含類型庫內(nèi)容的Object Pascal譯本。
5) 向?qū)葾ctiveX控件的實(shí)現(xiàn)文件,這個(gè)文件中有一個(gè)TActiveXControl對(duì)象,它實(shí)現(xiàn)了在類型庫中描述的接口,并自動(dòng)實(shí)現(xiàn)原來在VCL中的屬性、方法和事件。
注意:在類型庫的單元文件中有一個(gè)類似于TMemoX的類這是從TOleControl繼承下來的,這樣就可以把這個(gè)
ActiveX控件加到組件面板中,只要把XXX_TLB單元加到設(shè)計(jì)期包中。
Delphi的ActiveX框架(簡(jiǎn)稱DAX)在單元AxCtrls中。一個(gè)ActiveX控件可以看成是一個(gè)自動(dòng)化對(duì)象,因?yàn)樗枰獙?shí)現(xiàn)IDispatch接口及其他接口。TActiveXControl是TAutoObject的派生類,它能實(shí)現(xiàn)一個(gè)ActiveX控件所需的接口。DAX框架是一個(gè)雙向的框架,在ActiveX中的TActiveXControl部分能和在VCL控件中的TWinControl進(jìn)行通信。就像所有的COM對(duì)象一樣,ActiveX控件由類工廠創(chuàng)建, DAX中的TActiveXControlFactory就是TActiveXControl對(duì)象的類工廠。而類工廠的實(shí)例是在控件實(shí)現(xiàn)單元的initialization部分創(chuàng)建的,這個(gè)類的構(gòu)造器聲明如下:
constructor TAcitveXControlFactory.Create(ComServer:TComServerObject;ActiveXControlClass:
TActiveXControlClass;WinControlClass:TWinControlClass;const ClassID:TGUID;ToolboxBitmapID:
Integer;const LicStr:String;MiscStatus:Integer; ThreadingModel:TThreadingModel=tmSingle);
ComServer用于指定一個(gè)TComServer的實(shí)例,它通常是ComServ單元中的全局變量ComServer。
ActiveXControlClass用于指定TActiveXControl的派生類的名字,它定義在實(shí)現(xiàn)文件中。
WinControlClass指定了VCL TWinControl派生類的名字,ActiveX控件就是從它轉(zhuǎn)換來的。
ClassID指定了ActiveX控件的類標(biāo)識(shí)符(CLSID),它被列在類型庫編輯器中。
ToolboxBitmapID指定了一個(gè)位圖的資源標(biāo)識(shí)符,這個(gè)位圖作為ActiveX控件在組件面板中的圖標(biāo)。
LicStr用于指定AtiveX控件的許可字符串,如果這個(gè)字符串設(shè)為空,表示不許可。
MiscStatus用于指定Activex控件的OLEMISC_XXX狀態(tài)標(biāo)志。這些標(biāo)志決定了一個(gè)ActiveX控件怎樣在窗口畫
出,是否能包含其他控件。關(guān)于這些標(biāo)志的含義,請(qǐng)查閱Microsoft Develpoer’s Network中OLEMISC主題。
ThreadingModel用于指定ActiveX控件的線程模式,特別要注意,這個(gè)參數(shù)僅用來對(duì)ActiveX控件指定一種線
程模式,但不能保證在這個(gè)線程模式下ActiveX控件就能安全工作,它只是決定了ActiveX控件是怎樣注冊(cè)的。
線程安全需要由程序員編程實(shí)現(xiàn)。
OLEMISC_XXX參數(shù)的其中一個(gè)值為OLEMISC_SIMPLEFRAME ,當(dāng)VCL控件的ControlStyle屬性中有
csAcceptsControls時(shí),這個(gè)值被自動(dòng)加到ActiveX控件中。這意味著,ActiveX控件就能成為其他ActiveX控
件的容器。在TActiveXControl類中有能使控件正確工作的消息處理結(jié)構(gòu),以處理子控件的消息。通常這個(gè)
值通過向?qū)ё詣?dòng)設(shè)定。如果不希望這樣,就應(yīng)當(dāng)在調(diào)用類工廠構(gòu)造器的代碼中把這個(gè)標(biāo)志手工地去掉。
某些ActiveX控件要有消息才能正確工作。因此,DAX將創(chuàng)建一個(gè)反射器窗口,它的任務(wù)是接收消息,并把它
們傳遞給VCL控件。凡是需要反射器窗口的VCL控件在ControlStryle屬性中有csReflector標(biāo)志。如果有一個(gè)
要處理通知消息的自定義的TWinControl控件,必須保證在控件構(gòu)造器的ControlStyle集合中有這個(gè)標(biāo)志值。
VCL提供一種簡(jiǎn)單的方法來判斷一個(gè)控件當(dāng)前是處在設(shè)計(jì)期還是在運(yùn)行期,只要檢查在ComponentState屬性中
是否有csDesigning標(biāo)志。雖然對(duì)ActiveX控件也能進(jìn)行類似的判斷,但它實(shí)現(xiàn)起來不那么簡(jiǎn)單,它需要獲得
容器的IAmbientDispatch調(diào)度接口的指針并檢查這個(gè)調(diào)度接口的UserMode屬性??梢杂孟铝写a來完成:
function IsControlRunning(Control:IUnknown):Boolean;
var
OleObj:IOleObject;
Site:IOleClientSite;
begin
Result:=true;
//得到控件的IOleObject指針,通過它得到容器的IOleClientSite,再得到IAmbientDispatch
if (Control.QueryInterface(IOleObject,OleObj)=S_OK) and
(OleObj.GetClientSite(Site)=S_OK) and (Site<>nil) then
Result:=(Site as IAmbientDispatch).UserMode;
end;
LIC文件并不是唯一的許可策略。例如,有些開發(fā)者認(rèn)為附加一個(gè)文件很麻煩,他們更愿意在注冊(cè)表中注冊(cè)
一個(gè)許可字符串。DAX用一種簡(jiǎn)單的方法來實(shí)現(xiàn)了這個(gè)目標(biāo),在TActiveXControlFactory中有一個(gè)方法叫
HasMachineLicense。默認(rèn)的情況下,這個(gè)方法在LIC文件中查找許可字符串,但可以讓這個(gè)方法在注冊(cè)表中
查找許可字符串。例如,下面代碼顯示了一個(gè)TActiveXControlFactory的派生類如何在注冊(cè)表中查找許可字
符串。
type
TRegLicActiveXControlFactory=class(TActiveXControlFactory)
protected
function HasMachineLicense:Boolean;override;
end;
function TRegLicActiveXControlFactory.HasMachineLicense:Boolean;
var Reg:TRegistry;
begin
Result:=true;
if not SupportsLicensing then Exit;
Reg:=TRegistry.Create;
try
Reg.RootKey:=HKEY_CLASSES_ROOT;
Result:=Reg.OpenKey('\Licenses\'+LicString,False);
finally
Reg.Free;
end;
end;
把許可字符串加到注冊(cè)表文件的REG文件:
REGEDIT4
[HKEY_CLASSES_ROOT\Licenses\{C06EFEA0-06B2-11D1-A9BF-B18A9F703311}]
@="Licensing info for DDG demo ActiveX control"
屬性頁提供了通過一個(gè)對(duì)話框修改ActiveX控件屬性的方法。在控件容器中,通過在控件上單擊右鍵并在產(chǎn)
生的菜單中選擇命令,就能打開一個(gè)控件的屬性頁。
1. 標(biāo)準(zhǔn)的屬性頁
DAX為類型IString、IPicture、TColor和IFont提供了標(biāo)準(zhǔn)的屬性頁。這些屬性頁的CLSID定義在AxCtrls
單元中。它們聲明如下:
const
Class_DColorPropPage:TGUID='{5CFF5D59-5946-11D0-BDEF-00A024D1875C}';
Class_DFontPropPage:TGUID='{5CFF5D5B-5946-11D0-BDEF-00A024D1875C}';
Class_DPicturePropPage:TGUID='{5CFF5D5A-5946-11D0-BDEF-00A024D1875C}';
Class_DStringPropPage:TGUID='{F42D677E-754B-11D0-BDFB-00A024D1875C}';
在ActiveX控件中使用上述任何一種屬性頁時(shí),僅需要把它們的CLSID傳遞到控件DefinePropertyPages()方
法中的DefinePropertyPage參數(shù)即可。示例如下:
procedure TMemoX.DefinePropertyPages(DefinePropertyPage:TDefinePropertyPage);
begin
DefinePropertyPage(Class_DColorPropPage);
DefinePropertyPage(Class_DFontPropPage);
DefinePropertyPage(Class_DStringPropPage);
end;
2、自定義的屬性頁
示例:先新建一個(gè)ActiveX Control,再新建一個(gè)Property Page,在Property Page上設(shè)計(jì)界面與代碼,
將屬性頁的默認(rèn)類型標(biāo)志符Class_PropertyPage1改名為其它喜歡的名字,再在ActiveX控件類的
DefinePropertyPages方法中加入以下代碼:
procedure TMemoX.DefinePropertyPages(DefinePropertyPage: TDefinePropertyPage);
begin
DefinePropertyPage(Class_DStringPropPage);//這個(gè)是標(biāo)準(zhǔn)的屬性頁的CLSID
DefinePropertyPage(Class_PropertyPage1);
end;
實(shí)現(xiàn)自定義屬性頁時(shí),用OleObject來與屬性頁中的ActiveX控件交互。OleObject是變體,它能引用
ActiveX控件的IDispatch接口,屬性頁的UpdatePropertyPage()方法和UpdateObject()方法由向?qū)Мa(chǎn)生。
在屬性頁激活時(shí)UpdatePropertyPage()被調(diào)用,這樣就有機(jī)會(huì)把ActiveX控件的屬性值顯示在屬性頁上。當(dāng)
用戶單擊屬性頁上的OK鍵或Apply按鈕時(shí)會(huì)調(diào)用UpdateObject()方法。這樣就有機(jī)會(huì)以用戶所做的修改來更
新Activex控件的屬性。屬性頁上的按鈕被按下時(shí)應(yīng)該調(diào)用屬性頁的Modified()方法,它能使Apply按鈕有效,
并臨時(shí)更新ActiveX控件的屬性。
ActiveForm:
從功能上講,ActiveForm非常像ActiveX控件,
ActiveForm在類型庫中的接口是“平面”的,而不是像VCL那樣是嵌套的。這表示如果一個(gè)ActiveForm上有
幾個(gè)按鈕,則無法用類似于ActiveForm.Button.ButtonProperty的方式來訪問ActiveForm上的按鈕(訪問者
是使用該ActiveForm的客戶端程序)。要解決這個(gè)問題的最簡(jiǎn)單的方法是把按鈕的屬性轉(zhuǎn)換為ActiveForm的
屬性。只要采取兩個(gè)步驟。這里假設(shè)要轉(zhuǎn)換按鈕的Caption屬性:
1) 在實(shí)現(xiàn)文件的ActiveForm聲明中增加一個(gè)公開的被稱為ButtonCaption的新屬性,它有讀、寫方法,來讀
寫按鈕的Caption屬性。
2) 在類型庫中中的ActiveForm接口中加入一個(gè)名字為ButtonCaption的新屬性。Delphi將為這個(gè)屬性自動(dòng)生
成讀、寫方法的程序框架。必須自己編寫代碼通過對(duì)ActiveForm的ButtonCaption屬性的讀、寫來完善程序。
ActiveForm最理想的用途是在WWW上作為傳送小型程序的載體。小小的ActiveX框架同樣能增加Web頁的功能和
外觀。因?yàn)锳ctiveX控件能運(yùn)行在Web瀏覽器上,如果它能調(diào)用Web瀏覽器的函數(shù)和接口,這非常有意義。Web
瀏覽器的函數(shù)和接口大部分在UrlMon單元中,其中最簡(jiǎn)單的是Hlinkxxx()函數(shù),它能讓瀏覽器跳轉(zhuǎn)到不同的
地方。例如,HlinkGoForward()和HlinkGoBack()函數(shù)可以使瀏覽器在歷史記錄中前后跳轉(zhuǎn)。
HlinkNavigateString()函數(shù)能使瀏覽器跳轉(zhuǎn)到一個(gè)特定URL,這些函數(shù)在UrlMon單元中是這樣聲明的:
function HlinkGoForward(pUnk:IUnknown):HResult;stdcall;
function HlinkGoBack(pUnk:IUnknown):HResult;stdcall;
function HlinkNavigateString(pUnk:IUnknown;szTarget:PWideChar):HResult;stdcall;
pUnk參數(shù)是ActiveX控件的IUnknown接口,對(duì)于ActiveX控件來說,可以傳遞Control as IUnknown給這個(gè)參
數(shù);對(duì)于ActiveForm來說,可以傳遞IUnknown(VclComObject)給這個(gè)參數(shù)。HlinkNavigateString()的
szTarget參數(shù)用于指定一個(gè)URL。調(diào)用URLDownloadToFile()函數(shù)可以從服務(wù)器下載一個(gè)文件,這個(gè)函數(shù)在
UrlMon中是這樣聲明的:
function URLDownloadToFile(p1:IUnknown;p2:PChar;p3:PChar;p4:DWORD;p5:
IBindStatusCallback):HResult;stdcall;
p1代表ActiveX控件的IUnknown接口,它類似于HlinkXXX()函數(shù)的pUnk參數(shù)。p2參數(shù)是要下載的文件的URL。
p3參數(shù)用于指定該文件下載到本地的路徑和名稱。p4參數(shù)必須設(shè)為0。p5參數(shù)用于指定一個(gè)可選的
IBindStatusCallback接口的指針。這個(gè)接口用于獲取文件在下載時(shí)的附加信息。
Delphi的IDE可以很方便地把ActiveX控件在Web站點(diǎn)上發(fā)布,要能實(shí)現(xiàn)這個(gè)功能,必須在編輯ActiveX控件
項(xiàng)目時(shí)選擇菜單項(xiàng)Project|Web Deployment Options。該對(duì)話框中的各個(gè)選項(xiàng)解釋如下:
1. Project頁
Target Dir框用于指定ActiveX控件要發(fā)布的目標(biāo)路徑。這里假設(shè)能把一個(gè)驅(qū)動(dòng)器映射到Web服務(wù)器上—
Target Dir框中必須輸入一個(gè)常規(guī)的或UNC路徑名,其中不應(yīng)當(dāng)有文件名。
Target URL框用于輸入Target Dir框所指定的路徑的URL。一個(gè)合法的URL必須以http://、file://、
ftp://等為前綴。這個(gè)框中也不要輸入文件名。
HTML Dir 框用于指定一個(gè)路徑,用于存試生成的HTML文檔。它通常跟Target Dir框中指定的路徑相同。
use CAB file compression,如果選中了這個(gè)選項(xiàng), OCX文件將以Microsoft Cabinet(CAB)格式壓縮。在
低帶寬的網(wǎng)絡(luò)上,建議選中這個(gè)選項(xiàng)。
Include file version number,這個(gè)選項(xiàng)決定生成的HTML文件或INF文件中是否要有版本號(hào)。推薦選中這
個(gè)選項(xiàng),它能避免用戶下載已經(jīng)下載過的控件。
Autoincrement release number,如果選中這個(gè)選項(xiàng),版本信息中的發(fā)布號(hào)將自動(dòng)增大。
Code sign project,如果有數(shù)字簽名的授權(quán)證書,可以讓IDE自動(dòng)給ActiveX項(xiàng)目加上數(shù)字簽名。
Deploy required packages,如果ActiveX項(xiàng)目使用了包,發(fā)布ActiveX項(xiàng)目時(shí)會(huì)自動(dòng)包括所需要的包。
Deploy additional files,如果還需要跟其他文件一起發(fā)布,就選中這個(gè)復(fù)選框。
2. Packages頁和Additional Files頁
如果在Project頁上選中了use CAB file compression復(fù)選框,在Packages頁和Additional Files頁上的
CAB Options框中就可以選擇把CAB文件與OCX一起壓縮還是單獨(dú)分別壓縮,一般都選擇分別壓縮到各自的
CAB中,這樣能使用戶避免每次都下載所有文件。如果選中Use File VersionInfo 復(fù)選框,發(fā)布引擎將決
定選中的文件是否有版本信息。如果有,在VersionInfo中的版本號(hào)將加到INF文件中。Target URL框缺省
地是Project頁中Target URL框中的內(nèi)容,即文件可以被下載的URL,如果ActiveX控件的用戶已經(jīng)安裝了這
個(gè)文件,就讓這個(gè)框空著。Target Directory編輯框用于指定文件被復(fù)制到服務(wù)器的哪個(gè)路徑中。如果文件
已經(jīng)在服務(wù)器中,就讓這個(gè)編輯框空著,以避免重復(fù)復(fù)制。
3. Code Signing頁
Code Signing頁可以用來指定授權(quán)文件和私人密鑰文件。另外還能指定ActiveX控件的名稱、公司的URL、
壓縮算法類型、是否對(duì)授權(quán)文件加蓋時(shí)間戳。推薦加蓋時(shí)間戳,這樣即使授權(quán)文件過期了,簽名仍然有效。
注意:如果在Project頁上的設(shè)置有錯(cuò)誤,控件在Web頁上出現(xiàn)的時(shí)候,在控件的左上角有一個(gè)紅色的X。出
現(xiàn)這種情況后,要在HTML文件和INF文件中尋找錯(cuò)誤,最通常的錯(cuò)誤是控件的URL不正確。