以Delphi開發ActiveX元件

---摘自:http://www.bravos.com.tw/big5/tutor/profession/componentvcl2activex/

1.前言: ActiveX vs Java

 

未來我們朝向以Windows作業平台為主的Web Application系統開發時,Delphi將會被定位為軟體元件開發工具以提供ActiveXASP使用。本文詳述如何將VCL 模組轉換成 ActiveX 元件,對於ASPVB程式開發期間若遇到強悍(tough)的功能需求時,保證各位不會捉襟見肘的。Code Reusing à Programmer生涯海闊天空。

 

以下敘述為擁ActiveX的論點,不代表本臺立場。

ActiveX offers several benefits not available to Java, its primary competition:

l

It's cached. OCX files brought down from the Web are brought once, assuming cache-time and disk allotment aren't exceeded. Java code must be downloaded and run with each hit to a Java-enabled site.

l

It's fast. ActiveX files are compiled code, and run natively as extensions to the clients' browsers. Java, to date, is interpreted (there are some exceptions for JIT compilers and the JBuilder native compiler), and takes between five and 20 times the amount of time to provide identical functionality if achievable.

l

It can be 100 percent Delphi. One of the things I dislike about Java is that - it's Java. I took up Delphi specifically because I didn't want to learn C. Perhaps I'm lazy, but I am reticent to give up the skills it's taken me a few years to develop. JBuilder is a great product, and I do see a future in Java, but I don't want to learn the syntax. Installed development shops that have a lot invested in Delphi will find the ActiveX route a potential gold mine in resource usage.

 

It also shares some benefits with Java:

l

It's instantly updated. As soon as a new OCX file is delivered to the Web site, new hits draw an updated version of the application.

l

It's thin. That's right, thin. Although even a small ActiveX application deploys at around a half a megabyte (the sample application in this article deploys at 1078KB), when deployed with run-time packages, that total can shrink to something really puny (the sample mentioned deploys to 337KB under run-time packages). There's an additional benefit in using CAB file compression (more on this later).

l

It can be N-Tier. In fact, I recommend this highly. Because the user has a network connection already (otherwise he or she would not be able to tag your Web site), there isn't anything that should prevent your application from being aware of a middle-tier server. Using TClientDataSet in your ActiveX application provides two benefits: It maintains the "Ivory Tower" of data control, and further "thins" the application by not requiring a BDE installation or configuration (all this is maintained at the middle tier). If the only requirements are the OCX, some run-time packages, and a copy of Dbclient.dll, your client should be getting downright skinny.


 

2.Delphi提供的VCL元件轉換成ActiveX元件功能

 

l

VCL元件轉換成ActiveX元件-操作說明

 

Step 1.

File è New,選取ActiveX TabSheet點選ActiveX Control



 


Step 2.

VCL Class Name Combo Box選取一個已installedDelphi中的元件(eg. TBvIdleCheck),給予一個新的

 

 

New ActiveX Name

(eg. BvIdleCheckX),

 

 

implementation unit

(eg. BvIdleCheckImpl1.pas)

 

 

Project Name

(eg. BvIdleCheckAx.dpr)



 

 


OK

 

 

此時Delphi build會依據VCL元件程式碼內容產生對應的typed library程式碼BvIdleCheckAx_TLB.pas)

 

Step 3.

Build Project

 

 

此時Delphi build產生BvIdleCheckAx.OCX元件

 


 

 

l

VCL元件轉換成ActiveX元件-機制說明

 

Suppose your orignal VCL compoent named TFoo, Delphi Convert to ActiveX component named TFooX.

TFooX inherited from the following two classes (TActiveXControl and IFooX):

 


TFooX = class(TActiveXControl, IFooX)

新產生的ActiveX元件包含以下幾個重要函數:

 

ActiveX methods

Description

DefinePropertyPages

透過DefinePropertyPage()於此函數中定義客製化元件屬性頁內容(property page).

eg. DefinePropertyPage(Class_FooXPage);

EventSinkChanged

於此函數中放置設定ActiveX元件支援的EventSink程式碼.

InitializeControl

ActiveX元件初始化時回呼此函數

InitiateAction

客製化ActiveX元件相關的Action Link更新動作(類似MFC中的UpdateCommandUI功能)

Application OnIdle時此函數會被回呼

 

 


 

3.能夠被轉換成ActiveX元件之VCL元件必須符合之條件

 

能夠被轉換成ActiveX元件之VCL元件必須符合以下條件

l

The VCL control must be installed in Delphi. If the component isn't installed in the Component palette, it's not registered with Delphi
只有被Delphi註冊安裝到Component Palette之元件才有資格直接轉換成ActiveX control

l

