2012年7月24日 星期二

剪貼簿(Clipboard)和動態數據交換

轉貼自剪貼簿和動態數據交換

應用程式間的數據交換是象Windows 這樣的多工環境的重要特性。作為一種基於Windows的開發工具,Delphi支援如下四種數據交換方式:剪貼簿、動態數據交換 ( DDE)、物件聯接與嵌入(OLE)以及動態聯接庫(DLLs)。這中間前三種方式最為常用,OLE功能最為強大,DDE次之。而剪貼簿使用最為方便。在本章,我們只討論剪貼簿和動態數據交換。利用OLE實現數據交換見下一章,利用動態聯接庫(DLLs)進行數據交換將在第十章中介紹。  

7.1 剪貼簿及其應用 

本質上,剪貼簿只是一個全局記憶體塊。當一個應用程式將數據轉送給剪貼簿後,通過修改記憶體塊分配標誌,把相關記憶體塊的所有權從應用程式移交給Windows自身。其它應用程式可以通過一個句柄找到這個記憶體塊,從而能夠從記憶體塊中讀取數據。這樣就實現了數據在不同應用程式間的傳輸。  

剪貼簿雖然功能較為簡單,且不能實現即時傳輸,但卻是更為複雜的DDE和OLE的基礎。對於一些只是偶爾需要使用其它應用程式數據的程式來說,使用剪貼簿不失為一種方便、快捷的方式。

Delphi把剪貼簿的大部分功能封裝到一個TClipboard類中,同時把使用頻度最高的文本傳輸功能(包括DBImage的圖像傳輸功能)置入相應部件作為部件的方法,從而使用戶可以十分方便地使用剪貼簿進行程式設計。 

7.1.1 使用剪貼簿傳輸文本 

剪貼簿傳輸文本主要是應用如下的三個方法:CopyToClipboard、CutToClipboard 和PasteFromClipboard。包含這些方法的部件如下表所示。 

   表7.1 包含剪貼簿方法的部件

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

方 法 部 件

??????????????????????????????????????????????????????

TDBEdit TDBMemo

TDBImage

CopyToClipboard TEdit TMemo TMaskEdit

TOLEContainer

TDDEServerItem

??????????????????????????????????????????????????????

TDBEdit TDBMemo

CutToClipboard TDBImage

TEdit TMemo TMaskEdit

??????????????????????????????????????????????????????

TDBEdit TDBMemo

PasteFromClipboard TDBImage

TEdit TMemo TMaskEdit

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

除TDBImage外,其餘全是有關文本的控件。

在把文本傳輸到剪貼簿之前,文本必須被選中。

若選TMaskEdit的AutoSelect屬性為True,則當MaskEdit獲得輸入焦點時文本自動被選中;若選TEdit、TMemo的HideSelection屬性為True,則失去焦點時,文本選中狀態自動隱藏,重新獲得焦點時再顯示。

下面的語句把MaskEdit中選中的文本剪下來到剪貼簿: 

MaskEdit .CutToClipboard; 

下面的語句把剪貼簿中的文本貼上去到Memo的目前遊標處: 

Memo.PasteFromClipboard; 

利用剪貼簿類也可以實現文本的傳輸,見(7.1.2)中的介紹。 

7.1.2 剪貼簿類 

為方便剪貼簿的操作,Delphi在Clipbrd庫單元中定義了一個TClipboard類,並且預定義了一個變數Clipboard作為類TClipboard的實例,從而使用戶在絕大多數場合不必自己去定義一個TClipboard的實例。

利用剪貼簿類可以進行文本、圖像和部件的傳輸,剪貼簿類為實現這些方法提供了相應的屬性和方法。表7.2、表7.3列出了TClipboard屬性和方法的意義。  

表 7.2 TClipboard的屬性

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

屬 性 意 義

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

AsText 存檔剪貼簿的文本,只有執行時才可設定

