後一頁
前一頁
回目錄
回首頁
第八章 物件鍊結與嵌入(二)

8.3.5.2 在應用程式中釋放OLE物件 

  當一個物件釋放到一個窗體,該窗體發生OnDragDrop 事件。該物件定義為TDragDropEvent方法中的Source參數,而TDragDropEvent 方法是用來處理OnDragDrop事件”。 如果Source 是一個OLE 物件, 那麼它是TOLEDropNotify 物件的派生型式。 TOLEDropNotify物件有一個與OLE包容器部件PInitInfo屬性相對應的PIniInfo屬性。 如果一個OLE物件被釋放。PInitInfo指向OLE物件的初始化資訊結構。要實現釋放功能。只需將TOLEDropNotifyPInitInfo屬性賦給OLE包容器部件的PInitInfo屬性。

  以下為處理OnDragDrop事件的代碼: 

procedure TOLEFrameForm.FormDragDrop(Sender, Source: TObject; X,

Y: Integer);

var

NewChild: TOLEObjectForm;

begin

if Source is TOLEDropNotify then

begin

NewChild := CreateChild;

with Source as TOLEDropNotify do

NewChild.OLEContainer.PInitInfo := PInitInfo

end

end; 

注意不要用ReleaseOLEInitInfo釋放分配給PInitInfo屬性的記憶體。Delphi自動釋放這塊記憶體。 

8.3.6 文件中的OLE物件 

  在OLE應用程式中,要存檔對OLE物件的修改,需將物件數據存檔在文件中。 如果物件是鍊結的數據,Delphi將自動的存檔在源文件中。當物件被修改時,文件中的數據自動修改。 如果物件是嵌入的,數據貯存在應用程式程式的窗體。要存檔對嵌入物件的修改, 應用程式應把數據存檔在特殊的OLE文件中。如果要對已存文件的物件進行編輯,應用程式必須從文件中載入OLE物件。

  OLE包容器部件的SaveToFile方法可存檔物件: 

  OleCntainer1.SaveToFile('C: \SALEs.OLE'); 

  OLE包容器部件的loadFromFile方法可把文件中的物件載入OLE包容器部件。 

  OleContainer1.loadFromFile('C:\SALEs.OLE')

  本章例程使用了存檔對話方塊和打開對話方塊來實現執行狀態的物件存檔和物件載入。

  在OLEObjectForm窗體加入存檔對話方塊部件和打開對話方塊部件。其主要屬性如表8.4: 

  表8.4 存檔對話方塊的屬性及取值:

────────────────────────

 屬性        值

————————————————————————

  Name SaveAsDialog

DefaultExit ole

FileName .OLE

Filter OLE files (*.OLE)|*.OLE

──────────────────────── 

8.5 打開對話方塊的屬性及取值

─────────────────────────

  屬性        取值

————————————————————————

  Name OpenDialog

DefaultExit ole

FileName .OLE

Filter OLE files (*.OLE)|*.OLE

───────────────────────── 

  用戶按一下“文件|存檔”選擇表項實現OLE物件的存檔。代碼如下: 

procedure TOLEObjectForm.SaveAs1Click(Sender: TObject);

begin

if SaveAsDialog.Execute then

OLEContainer.SaveToFile(SaveAsDialog.Filename)

end; 

用戶按一下“文件|打開”選擇表項實現物件文件載入: 

procedure TOLEFrameForm.Open1Click(Sender: TObject);

var

NewChild: TOLEObjectForm;

begin

f OpenDialog.Execute then

begin

NewChild := CreateChild;

NewChild.OLEContainer.LoadFromFile(OpenDialog.FileName)

end

end;

   8.4 OLE自動化 

  OLE自動化是Windows應用程式操縱另一個程式的一種機制。OLE 2.0提供了一種方法來整合應用程式,這就是應用程式之間的命令操作。

  利用OLE 2.0,程式員可以定義一群群組命令,使它們進入到其它程式中。這些命令可帶參數。看起來很象應用程式在呼叫函數或過程一樣。採用上述辦法, 可以在人不參與的情況下,就能使得兩個應用程式的相互作用。

  被自動化的程式稱作自動化物件或自動化伺服器, 操作或自動化其他程式的應用程式稱為自動化控制器或自動化用戶器。

  Delphi2.0完全支援OLE2.0的應用程式自動化,可以用Delphi 2.0編寫自動化控制器和服務