The VCL control must descend from TWinControl. This may force you to alter the parentage of your VCL control, but there is usually a suitable alternative. For example, if you're trying to port a non-visual control to an ActiveX control, you might consider using TCustomControl as the ancestor, and provide a simple Paint method.
只有繼承 TWinControl之元件才可被Delphi直接轉換成ActiveX control,但其他非視覺化元件可透過繼承TCustomControl並提供簡單的Paint method以利Delphi直接轉換成ActiveX control

l

Because an ActiveX control is based on OLE, the VCL control can only translate properties that have a corresponding native-OLE data type. In addition, you can provide an adapter to convert the non-standard data type into something that OLE can understand. For example, Delphi comes bundled with adapters, so OLE can use properties of types TString, TPicture, and TFont. If Delphi can't map a data type to a type that OLE can understand, Delphi will omit that property from the generated ActiveX control. You can add properties and methods to the ActiveX control manually by selecting Edit | Add To Interface, or editing the type library itself. Or, you can use the Type Library editor (by selecting View | Type Library) and have Delphi 3 do most of the work.
透過DelphiVCL元件直接轉換成ActiveX Control,Delphi會將VCL propertydata type轉成正確的native-OLE data type(例如string轉成OleString)但其他非視覺化元件可透過繼承TCustomControl並提供簡單的Paint method以利Delphi直接轉換成ActiveX control
注意:若程式碼參數或property中運用到Delphi特有的data type而與OLE不相容時, DelphiVCL元件轉換成ActiveX Control時會忽略此參數或property(8.6.3 DelphiOLE不相容之data type).

 

因此在撰寫VCL元件時若考慮要轉換成為ActiveX元件時,即使為非視覺化VCL元件也要考慮由           TCustomControl來繼承,改寫要領參考8.6.4

 

 

4.VCLActiveX Control不相容之Data Type

 

注意:若程式碼參數或property中運用到Delphi特有的Data Type而與OLE不相容時, DelphiVCL元件轉換成ActiveX Control時會忽略此參數或property,如此可會造成ActiveX功能之限制,以下列出不相容之處及解決方案

 

Delphi特有的Data Type

解決辦法: 轉換成ActiveX Control前需改寫

set property(集合屬性)轉換成ActiveX元件時會失效。例如 TStringGrid.Options轉換成ActiveX時於VB中看不到此propery

新增Boolean property一一對應至集合屬性

範例參照: 下載範例 AxGrid.zip

一些Delphi特有的class:

TStrings, TList, TStream…

例如:  TMemo.Lines, TListBox.Items這些TStrings            property轉換成ActiveX 元件後無法利用           TStrings class member操作物件。

例如:  Delphimemo1.Lines.Add(s);敘述無法於           ActiveX元件中使用

封裝TStrings物件 ( AxMemo.PAS):

例如: 原本例如: MemoX1.Lines.Add(s);可透過封裝隱藏  TStrings的存取方法。範例參照: 下載範例 AxMemo.zip

function TAxMemo.Add(s: string): integer;

begin

           Result:=Lines.Add(s);

end;

VCL元件的RunTimeDesignTime檢查敘述無法辨識

例如: 轉換成ActiveX 元件後以下的statement           無法正確執行

           if (csDesigning in ComponentState)then

Delphi轉換的成的ActiveX元件繼承TActiveXControl

可利用其member ClientSite IAmbientDispatch.UserMode判別

eg.      以下函數用來判別ActiveX元件是否處於Design Time

           Run Time之狀況

function IsAxDesignTime(ax: TActiveXControl): boolean;

begin //[

  Result:=true;

  if  (ax.ClientSite<>nil) and

     (ax.ClientSite as IAmbientDispatch).UserMode then

     Result:=false;

end; // ] IsAxDesignTime

 


 

l

實作1: 封裝隱藏TMemo.Lines存取方法

 

DelphiTMemo改成TAxMemo並封裝隱藏TMemo.Lines存取方法。

下載範例 AxMemo.zip

l

實作2:新增相對應於元件集合屬性之Boolean prooerties

 

TStringGrid原本的集合屬性 property Options: TGridOptions; 改成加上 optXXX Boolean屬性一一對應至TGridOptions集合屬性以便轉成ActiveX元件時可相容

下載範例 AxGrid.zip

 

 

5.改寫非視覺化VCL元件以利轉換至ActiveX元件

 

TBvIdleCheck 元件為例原本 TBvIdleCheck繼承於 TComponent現需將其改寫使元件於Design Time時模仿TComponent一般只顯示一個小Icon, Run Time時為invisible。改寫實請依照以下範例套用:

l

修改使元件繼承TCustomControl

l

新增一個override Paint方法,於Design Time時畫一個小Icon

l