FormatCount 可用剪貼簿格式的數目

Formats 可用剪貼簿格式鍊

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

   表 7.3 TClipboard的方法

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

方 法 參 數 意 義

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

Clear 無 清除剪貼簿的內容

Assign Source:TPersistent 把Source參數指定的物件拷貝到剪貼簿,常

用於圖形、圖像物件

Open 無打開剪貼簿,阻止其它應用程式改變它的內容

Close 無 關閉打開的剪貼簿

SetComponent Source:TPersistent 把部件拷貝到剪貼簿

GetComponent Owner 從剪貼簿取回一個部件並放置

Parent :TPersistent

SetAsHandle Format:Word 把指定格式數據的句柄交給剪貼簿

返回型式:THandle

GetAsHandle Format:Word 返回剪貼簿指定格式數據的句柄

返回型式:THandle

HasFormat Format:Word 判斷剪貼簿是否擁有給定的格式

返回型式:Boolean

SetTextBuf Buffer:PChar 設定剪貼簿的文本內容

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

  剪貼簿中可能的數據格式如下表。 

表 7.4 剪貼簿數據格式及其意義

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

數據格式 意 義

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

CF_TEXT 文本。每行以CF_LF結束,nil標誌文本結束

CF_BITMAP Windows點陣圖

CF_METAFILE Windows元文件

CF_PICTURE TPicture型式的物件

CF_OBJECT 任何TPersistent型式的物件

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

利用TClipboard實現文本的傳輸使用AsText屬性和SetTextBuf方法。

AsText屬性為非控件部件的剪貼簿操作提供了方便。如: 

Clipboard. AsText := Form1.Caption ; 

把Form1的標題拷貝到剪貼簿。 

Label1.Caption := Clipboard.AsText; 

把剪貼簿中的文本寫入Label1。

SetTextBuf用於把超過255個字元的字元串拷入剪貼簿。 

7.1.3 利用剪貼簿傳輸圖像 

7.1.3.1 拷貝 

Image部件上的內容和窗體上的圖形可以直接拷貝到剪貼簿。圖像拷貝利用Clipboard的Assign方法。

例如: 

Clipboard.Assign(Image1.Picture); 

把Image1上的圖像拷貝到剪貼簿。 

7.1.3.2 剪下來 

圖像的剪下來是首先把圖像拷貝到剪貼簿,而後在原位置用空白圖像進行覆蓋。

下面一段程式表示了圖像的剪下來。  

procedure TForm1.Cut1Click(Sender: TObject);

var

ARect: TRect;

begin

Clipboard.Assign(Image1.Picture);

with Image.Canvas do

begin

CopyMode := cmWhiteness;

ARect := Rect(0, 0, Image.Width, Image.Height);

CopyRect(ARect, Image.Canvas, ARect);

CopyMode := cmSrcCopy;

end;

end;

7.1.3.3 貼上去 

從剪貼簿上貼上去圖像,首先偵測剪貼簿上的數據格式。如果格式為CF_BITMAP,則呼叫目標點陣圖的Assign 方法貼上去圖像。

程式清單如下。

procedure TForm1.PasteButtonClick(Sender: TObject);

var

Bitmap: TBitmap;

begin

if Clipboard.HasFormat(CF_BITMAP) then

begin

Bitmap := TBitmap.Create;

try

Bitmap.Assign(Clipboard);

Image.Canvas.Draw(0, 0, Bitmap);

finally

Bitmap.Free;

end;

end;

end; 

try...finally為資源保護塊,參第十二章。

7.1.4 建立自己的剪貼簿觀察程式 

在這一節中我們要建立一個自己的剪貼簿觀察程式,用來存檔截獲到剪貼簿中的點陣圖。

Windows允許用戶建立自己的剪貼簿觀察程式,並把該程式加入到一個剪貼簿觀察器鍊中。在鍊中,位置靠前的程式有義務把有關剪貼簿的訊息傳遞到緊隨其後的觀察程式。而處於鍊首的程式由Windows的訊息回圈機制直接把剪貼簿訊息發送過來。