器。在應用程式之間可程式設計的潛能是巨大的。用戶可以建立宏或者其它命令, 使得某個應用程式能透過其它應用程式進行工作。已經存在的應用程式的宏語言很容易被擴展,它可以包括一群群組別的應用程式能夠執行的命令和函數呼叫。

   現在介紹兩個應用程式,其中MemoEdit.dpr 是多文檔介面的文本編輯器,作為OLE自動化伺服器,AutoFrom.dpr是自動化控制器。執行AutoForm前,在Delphi整合開發環境中按一下選擇表(run | parameters),Delphi彈出執行參數對話方塊,如圖8.5,輸入參數後執行狀態如圖8.6AutoForm窗體的多個按鈕。可對MemoEdit進行操作;如按Creat按鈕,MemoEdit產生三個子窗體,如圖8.7,按"AddText",子窗體將出現"This text was added through OLE Automation"的字元串“

MemoEdit包括三個單元:

  Mainfrom MDI主窗體

  EditFrom MDE子窗體和自動化類

  MemoAuto 應用程式自動化物件

  下面結合例程講述OLE自動化的基本概念及開發。 

8.4.1 TAutoObject物件 

  TAutoObject Delphi自動化伺服器中所有物件的基類,任何自動化物件都是從TAutoObject類派生出來的。

  OLE物件的定義與其它類的定義類似。它的automated部分象普通類的public部分,OLE控制器可引用在這部分聲明的屬性和方法。編譯器把automated部分建立成OLE自動化物件的入口。但automated部分的代碼有很多限制:

  ● 屬性方法可以定義,但不能定義欄位;

  ● 所有屬性、參數、函數型式必須是以下型式之一: 

  SmallInt,Integer,Single,Double,Currency,TDateTime,String,WordBool, Varint 

屬性聲明只能包括存取定義符(read and Write),其它定義符如index,stored,

default,odefault均不能使用;

  ● 存取定義符必須列出相應的方法標識符,不能使用欄位標識符;

  ● 支援數群群組型式;

  ● 不允許屬性重載;

  ● 方法是可以是虛擬的,但不能是動態的,允許方法重載。

  在EditFrom單元中定義了TMemoDoc類: 

  type

TMemoDoc = Class(TAutoObject)

private

FEditForm : TEditForm;

funtion CretFileName : String;

funtion CretModiFied : WordBool;

procedure SetFileName(Const Value : String);

automated

procedure Clear;

procedure Ineart(Const Text : String);

procedure Save;

procedure Close;

procedure FileName : String read GretFileName write

SetFileName;

procedure Modified : WordBool read GretModified

end; 

        TMemeDoc類是MemoEdit程式的內部自動化類,因此不需要註冊。外部OLE自動化控制器對它不能直接引用。如果要使外部控制器對自動化物件進行操作,則要在聲明自動化物件的單元中呼叫Automation. RegisterClass 進行註冊。例程MemoAuto 單元定義了TMemoApp物件並進行註冊。 

  unit MemoAuto

 

type

TMemoApp = Class(TAutoObject)

implementation

  procedure RegisterMemoApp

Const

AutoClassInfo : TAutoClassInfo = (

AutoClass : TMemoApp;

ProgID : MemoEdit,Application

ClassIn : '{FIFF4880 - 200D - 11CF - BDCF - D020AFOE5B81}';

Description : 'Memo Editor Application';

Instancing : acSingle Instance );

begin

Automation,RegisterClass(AutoClassInfo)

end;

inibialization

RegisterMemoApp;

end; 

        自動化物件要在initialization部分中對自動化物件進行註冊。 註冊的資訊用以唯一辨識伺服器物件。把一個自動化物件加入到伺服器中要用到這些資訊。程式一旦註冊了自動化物件,全局自動化物件將用OLE自動化API進行自動管理。

  註冊後的OLE自動化物件是引用記數的,因為物件可能被多個控制器控制。當使用完一個OLE物件,呼叫Release方法,Release可減少引用數目,當引用數目為零時,呼叫Free方法釋放物件。

  通常把OLE物件作為變體型式(variants)進行輸出,任何OLE 物件的方法和屬性必須返回一個包含OLE物件的變體型式,TAutoObject提供了一個變體型式的OLEObject屬性。控制器不能直接得到伺服器中的類或指標,而是引用OLE物件的OLEObject屬性。

  例程MemoAuto單元的NewMemo函數就是通過引用OLEObject 屬性而提供引用TMemoDoc物件的接口。 

  function TMemoApp,NewMemo : Variant;