新增一個處理WM_SIZE之程序,防止物件於Design Time時被Resize

l

判斷DesignTime時元件為Visible, RunTimeInvisible

l

Delphi中安裝註冊改寫完畢的VCL元件

l

測試VCL元件

l

利用Delphi ActiveX Control WizardVCL元件轉換成ActiveX元件

l

小幅度修改BvIdleCheckImpl1.PAS

l

註冊OCX元件(BvIdleCheckAx.OCX)

l

VB中測試新產生的元件

 

 

l

修改使元件繼承TCustomControl

 

TBvIdleCheck = class(TComponent) 改為

TBvIdleCheck = class(TCustomControl)

 

l

新增一個override Paint方法,於Design Time時畫一個小Icon

 

TBvIdleCheck = class(TCustomControl)

private

          

protected

           procedure Paint; override;

          

end;

procedure TBvIdleCheck.Paint;

begin

           //這是我寫的副程式,Design Time時模仿TComponent一般只顯示一個小Icon

PaintComponentIcon(Self, Self.Canvas);

end;

 

l

新增一個處理WM_SIZE之程序,防止物件於Design Time時被Resize

 

TBvIdleCheck = class(TCustomControl)

private

          

protected

           procedure WMSize(var Message: TWMSize); message WM_SIZE;

          

end;

procedure TBvIdleCheck.Create(AOwner: TComponent);

begin

   

    Width:=24; Height:=24; //固定object size 24x24

end;

//         收到WM_SIZE訊息時固定object size 24x24

procedure TBvIdleCheck.WMSize(var Message: TWMSize);

{$J+}

const

    s_bOnOp: boolean=false;

begin

    if  s_bOnOp then exit;

    s_bOnOp:=true; Width:=24; Height:=24; s_bOnOp:=false;

end;

 

l

判斷DesignTime時元件為Visible, RunTimeInvisible

 

//         元件被載入Loaded時, 設定物件寬高為24

//         判斷若是RunTimeè設定物件為invisible

procedure TBvIdleCheck.Loaded;

begin

          

if   not (csDesigning in ComponentState) then Visible:=false

else                                                                     Invalidate;

end;

 

l

Delphi中安裝註冊改寫完畢的VCL元件

 

DelphiComponentàInstall Compoent 安裝TBvIdleCheck元件



 


下載範例 BvIdleCheck.zip

 


 

l

測試VCL元件

 

下載Delphi範例BvIdleCheckDemo.zip



 

 


l

利用Delphi ActiveX Control WizardVCL元件轉換成ActiveX元件

 

參照8.6.1 利用將VCL元件轉換成ActiveX元件,將TBvIdleCheck元件包裝成OCX元件



 


請注意公司內定之Naming Convention : (Project規定存放至 /sdk/ActiveX/ 路徑中)

 

 

TBvIdleCheck為例

Delphi產生之預設名稱

將之改稱我們的Naming Convention

 

New ActiveX Name

BvIdleCheckX

BvIdleCheckX

 

Implemntation Unit

BvIdleCheckImpl1.pas

BvIdleCheckImpl1.pas

 

Project Name

BvIdleCheckXControl1.dpr

BvIdleCheckAx.dpr

(注意: Project Name不得與ActiveX Name同名)

 

Build Project後產生 BvIdleCheckAx.OCX

註冊OCX新元件: 執行  TRegSvr BvIdleCheckAx.OCX

 

 

 

 

 

 


 

l

小幅度修改BvIdleCheckImpl1.PAS

 

//  EventSinkChanged() 決定物件是否為 visible

procedure TBvIdleCheckX.EventSinkChanged(const EventSink: IUnknown);

begin

 

FEvents := EventSink as IBvIdleCheckXEvents;

//  IsAxDesignTime() 這是我包裝的副程式,可以檢查繼承自

//  TActiveXControl ActiveX元件是否處於DesignTimeRunTime

//  加上此行, ActiveX元件為   Design Time   èVisible,

//                              Run Time     èinvisible

FDelphiControl.Visible:=IsAxDesignTime(Self);

 

end;

 

//  TActiveXControlFactory constructor

//  ActiveX元件狀態初始化值為 Invisible At Run Time

initialization

 

TActiveXControlFactory.Create(

 

ComServer,

TBvIdleCheckX,

TBvIdleCheck,

Class_BvIdleCheckX,

1,

'{EEB41A8A-5EFE-4759-84A5-27DD7BCA0886}',

OLEMISC_INVISIBLEATRUNTIME, //ActiveX元件狀態初始化值

tmApartment);

 

end.

 

 

l

註冊OCX元件(BvIdleCheckAx.OCX)



 

 


l

VB中測試新產生的元件

 

下載VB 範例BvIdleCheckXDemo.zip

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值