建立一個剪貼簿觀察程式,首先該程式必須能響應相應的Windows訊息。對於那些熟悉Microsoft公司Visual Basic的讀者來說,這是令他們頭疼而束手無策的地方。但Delphi在這方面卻有良好的表現:利用關鍵字message,用戶可以將一個過程定義為響應特定的Windows訊息。如: 

procedure WMDrawClipboard(var Msg:TWMDrawClipboard);

message WM_DRAWCLIPBOARD; 

可以響應WM_DRAWCLIPBOARD訊息。類TWMDrawClipboard是訊息類Message 的子類。Delphi把所有的訊息都重新進行了定義,使用戶在使用時可以直接引用其便於記憶的數據成員,而不必再自己動手去分解訊息。雖然這並不能算作是一個重大的改進,但卻體現了Delphi處處為用戶方便著想的特點。

我們將要建立的程式目的是把截獲到剪貼簿上的點陣圖存檔下來。在本書的寫作過程中,這一工作是大量存在的。雖然利用Windows工具PaintBrush(畫筆),通過貼上去、存檔等操作可以實現這一功能,但卻存在以下一些問題:

1.程式頻繁切換影響效率,當有大量點陣圖存在時更是如此;

2.畫筆有一個很討厭的缺陷:當剪貼簿上的點陣圖比畫筆介面的用戶區大時,用戶區外的點陣圖被截斷。因而往往需要根據所截獲點陣圖的大小來調整畫筆用戶區的大小,並重新進行貼上去。而如果開始就把畫筆用戶區調整到足夠大,又會覆蓋掉螢幕上一些有用的資訊。

為解決這些問題,我開發了下面的程式。程式啟動時,以極小化方式執行。此時只要剪貼簿中存入點陣圖,則自動彈出一個對話方塊請求用戶存檔。如果用戶希望查看確認,則可以連續按兩下執行程式圖示,選擇相應按鈕,剪貼簿中的點陣圖就會顯示在螢幕上。

部件關鍵屬性設計如下: 

ClipSaveForm:

Caption=‘Save Bitmap in Clipboard '

Panel1:

Align = ' Top '

Image1:

Align = ' Client '

SaveDialog1:

FileEditStyle = fsEdit

FileName = '*.bmp'

Filter = 'Bitmap Files(*.bmp)|*.bmp|Any Files(*.*)|*.*'

InitialDir = 'c:\bmp'

Title = 'Save Bitmap' 

程式主視窗是TForm派生類TClipSaveForm的實例。TClipSaveForm通過定義一些私有數據成員和過程,使響應和處理Windows的相應訊息成為可能。下面是TClipSaveForm的類定義: 

type

TClipSaveForm = class(TForm)

SaveDialog1: TSaveDialog;

Image1: TImage;

Panel1: TPanel;

Button1: TButton;

SpeedButton1: TSpeedButton;

SpeedButton2: TSpeedButton;

Button2: TButton;

procedure FormCreate(Sender: TObject);

procedure FormDestroy(Sender: TObject);

procedure Button1Click(Sender: TObject);

procedure Button2Click(Sender: TObject);

procedure SpeedButton1Click(Sender: TObject);

procedure SpeedButton2Click(Sender: TObject);

private

{ Private declarations }

MyBitmap: TBitmap; { 存檔截獲的點陣圖 }

View: Boolean; { 判斷是否顯示 }

NextViewerHandle: HWND; { 下一剪貼簿觀察器的句柄 }

procedure WMDrawClipboard(var Msg:TWMDrawClipboard);

message WM_DRAWCLIPBOARD;

procedure WMChangeCBChain(var Msg:TWMChangeCBChain);

message WM_CHANGECBCHAIN;