begin

Result := MainForm,CreateMemo(' '),OleObject;

end; 

8.4.2 建立OLE自動化伺服器 

  OLE自動化伺服器是應用程式或動態鍊結庫(DLL),它可向OLE 自動化控制器輸出OLE物件。 MemoEditdpr 就是OLE 自動化伺服器, MemoAuto 單元中註冊了MemoEdit.Appdication自動化類,所有OLE控制器均可對MemoEdit.Application進行引用。

  在Windows環境下有兩種OLE自動化伺服器,進程內伺服器和進程外伺服器, Delphi可建立這兩種伺服器。

  進程內伺服器是輸出OLE自動化物件的動態鍊結庫。因為OLE自動化物件來自於DLL

物件是控制器程式的同一窗體進程,進程內伺服器適合於建立共享的程式模群組, 而這個模群組可以被用不同語言編寫的多個程式所共享。 進程內伺服器被呼叫時在同一位址中執行,這樣就不需要控制器進行調度,以避免處理大量的訊息句柄。 進程外伺服器是能輸出OLE自動化物件的應用程式。

  有些OLE自動化伺服器只能建立和輸出一個OLE物件,有些伺服器則可以處理多個OLE物件,另外一些伺服器不能輸出OLE物件,只能在程式內部使用OLE物件。 伺服器與其能輸出的物件數目的關係稱為實例(instancing)

  在建立OLE 自動化物件時必須定義實例, 這樣, 在建立一個OLE 自動化物件時,Windows就能決定是否建立一個新的伺服器實例。表8.5列出三種實例型式。

8.6 實例的取值及含義

───────────────────────────────────────

instancing型式          含義

——————————————————————————————— ———————

internal OLE物件是應用程式的內部物件,物件不需要註冊,外部進程不能創

          建此物件

Single 每個伺服器實例只能輸出一個OLE物件實例, 若控制器需要多個OLE

 

          物件實例,WIndows為第一個OLE物件建立一個伺服器實例

Multiple 一個伺服器能建立和輸出多個OLE 物件實例, 進程內伺服器大多是

         Multiple型式

─────────────────────────────────────── 

  每個使用OLEAuto單元的工程文件自動地擁有一個叫Automation的物件,它是非可視物件。就象Application部件擁有Delphi應用程式的一些資訊一樣,Automation物件也擁有伺服器的一些資訊,其中最重要的是StartMode屬性和OnLastRelease事件。

  StartMode指示OLE自動化伺服器打開方式打開的目的。表8.7列出StartMode四種取值。 

8.7 StartMode 的取值及含義

───────────────────────────────

  取值          含義

———————————————————————————————

  SmStandAlone 用戶啟動應用程式

  SmAutomation Windows為建立OLE物件而啟動程式

  SmRegSever 應用程式僅為註冊一個或多個OLE物件而啟動

  SmUnregSever 應用程式僅為登出一個或多個OLE物件而啟動

─────────────────────────────── 

  當StartMode模式是SmAutomation,而用戶不再需要伺服器時發生OnLastRelease 事件。此時所有OLE控制器釋放了由伺服器建立的物件。缺省情況下,伺服器關閉實例,但OnLastRelease 事件可根據實際情況是否關閉。OnLastRelease 事件可得到一個叫ShutDown的布爾型變數。把ShutDown設定成True,則在最後一個OLE物件釋放時伺服器不關閉。

  無論建立何種自動化伺服器,必須定義對控制器的介面,包括定義和註冊OLE物件,OLE自動化物件的屬性和方法。定義介面主要是為了控制器能夠引用它們。

  對已存在的自動化伺服器界進行修改時,要確保向上相容 ,不要刪去已有的屬性、方法,這樣會導致已存在的自動化控制器發生錯誤,修改伺服器只能增加屬性和方法。

  建立OLE自動化伺服器第一步是建立伺服器自身。即建立能輸出OLE 物件的應用程式或動態鍊結庫。這主要取決於是建立進程內伺服器還是進程外伺服器。

  建立進程內伺服器,即動態鍊結庫:

  1.建立動態鍊結庫;

  2.在工程文件的uses條款中加入OLEAuto單元;

  3.DLL中輸出四個標準入口,即加入以下代碼。 

  exports

