線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:5068
推到 Plurk!
推到 Facebook!

【Windows的DDE原理】

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-09-26 16:06:20 IP:61.221.xxx.xxx 未訂閱
【Windows的DDE原理】 http://www.delphiok.com/article/0014.htm 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類型字串中。 7.3.5 控制伺服器應用程式的執行 客戶程式控制伺服器應用程式的一個方面是:必要的時候客戶程式可以啓動伺服器程式,並裝載會話主題。 而客戶程式控制伺服器應用程式更重要的一點是向伺服器發送伺服器承認的巨集命令,來完成對伺服器應用程式的各種操作。伺服器到底支援哪些巨集命令,可參閱伺服器應用程式文檔。 發送巨集命令要使用DDEClientConv的兩個方法 ExecuteMacro和ExecuteMacroLines ,它們的語法如下: function ExecuteMacro(Cmd: PChar; WaitFlag: Boolean): Boolean; function ExecuteMacroLines(Cmd: TStrings;WaitFlag: Boolean): Boolean; Cmd是欲發送的巨集命令字串或巨集命令字串鏈表。WaitFlag決定了在DDE 伺服器程式執行巨集命令時客戶程式的行爲。如果WaitFlag設置爲True,則在伺服器巨集命令執行完畢前,不允許對ExecuteMacro、ExecuteMacroLines、PokeData、PokeDataLines這些方法的成功調用,它們都不向伺服器發送資料並返回False。如果WaitFlag設置爲False,則調用的方法在第一個宏執行完畢前即試圖向伺服器發送資料。 WaitFalg的設置也取決於伺服器應用程式。一些應用程式當在第一個巨集執行完之前就試圖向它發送資料或命令時,可能導致第一個宏執行失敗或導致不可預料的後果。具體情況可查閱伺服器應用程式文檔。 函數返回值表示命令串是否被成功傳輸。而巨集命令執行是否成功客戶是無法檢測到的。 7.3.6 格式化文本 DDEClientConv有一個布林屬性FormartChars,用於決定是否格式化文本。所謂格式化文本是指從傳輸來的文本資料中過濾掉BackSpace(8)、 Tab(7) 、Linefeed(10) 、Return(13)等字元。括弧內是字元的ASCII碼。許多時候這些字元將導致DDE客戶資料顯示的混亂。 FormatChars的缺省值是False。 7.3.7 回應DDE事件 部件DDEClientConv有兩個事件OnOpen和OnClose,分別在DDE 會話建立和中止時觸發。部件DDEClientItem有一個OnChange事件。這一事件常用於DDE專案資料的轉儲和顯示,如(7.3.1)節所示。 在自動模式下,OnOpen事件在包含DDEClientConv部件的視窗創建時觸發,或在調用SetLink方法時觸發,OnClose事件在客戶程式或伺服器程式關閉時觸發。 在人工模式下,OnOpen事件在調用OpenLink 方法時觸發,OnClose事件在調用ColseLink方法時觸發。 7.3.8 利用客戶程式和Excel交換資料 下面我們建立一個DDE客戶程式,並利用這一程式與Excel中的一個工作表交換資料。程式設計介面如圖。 圖7.2 客戶程式示例設計介面 介面中包含一個DDE會話部件DDEClientConv1和DDE專案部件DDEClientItem1,用於建立和維護DDE聯接;一個RadioGroup控制項和其中的兩個無線電按鈕AutoRadio、ManualRadio,用於設置聯接模式;一個GroupBox控制項和其中的兩個按鈕RequestBtn和PokeBtn,用於控制資料的申請和發送,其中RequestBtn在自動模式下變灰;一個文本框Memo1用於保存DDE資料;一個按鈕PasteBtn用於粘貼聯接資訊並建立DDE聯接;另外一個按鈕CloseBtn用於關閉系統。 設計時把DDEClientConv1的FormatChars屬性置爲True,這樣可以保留伺服器傳來資料的顯示格式;ConnectMode保留ddeAutomatic的缺省設置。 程式在類TForm1中定義了一個私有資料成員Automatic,用於標誌聯接模式;三個字串資料成員DDEService、DDETopic、DDEItem用於記錄聯接資訊。 視窗生成時進行變數和部件狀態的初始化。 procedure TForm1.FormCreate(Sender: TObject); begin RequestBtn.Enabled := False; AutoRadio.Checked := True; Automatic := True; end; 當聯接模式改變時,程式進行相應的處理。 自動模式轉換爲人工模式: procedure TForm1.ManualRadioClick(Sender: TObject); begin if Automatic then begin RequestBtn.Enabled := ManualRadio.Checked; DDEClientConv1.ConnectMode := ddeManual; Automatic := False; end; end; 人工模式轉換爲自動模式: procedure TForm1.AutoRadioClick(Sender: TObject); begin if not Automatic then begin RequestBtn.Enabled := ManualRadio.Checked; If (DDEService = '') or (DDETopic = '') then begin MessageDlg(' Can not Set Link.',mtWarning,[mbOK],0); Exit; end; DDEClientConv1.SetLink (DDEService, DDETopic); DDEClientItem1.DdeConv := DDEClientConv1; DDEClientItem1.DDEItem := DDEItem; DDEClientConv1.ConnectMode := ddeAutomatic; Automatic := True; end; end; 當從自動模式轉換到人工模式,只需要簡單修改相應屬性即可;而從人工模式轉換到自動模式,則需要調用SetLink重新建立聯接,否則往往會引發一個DDE異常。 聯接的建立採用從剪貼板粘貼聯接資訊的方式,這是最具有靈活性的一種方法。 procedure TForm1.PasteBtnClick(Sender: TObject); begin if GetPasteLinkInfo (DDEService, DDETopic, DDEItem) then begin DDEClientConv1.SetLink (DDEService, DDETopic); if Automatic then begin DDEClientItem1.DdeConv := DDEClientConv1; DDEClientItem1.DDEItem := DDEItem; end; end; end; GetPasteInfo是 DDEMan庫單元中定義的一個函數,用於檢測剪貼板上是否有聯接資訊並返回相應的DDE服務、主題和專案。 對於人工模式,必須由客戶顯式向伺服器申請資料。在這種模式下DDE專案部件是多餘的,接收到的DDE聯接資訊用一個字串來記錄。下面是實現代碼。 procedure TForm1.RequestBtnClick(Sender: TObject); var TheData: PChar; begin If DDEItem = '' then begin MessageDlg('Can not Request Data',mtWarning,[mbOK],0); Exit; end; TheData := StrAlloc(79); DDEClientConv1.OpenLink; TheData := DDEClientConv1.RequestData(DDEItem); DDEClientConv1.CloseLink; if TheData <> nil then Memo1.Text := StrPas(TheData); StrDisPose(TheData); end; OpenLink、CloseLink方法用於打開和關閉聯接。RequestData方法向伺服器申請資料並返回到一個PChar字串中。字串必須顯式分配記憶體並在退出時釋放。 資料發送在不同聯接模式下是不同的。對於人工模式,增加了聯接的打開和關閉操作。程式清單如下。 procedure TForm1.PokeBtnClick(Sender: TObject); begin If DDEItem = '' then begin MessageDlg('Can not Poke Data.',mtWarning,[mbOK],0); Exit; end; if Automatic then DDEClientConv1.PokeDataLines(DDEItem,Memo1.Lines) else begin DDEClientConv1.OpenLink; DDEClientConv1.PokeDataLines(DDEItem,Memo1.Lines); DDEClientConv1.CloseLink; end; end; 打開Microsoft Office中的Excel,裝入一個文件,把相關的單元選中,拷貝到剪貼板上。而後運行程式,按下Paste Link按鈕,DDE聯接就建立起來,相關單元中的資料顯示在Memo1中。之後可以進行模式轉換、資料申請、申請發送等一系列工作。運行後的螢幕顯示如下圖所示。 圖7.3 DDE客戶和Excel交換資料 7.3.9 用客戶程式控制程式管理器 下面的例子用客戶程式向程式管理器發送命令,用於創建程式組、程式項以及刪除程式組。 程式管理器提供了應用程式的DDE介面命令字串,應用程式利用這些命令字串可以實現以下的功能: 1.創建程式組 命令格式爲: CreateGroup(程式組名[,程式組所在的路徑]) 程式組不存在時進行創建;如程式組存在則按照指定的路徑啟動。 2.刪除程式組 命令格式爲: DeleteGroup(程式組名) 3.顯示程式組 命令格式爲; ShowGroup(程式組名,顯示標誌) 顯示標誌用於控制程式組在程式管理器中以極大、極小或正常方式顯示。 4.重新裝入程式組 命令格式爲: ReLoadGroup(程式組名) 該命令使程式管理器先刪除而後再重新裝入一個已有的程式組。 5.向程式組中添加程式項 命令格式爲: AddItem(命令行[,描述[,圖示路徑[,圖示序號[,圖示橫坐標,圖示縱坐標[,工作區目錄[,熱鍵[,是否最小化顯示標誌]]]]]]]) 命令行控制程式項的執行,可包括路徑、參數等。其他參數分別對應在程式管理器中添加一個程式項時需要設置的參數和選項。它們都有缺省設置,因而是可選的。 6.替換程式組中的程式項 命令格式爲: ReplaceItem(程式項名) 該命令刪除一個程式項,並將所刪除程式項的位置記錄下來,以後通過AddItem在這個所記錄的位置增加新專案。 7.從程式組中刪除程式項 命令格式爲: DeleteItem(程式項名) 從當前活動程式組中刪除一個程式項。 8.關閉程式管理器 命令格式爲: ExitProgram(是否保存程式組資訊標誌) 從應用程式向程式管理器發送命令字串的方法是基本一致的。爲簡便起見,在常式中只實現了其中僅包含一個字串參數的情形,讀者可以很容易作進一步的擴展。 程式設計介面如圖所示,包含一個DDE客戶會話(DDEClientConv)部件和四個完成不同功能的按鈕。 圖7.4 控制程式管理器應用程式的設計介面 DDEClientConv在設計時和程式管理器建立一個DDE會話,其中DDE伺服器和DDE主題 都爲PROGMAN。聯接模式ConnectMode設置爲ddeManual。 我們把只有一個字串參數的命令發送情況抽象出來,形成下面的SendMacro函數。 function TForm1.SendMacro(Name: String;Command: String): Boolean; var Macro: String; Cmd: array[0..255] of Char; begin Result := True; if Name <> '' then begin Macro := Format('[' Command '(%s)]', [Name]) #13#10; StrPCopy (Cmd, Macro); DDEClient.OpenLink; if not DDEClient.ExecuteMacro(Cmd, False) then Result := False; DDEClient.CloseLink; end; end; 過程首先利用Format函數形成巨集字串: Macro := Format('[' Command '(%s)]', [Name]) #13#10; 而後把Pascal類型的字串拷貝到一個程式管理器可接受的PChar類型字串中。 DDE聯接採用人工模式。首先調用OpenLink方法。而後調用ExecuteMacro方法發送命令,如失敗則返回False。最後用CloseLink關閉聯接。 三個按鈕CreateButton、AddButton、DeleteButton分別用於創建程式組、添加程式項、刪除程式組。它們的程式實現大同小異,如下所示。 創建程式組: procedure TForm1.CreateButtonClick(Sender: TObject); var Name: String; begin Name := InputBox('Input Box','Input Group Name',''); if Name = '' then MessageDlg('Group name can not be blank.', mtError, [mbOK], 0) else if SendMacro(Name,'CreateGroup') = False then MessageDlg('Unable to create group.', mtInformation, [mbOK], 0); end; 添加程式項: procedure TForm1.AddButtonClick(Sender: TObject); var Name: String; begin Name := InputBox('Input Box','Input Application full_Path name',''); if Name = '' then MessageDlg('Application name can not be blank.', mtError, [mbOK], 0) else if SendMacro(Name,'AddItem') = False then MessageDlg('Unable to Add Item.', mtInformation, [mbOK], 0); end; 刪除程式組: procedure TForm1.DeleteButtonClick(Sender: TObject); var Name: String; begin Name := InputBox('Input Box','Input Group Name to be Deleted',''); if Name = '' then MessageDlg('Group name can not be blank.', mtError, [mbOK], 0) else if SendMacro(Name,'DeleteGroup') = False then MessageDlg('Unable to create group.', mtInformation, [mbOK], 0); end; 7.4 DDE伺服器程式的實現 DDE伺服器程式回應DDE客戶的請求,一般地它包含了客戶程式希望獲取的資料。 創建一個DDE伺服器程式,必須要把一個DDEServerItem部件添加到表單中。DDEServerItem的text或Lines屬性包含了要聯接的資料。一般地 DDEServerItem部件又和另一個文本控制項相聯繫。當文本控制項中的內容變化時則更新DDEServerItem 的text或Lines屬性的值。下面的一段程式把DDEServerItem和一個列表框相聯繫。這一聯繫是在列表框的OnChange事件中實現。 procedure Form1.OnListBoxChange(Sender: TObject); begin DDEServerItem1.Lines := ListBox1.Items; end; 創建DDE伺服器程式時也可以再加入一個DDEServerConv部件,並把兩個部件利用DDEServerItem的ServerConv屬性聯繫起來。此時DDE主題成爲部件DDEServerConv的名稱,而不是擁有DDEServerItem部件表單的標題。 在下列情況下使用DDEServerConv部件成爲必要: 1.擁有DDEServerItem 部件表單的標題可能在運行時改變或可能有其他表單擁有同樣的標題。在這種情況下DDE聯接可能無法建立; 2.DDE客戶程式可能會向你的伺服器程式發送一條巨集命令。在這種情況下只有擁有一個DDEServerConv部件才能回應OnMacroExecute事件並執行相應的動作。 7.4.1 和DDE客戶程式建立聯接 一般說來,建立DDE聯接是客戶程式的任務。但伺服器程式可以把一個聯接拷貝到剪貼板上供客戶程式粘貼並建立DDE會話。步驟如下: 1.調用DDEServerItem部件的CopyToClipboard方法, 把Text(或Lines)屬性的值和DDE聯接資訊拷貝到剪貼板上; 2.DDE客戶程式插入聯接的資料。一般地這是通過選擇適當的命令(如Edit|Paste Special或Edit|Paste Link)來實現的。 7.4.2 回應DDE事件 部件DDEServerConv有三個事件:OnOpen、OnClose、OnExecuteMacro。前兩個事件在DDE會話建立和終止時觸發。同(7.3.7)中的介紹。 OnExecuteMacro事件用於回應客戶程式發送過來的巨集指令。OnExecuteMacro事件處理過程有一個Msg參數,保存發送過來的指令串。用戶可以在該過程中決定如何回應這些巨集指令。 DDEServerItem部件只有一個事件OnPokeData。這一事件用於回應客戶程式發送來的資料。如果客戶程式是Delphi程式,則客戶程式調用了PokeData或PokeDataLines方法。在這一事件的處理過程中用戶可以把發送來的資料保存到一個合適的地方。一般說來這應該就是DDEServerItem所聯繫的文本控制項。 下面的程式把發送來的資料保存到ListBox中。 procedure Form1.OnDDEServerItemPokeData(Serder: TObject); begin ListBox1.Items := DDEServerItem1.Lines; end; 7.4.3 DDE伺服器應用常式 下面我們創建一個DDE伺服器常式和一個相應的DDE客戶常式。 DDE伺服器常式可以完成的工作有: 1.把DDE聯接資訊拷貝到剪貼板上供其他程式使用; 2.利用一個TMemo部件爲其他程式提供資料源; 3.接收客戶程式發送來的資料; 4.根據客戶程式發送來的巨集指令改變自身的運行狀態。 伺服器常式的設計介面如圖。 圖7.5 伺服器常式設計介面 其中各部件的關鍵屬性如下: DDESrvrForm.ActiveControl = Memo1 DDESrvrForm.Menu = MainMenu1 Bevel1.Align = alTop Memo1.Align = alClient DDETestItem.ServerConv = DDETestTopic 通過設置Bevel1、Memo1的Align屬性,可以保證視窗大小變化時仍能有較爲美觀的螢幕顯示。 Memo1是伺服器的資料源,DDE專案部件DDETestItem通過Memo1的OnChange事件與Memo1 建立聯繫。 procedure TDdeSrvrForm.doOnChange(Sender: TObject); begin if not FInPoke then DDETestItem.Lines := Memo1.Lines; end; 其中FInPoke是一個布林類型的私有資料成員,用於標誌程式是否在處理客戶程式的資料發送。當資料是由客戶發送過來轉存到資料源時,則沒有必要再把數據傳給DDE專案部件。 把聯接資訊拷貝到剪貼板,只需簡單調用DDETestItem的CopyToClipboard方法。 procedure TDDESrvrForm.CopyClick(Sender: TObject); begin DDETestItem.CopyToClipboard; end; 這是通過功能表項Edit|Copy來調用的。 接收客戶程式發送來的資料,是在DDETestItem的OnPokeData事件處理過程中。在接收過程中改變FInPoke的值,以阻止資料的無效反送。 procedure TDDESrvrForm.doOnPoke(Sender: TObject); begin FInPoke := True; Memo1.Lines := DDETestItem.Lines; FInPoke := False; end; 在DDE會話部件DDETestTopic的OnExecuteMacro事件處理過程中處理客戶發送來的巨集指令。我們共定義了五種可以回應的巨集指令:CopyDDE、Clear、WS_Normal、WS_MINIMIZED、WS_MAXIMIZED,分別用於拷貝聯接資訊、清除Memo1中的內容以及改變視窗顯示狀態。 procedure TDdeSrvrForm.doMacro(Sender: TObject;Msg: TStrings); var Cmd: String; i: Integer; begin Cmd := ''; if Msg.Count = 0 then Exit; for I := 0 to Msg.Count-1 do begin Cmd := Msg.Strings[i]; if UpperCase(Cmd) = 'COPYDDE' then DDETestItem.CopyToClipboard else if UpperCase(Cmd) = 'CLEAR' then Memo1.text: = '' else if UpperCase(Cmd) = 'WS_NORMAL' then WindowState := wsNormal else if UpperCase(Cmd) = 'WS_MINIMIZED' then WindowState := wsMinimized else if UpperCase(Cmd) = 'WS_MAXIMIZED' then WindowState := wsMaximized else MessageDlg('Invalid Command',mtWarning,[mbOK],0); end; end; 下面的DDE客戶程式,主要是爲了驗證上面的DDE伺服器程式而設計的,但同時也提供了一個DDE客戶程式設計的完整實例。程式設計介面如圖。 圖7.6 DDE客戶程式的設計介面 程式把接收到的DDE資料保存在一個TMemo類部件DDEDat中,而欲發送給伺服器的資料和巨集指令在另一個TMemo類部件PokeDat中輸入。兩個按鈕PokeBtn、ExecuteBtn用於發送資料和巨集指令。兩個功能表項File|New Link和Edit|Paste Link用於根據用戶的輸入建立新聯接和從剪貼板上粘貼DDE聯接。 DDE聯接的建立通過調用SetLink方法實現。 建立新聯接的實現代碼如下。 procedure TFormD.doNewLink(Sender: TObject); begin DDEClient.SetLink (AppName.Text, TopicName.Text); DDEClientItem.DdeConv := DDEClient; DDEClientItem.DDEItem := ItemName.Text; end; 通過從剪貼板粘貼聯接資訊來建立聯接的實現代碼如下。 procedure TFormD.Edit1Click(Sender: TObject); var Service, Topic, Item : String; begin PasteLink1.Enabled := GetPasteLinkInfo (Service, Topic, Item); end; procedure TFormD.doPasteLink(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; 在DDEClientItem的OnChange事件處理過程中把接收到的事件保存在DDEDat中。 procedure TFormD.DDEClientItemChange(Sender: TObject); begin DDEDat.Lines := DDEClientItem.Lines; end; 資料發送的實現代碼如下。 procedure TFormD.doPoke (Sender: TObject); var DDECli : TDDEClientConv; begin DDECli := DDEClientItem.DdeConv; if DdeCli <> nil then DDECli.PokeDataLines (DDEClientItem.DDEItem, PokeDat.Lines); end; 巨集指令發送的實現代碼如下。 procedure TFormD.doMacro (Sender: TObject); var DDECli: TDDEClientConv; Cmd: String; begin DDECli := DDEClientItem.DdeConv; if DDECli <> nil then begin Cmd := PokeDat.Text #13#10; DDECli.ExecuteMacroLines (PokeDat.Lines, True); end; end; 運行以上兩個程式,建立DDE聯接。經測試,資料傳輸、資料發送和巨集指令的發送與執行都達到預期要求。下面是兩個程式同時運行後的螢幕顯示。 圖7.7 伺服器和客戶間的動態資料交換示例 7.4.4 小結 剪貼板和DDE是Windows下資料通信的兩種方法。Delphi以簡便、友好的方式實現了相應的功能,爲用戶編程提供了方便。一般說來,剪貼板多用於靜態資料傳輸,而DDE用於動態資料交換、控制其他程式運行等場合。這些內容對於多用戶環境下的程式開發是很重要的。 ===================== 備註: (1)DDE一個基礎的WINDOWS應用程式通訊協定,動態資料交換(DDE)爲WINDOWS 應用程式相互通信提供了一個杠架,使 客戶和伺服器之間開通會話,一次DDE會話(conversation)是指兩個合作應用程式從連通到結束的會話期,這兩 個應用程式必須都在運行,儘管運行前必有一定的準備。一個DDE對話必須有主題,一個最普通主題 的例子就是檔案名,MICROSOFT 認爲OLE大有前途,不鼓勵使用DDE,但有些事必須使用DDE來作。 (2)現在人都在用ole, (3)如果資料通訊的兩方都是你自己做的,那麽就不要用DDE了,好煩的,效率也不高,用WM_COPYDATA 消息要快得多,當然,如果面向工業控制,有些設備提供的就是DDE介面,那就不得不用了 ********************************************************* 哈哈&兵燹 最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好 Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知 K.表Knowlege 知識,就是本站的標語:Open our mind to make knowledge together! 希望能大家敞開心胸,將知識寶庫結合一起
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-05-06 11:30:51
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!