{ 響應Windows的剪貼簿訊息 }

public

{ Public declarations }

end;

視窗建立時,把該視窗登入為剪貼簿觀察器,加入到剪貼簿觀察器鍊中,同時進行變數、部件和剪貼簿的初始化。 

procedure TClipSaveForm.FormCreate(Sender: TObject);

begin

View := False;

SpeedButton2.Down := True;

MyBitmap := TBitmap.create;

try

MyBitmap.Width := 0;

MyBitmap.Height := 0 ;

except

Application.terminate;

end;

Clipboard.Clear;

NextViewerHandle := SetClipboardViewer(Handle);

end; 

視窗關閉時,結束剪貼簿觀察器鍊,並釋放記憶體: 

procedure TClipSaveForm.FormDestroy(Sender: TObject);

begin

ChangeClipboardChain(Handle,NextViewerHandle);

MyBitmap.Free;

end; 

在以上兩段程式中用到的兩個Windows API函數SetClipboardViewer和ChangeClipboardChain分別用於登入和結束剪貼簿觀察器鍊。

程式存檔點陣圖的功能是在訊息響應過程WMDrawClipboard中實現的。該過程在剪貼簿內容有變化時被呼叫。 

procedure TClipSaveForm.WMDrawClipboard(var Msg: TWMDrawClipboard);

var

FileName: String;

begin

If NextViewerHandle <> 0 then

SendMessage(NextViewerHandle,msg.Msg,0,0);

If ClipBoard.HasFormat(CF_BITMAP) then

begin

MyBitmap.Assign(Clipboard);

If SaveDialog1.Execute then

begin

FileName := SaveDialog1.FileName;

MyBitmap.SaveToFile(FileName);

end;

If View then

begin

WindowState := wsNormal;

Image1.Picture.Bitmap := MyBitmap;

end;

end;

Msg.Result := 0;

end; 

程式首先判斷在剪貼簿觀察器鍊中是否還存在下一個觀察器。如果有,則把訊息傳遞下去,這是剪貼簿觀察器程式的義務。而後判斷剪貼簿上內容的格式是否為點陣圖。如是,則首先把剪貼簿上內容存檔到數據成員MyBitmap中,並激活一個文件存檔對話方塊把點陣圖存檔到文件中。如果View=True,則把視窗狀態(WindowState)設定為wsNormal,並把MyBitmap賦給Image部件的相應值,使用戶可以對剪貼簿上的點陣圖進行觀察。

訊息響應過程WMChangeCBChain在剪貼簿觀察器鍊上其它觀察器結束時被呼叫。根據被移出觀察器的不同位置決定了不同的處理方法。

procedure TClipSaveForm.WMChangeCBChain(var Msg: TWMChangeCBChain);

begin

if Msg.Remove = NextViewerHandle then

NextViewerHandle := Msg.Next

else

if NextViewerHandle <> 0 then

SendMessage(NextViewerHandle,Msg.Msg,Msg.Remove,Msg.Next);

Msg.Result := 0;

end;

視窗上有兩個加速按鈕,兩個按鈕。它們擊鍵(click)事件處理過程如下。每一程式段的意義是非常顯然的。 

procedure TClipSaveForm.Button1Click(Sender: TObject);

begin

Close;

end;

procedure TClipSaveForm.Button2Click(Sender: TObject);

begin

WindowState := wsMinimized;

end;

procedure TClipSaveForm.SpeedButton1Click(Sender: TObject);

begin

View := True;

Image1.Picture.Bitmap := MyBitmap;

end; 

procedure TClipSaveForm.SpeedButton2Click(Sender: TObject);

begin

View := False;

Image1.Picture.Bitmap := nil;

end; 

通過對這個程式的介紹,以下幾點是應該注意的:

1.提供了一種自己截獲和處理剪貼簿上內容的方法。讀者可以根據需要進一步擴充;