DLLGetClassObject,DLLCanUnloadNow;

DLLRegisterServer,DLLUnregisterServer; 

以上代碼必須準確拼寫,包括大小寫。與Object Pascal的其它項目不同,這些代碼

對大小寫敏感。

  建立進程外伺服器:

  1.建立一個Delphi應用程式;

  2.在工程文件的begin之後加入以下代碼; 

  if Automation,Server Registration then Exit; 

建立伺服器之後,應該向伺服器加入OLE自動化物件,這個過程大部分是自動完成的,但必須向Delphi的自動化物件專家提供必要的資訊。

  把OLE自動化物件加入伺服器:

  1.Delphi整合開發環境中選擇File| New 選擇表項, 並在物件集中選擇Automation

Object,Delphi打開自動化物件專家。

2.給自動化物件命名

   這是伺服器內部標識OLE物件的名字,必須是個有效的面象物件Pascal標識符,習慣上以T字母開頭;

  3.OLE類命名

   該名用以外部控制器建立物件。當伺服器在Windows中註冊OLE物件, 就以這個名字在系統註冊。控制器使用這個名字呼叫CreateOLEObject來建立物件。

  4.描述要輸出的物件。

  5.定義物件的實例(instancing),進程內伺服器常定義為Multiple,進程外伺服器常定義為Single

  6.選擇OK鍵完成該過程

   自動化物件專家將產生以下代碼:

   ● TAutoObject派生下來的自動化物件定義,但沒有定義任何屬性方法;

   ● 呼叫DelphiOLE自動化管理器的註冊代碼,管理器負責Windows中註冊伺服器和物件。 

  在註冊代碼中包括一個自動產生的ID號,這個ID號是全局唯一的,通常不要修改。每個ID號與一個OLE類名相對應,如果其中之一被改變,應用程式在使用時會發生錯誤。

  在建立了伺服器並把OLE自動化物件加入伺服器之後,控制器程式就可以對伺服器進行操縱。 

8.4.3 自動化另一程式 

  每個伺服器在系統註冊中有一個叫ProgID的關鍵定,主要用以控制器辨識伺服器。任何控制器可以用ProgID號來建立OLE物件實例。例程AutoForm是控制器程式,它在其主窗體建立了OLE物件實例。 

  procedure TMainForm.FormCreate(Sender : TObject);

begin

try

MemoEdit := CreateOleObject('MemoEdit.Application');

except

MessageDlg(

'An instance of the "MemoEdit Application"OLE Automation Class could

not be created,Make sure that the MemoEdit application has been registered

using a "MemoEdit|regserver"command line',

mtError,[mbok],0)

Halt;

end;

end; 

        控制器建立了OLE自動化物件實例後,可對其進行操縱。OLE自動物件包括屬性和方法,雖然OLE自動化物件與面向物件Pascal中的物件不是同一概念,但Delphi允許使用與類似的語法對OLE物件的方法進行呼叫。

  AutoForm的很多過程引用了OLE自動化物件的方法: 

  procedure TMainForm,TileButtonClick(Sender : Tobject);

begin

MemoEdit,TileWindow;

end; 

其中TileWindowsOLE物件TMemoApp中定義的方法。

  AutoForm還通過TMemoAppNewMemo方法獲得了對伺服器內部OLE物件TMemoDoc 的引用。

 procedure TMainForm,CreateButtonClick(Sender : TObject);

var

I : Integer;

begin

CloseMemo

for I := 1 to 3 do Memos[2] := MemoEdit.NewMemo;

end; 

其中NewMemoMemoAuto單元中定義如下: 

  function IMemoApp.NewMemo : Variant;

begin

Result := MainForm,CreateMemo(' '),OleObject;

end;

控制器在獲得伺服器的內部OLE物件後,可以引用其方法: 

  procedure TMainForm.AddTextButtonClick(Sender,TObject);

var

I : Integer;

begin

for I := 1 to 3 do

if not var IsEmpty(Memo[I]) then

Memo[I],Insert{'This text was added through OLE Automation'#13#10);

end;

InsertTMemoDoc中定義的方法,用以在子窗體中插入字元串。



後一頁
前一頁
回目錄
回首頁