2.提供了響應Windows訊息的方法。在第三篇有關自定義部件開發的內容中,這一問題還要詳細論述;

3.最後的一點啟示是:在Delphi程式開發中巧妙應用傳統的Windows方法(如訊息處理、 API函數等)仍是很有必要的。而在應用這些方法中所體現的方便之處,正是Delphi勝過其它可視化開發工具的一個重要方面。 

7.2 Windows的DDE原理和 Dephi的DDE實現機制 

7.2.1 Windows的DDE原理 

Windows的DDE機制基於Windows的訊息機制。兩個Windows應用程式通過相互之間傳遞DDE訊息進行DDE交談(Conversation),從而完成數據的請求、接聽、傳輸。這兩個應用程式分別稱為伺服器(Server)和用戶(Client)。伺服器是數據的提供者,用戶是數據的請求和接受者。

DDE交談由用戶程式啟動。用戶程式把一條訊息(WM_DDE_INITIATE)傳播給目前執行的所有Windows程式。這條訊息指明了用戶程式所需要的一般數據(應用程式、主題)。擁有這些數據的DDE伺服器可以響應這條被傳播的訊息。此時,DDE交談就開始了。

由於在每個主題中,DDE伺服器可以支援一個或多個數據項,所以在用戶請求數據時應同時指明應用程式名、主題名和項目名。應用程式、主題、項目是DDE中三個最基本的概念。

利用Windows本身提供的DDE訊息和API進行DDE程式設計是一件相當棘手的問題。 雖然使用DDE管理庫(ddeml.dll)可以一定程度上減輕開發者的工作負擔,但開發DDE程式仍不是一件輕鬆的事情。

此時Delphi出現了!Delphi通過其自身巧妙的設計使開發一個DDE應用程式同開發一個普通程式一樣地快捷、方便。 

7.2.2 Delphi的DDE實現機制簡介 

Delphi把所有的DDE功能做到四個部件中,它們是:

● TDDEClientConv : 用於用戶程式建立和維護一個DDE交談

● TDDEClientItem : 用於用戶程式建立和維護數據交換通道

● TDDEServerConv : 用於伺服器程式響應DDE交談

● TDDEServerItem : 用於伺服器程式維護數據交換通道 

  前兩個部件用於產生一個DDE用戶程式,後兩個部件用於產生一個DDE伺服器程式。如果一個應用程式同時擁有這些部件,則這一程式既可以充當DDE用戶,也可以充當DDE伺服器。

交談部件TDDEClientConv、TDDEServerConv用於建立和維護一個DDE交談。DDE交談包括DDE服務和DDE主題兩部分。

DDE服務是DDE伺服器的標簽,即在一般的Windows DDE機制中所講的應用程式名。一般說來這一標簽是DDE伺服器應用程式執行檔案標簽去掉 .EXE後綴。比如你的應用程式要和Word 6.0建立交談,則DDE服務為WINWORD。但也不盡然。比如你的應用程式要和Borland ReportSmith ( RPTSMITH.EXE ) 建立交談,則DDE 服務為 Report Smith。DDE服務到底如何,讀者可參看相關的DDE伺服器應用程式文檔。

DDE主題是一個包含了聯接資訊的數據單元。一般說來DDE 主題是一個包括檔案附加名的完整檔案標簽。例如和Excel中的一個文件建立DDE交談,則主題可能是 

Topic = 'c:\excel\Example\sale.xls' 

如果伺服器是一個Delphi應用程式,缺省情況下主題是包含欲聯接數據窗體的標題。如果伺服器使用了DDEServerConv部件,則要求使用部件DDEServerConv的標簽作為DDE主題。

項目部件TDDEclientItem、TDDEServerItem用於建立和維護DDE數據的傳輸通道。 DDE項目中包含著實際欲傳輸的數據。DDE項目的格式取決於DDE伺服器應用程式。一個可能的DDE項目例子是電子表格中的單元和資料庫表中的欄位。如果伺服器是Delphi應用程式,則項目是連接的 DDEServerItem部件的標簽。

Delphi的DDE實現機制方便、實用,但也有一個令人遺憾的缺陷:只能傳輸文本數據以及命令、宏,而不能傳輸圖像數據。在這一點上微軟公司推出的Visual Basic 要略勝一籌。不過在目前文本數據的使用仍是最廣泛的,而且圖像傳輸可以利用剪貼簿和OLE來實現,則這一缺陷也並無很大的影響 

7.3 DDE用戶程式的實現

DDE用戶程式啟動DDE交談,向伺服器請求並從伺服器接收數據。同時還可以向伺服器發送數據、命令、宏,改變伺服器的狀態並控制伺服器的執行。 

7.3.1 聯接模式(ConnectMode)

Delphi的DDE提供了兩種聯接模式:自動和人工。這可以通過DDEClinetConv 部件的ConnectMode屬性進行設定。如下表所示。 

表 7.5 DDE的聯接模式

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

     值           意      義

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

ddeAutomatic 在執行中當包含TDDEClientConv部件的視窗建立時

聯接自動建立

ddeManual 只有當呼叫OpenLink方法時聯接才建立

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

不同聯接模式,DDE用戶程式的實現方式不同。

對於自動模式:

1. 向窗體中加入DDEClientConv和DDEClientItem部件並命名;

2. 把DDEClientItem部件的DdeConv屬性設定為DDEClientConv部件的標簽;

如果在設計時建立,則通過物件觀察器進行選擇;如果在執行時建立聯繫, 則通過如下的一條語句設定屬性的值: 

DDEClientItem1.DdeConv := 'DDEClientConv1' ; 

3. 和伺服器建立聯繫,實現數據共享。

對於人工模式:

1.向窗體中加入DDEClientConv部件;

2.和伺服器建立聯繫;

3. 數據更新時呼叫RequestData方法申請並獲得數據。 

7.3.2 和DDE伺服器建立聯繫 

和DDE伺服器建立聯繫,既可以在設計時進行,也可以在執行時進行。

在設計時,DDE聯接可以通過剪貼簿進行貼上去。具體步驟如下:

1. 激活伺服器程式,並選中你的用戶程式欲聯接的數據;

2. 把數據和DDE聯接資訊拷貝到剪貼簿上。一般說來這只需要選擇伺服器應用程式的 Edit|Copy 選擇表;

3. 在Delphi IDE的設計窗體中選中DDEClientConv部件;

4. 在Object Inspector(物件觀察器)中按一下DDEService屬性或DDETopic屬性,然後再按一下Ellipsis按鈕,打開DDE Info對話方塊;

5.選擇Paste Link按鈕。此時App編輯框和Topic編輯框被自動填充。如果Paste Link按鈕變灰,敘述你準備用作伺服器的應用程式不支援DDE或者DDE資訊沒有被成功地拷貝到剪貼簿上;

6.選擇OK 按鈕。此時Object Inspector中的DDEService、DDETopic 屬性包含了建立一個DDE聯接的正確值。

對於人工模式以下步驟是不需要的。

7.選中DDEClientItem部件,並在Object Inspector中設定DdeConv屬性為已完成聯接的DDEClientConv部件標簽;

8.假如剪貼簿上的DDE 聯接資訊仍保留的話,從Object Inspector的下拉列示方塊中選擇 DDEItem 屬性的值。否則輸入正確的值。

在執行時,呼叫 SetLink 方法來建立DDE聯接。

SetLink有兩個String型式的參數,分別用來接受DDEService和DDETopic的值。過程執行後DDEClientConv部件的DDEService 和DDeTopic屬性被設定。要注意的是:在執行時直接設定DDEService和DDETopic的值並不能建立一個DDE聯接,而必須呼叫SetLink 方法進行初始化。

比如,下面的語句和Excel的System主題建立聯接: 

DDEClietnConv. SetLink('Excel','System'); 

呼叫SetLink方法後,還需要設定DDEClientItem部件的DDEItem屬性。

比如,下面的語句聯接Excel的Topics項目,用以獲取目前活躍文件的檔案標簽: 

DDEClietnItem.DDEItem := 'Topics'; 

當DDE聯接建立後,聯接的數據存檔在DDEClientItem部件的Text和Lines 屬性中,Text用於存檔一個字元串(String),Lines用於存檔一個字元串鍊表(TStrings)物件。

為了顯示聯接數據,可以在DDEClientItem的OnChange事件中把數值賦給一個可視部件。

下面的事件過程把聯接數據即時地顯示在一個編輯框中。

procedure Form1.DDEClientItemChange(Sender: Tobject);

begin

Edit1.Text := DDEClientItem1.Text;

end; 

執行狀態下也可以從剪貼簿上貼上去DDE聯接資訊,並呼叫SetLink建立DDE交談。下面的例子顯示了當用戶按下應用程式中的Paste Link按鈕時,動態建立DDE交談的過程。 

procedure Form1.OnPasteLink(Sender: Tobject);

var

Service, Topic, Item: String;

begin

if GetPasteLinkInfo (Service, Topic, Item) then

begin

AppName.Text := Service;

TopicName.Text := Topic;

ItemName.Text := Item;

DDEClient.SetLink (Service, Topic);

DDEClientItem.DdeConv := DDEClient;

DDEClientItem.DDEItem := ItemName.Text;

end;

end; 

GetPasteLinkInfo是DDEMan 庫單元中定義的一個過程。如果返回True,則DDE聯接資訊存檔在三個參數中;如果返回False,敘述剪貼簿上沒有正確格式的DDE聯接資訊。 

7.3.3 數據申請 

雖然自動模式快捷、方便,但仍有一些理由使用DDE的人工模式:

1.伺服器程式可能不支援自動數據傳輸,用戶必須顯式申請伺服器更新一個特定的項目;

2.節省通信費用。假如沒有即時傳輸的要求,則人工模式可以大幅度降低通信的開銷;

3.若用戶程式只用於控制伺服器的執行,則往往沒有必要使用自動模式。

人工模式下用戶程式的數據更新需要採用數據申請的方式。數據申請需要呼叫DDEClientConv部件的RequestData方法。RequestData有一個參數,指向要申請的DDE項目。RequestData返回一個Pchar型式的無結束符字元串,包含了申請到的文本。返回字元串佔用的記憶體必須在程式終止前顯式釋放。

在人工模式下,即使存在一個DDEClientItem部件且與DDEClientConv相聯接,數據更新後DDEClientItem部件的Text、Lines屬性的值也不會改變。 

7.3.4 數據發送 

數據發送與一般的DDE數據流向正好相反,是把數據從DDE用戶應用程式發送到DDE伺服器應用程式。

數據發送使用DDEClientConv部件的兩個方法PokeData 和 PokeDataLines, 它們的語法是: 

function PokeData (Item: String ; Data: PChar): Boolean;

function PokeDataLines (Item: String ; Data: TStrings): Boolean; 

參數Item是DDE伺服器中被聯接的項目,Data是要發送的數據。如果數據是一個字元串,則把它轉化為PChar型式並呼叫PokeData方法;如果數據是一個字元串鍊表物件,可呼叫PokeDataLines方法。

方法的返回值標誌數據轉送是否成功。因為有一些DDE伺服器應用程式並不接收發送的數據。

下面的語句把編輯框中的內容發送給伺服器: 

StrPCopy(TheText , Edit1.text);

DDEClientConv1.PokeData(DDEClientItem1.DDEItem , TheText); 

過程StrPCopy把一個Pascal型式的字元串拷貝到一個無結束符的PChar型式字元串中。

沒有留言: