總則
打開Delphi 5 (或更早版本)的工程,新版本會自動對其進行升級。以下將要介紹的是新版本中可能會對現有的Delphi工程帶來潛在影響的一些改動。
IDE(集成開發環境)特性
包名稱的自動更新
兼容性問題
想要了解更多其他信息,請參考”Delphi6新特性”這一部分的內容。
兼容性問題
以下列出的是可能影響你的Delphi應用程序的幾個大的方面:
一. 由於VCL體系結構的變化而引起的Provider和Client Dataset 的一些事件的變動
TCustomClientDataSet的引入,使得Delphi 5或早期版本中的事件處理機制有些改動。
DBCLIENT.PAS單元中有5種類型的6個事件發生了變化,他們分別是:
事件類型 變化
TResolverErrorEvent 影響到provider的 OnUpDateError 事件。
TBeforeUpdateRecordEvent 影響到provider的 BeforeUpdateRecord事件。
TAfterUpdateRecordEvent 影響到provider的 AfterUpdateRecord事件。
TProviderDataEvent 影響到provider的 OnGetData and OnUpdateData事件。
TReconcileErrorEvent 影響到client dataset的 OnReconcileError 事件。
必須將以上提到的這些事件對應的處理函數(過程)中的TClientDataSet替換為TCustomClientDataSet。
二.使用默認數據庫登錄的代碼的變動
原先,將一個連接組件(比如 Tdatabase,TADOConnection,或TDCOMConnection)的LoginPrompt屬性設置為True,則會有默認的登錄對話框彈出。這一特性已經不再保留除非你在單元引用中增加一個引用DBLogDlg的語句。如果想要應用程序仍然能夠彈出默認的登錄對話框,務必加上 Use DBLogDlg這麼一句,否則便不會有任何提示輸入用戶名和密碼的對話框出現。
三.潛在的二進制Form文件的不兼容
過去,新版本Delphi創建的二進制Form文件(或稱DFM文件)可以被老版本的Delphi讀取。但是現在不行了。某些二進制Form文件可能不能被老版本正確的讀取,其原因是Delphi 6內部的字符串的流化和原先不同。過去,流化操作假設一個本地特殊的字符集。而現在新的流化操作假設字符集為UTF-8。由此帶來的問題就是,如果Delphi 6的二進制Form文件中包含有碼值大於127的字符出現(比如版權符®),則該文件就不能被Delphi 的老版本正確讀取。
如果你想在老版本的Delphi 中打開Delphi 6 的Form文件,那麼請先將該Form文件存為文本格式而非二進制格式。
四.有關可賦值的常量
編譯宏$WRITEABLECONST現在的缺省值為關(OFF),這是為了防止在Delphi的工程中運用可賦值的常量。可賦值的常量,也就是定義一個常量,但是卻允許在運行期間改變其值。例子如下:
const
foo: Integer = 12;
begin
foo := 14;
end.
在以往的Delphi版本中,有這麼一個特性:常量不是真正的常量。使用編譯宏$WRITEABLECONST OFF,則以上的代碼中Foo的賦值將引發一個編譯錯誤。若要避免這個錯誤,可將Foo的聲明改為 var。
將常量用作一個可以初始化的局部變量,這樣的代碼如下:
procedure MyProc;
const
somedata: Integer = 12;
begin
Inc(somedata, 3);
end;
現在你要做的是將局部常量的聲明移到過程的外部,使其成為一個全局的變量。然後代碼變為:
var
somedata: Integer = 12;
procedure MyProc;
begin
Inc(somedata, 3);
end;
對於過度依賴於常量的代碼(比如ActiveX 控件的包裝器),可以通過在源文件中插入一個{$WRITEABLECONST ON}的編譯命令來修正。這一特性,在RTL, VCL, CLX,和 DB 等核心的源代碼中被禁止使用,但是在周邊的單元比如ActiveX 控件的包裝器中倒可以接受。
總而言之,你應該意識到“可賦值的常量”這個說法的自相矛盾性。Delphi的以往版本中的這一特性,只是為了與老的16位的編譯器的兼容而保留,但現在對於Delphi的開發者來說這已經毫無意義了。另外,要養成好的編程習慣,應當盡量避免使用“可賦值的常量”。
五.Cardinal類型的負數值
過去,Delphi處理Cardinal類型的負數值時使用32位的機制,這樣使得結果為一些零頭的值(Cardinal類型允許的最大的值與當前值的差加一)。例子如下:
var
c: Cardinal;
i: Int64;
begin
c := 4294967294;
i := -c;
WriteLn(i);
end;
在以往版本的Delphi中,I的值應當是2。但是現在就不是這樣的了。在Delphi 6中,Cardinal類型是先轉化為64位的有符號類型,然後做取負數值的運算,所以最終結果I的值為-4294967294。
可能有些代碼依賴於原先錯誤的Cardinal負數值的實現方法,所以希望讀者對於Delphi 的這一新特性引起足夠的重視。花足夠多的時間來檢驗你的代碼中是否存在對Cardianl類型的值取負數的情況是很值得的,同時確信一點,Delphi的這個新的特性對你的程序的正確性不構成影響。
六.單元DsgnIntf改名及相關變化
程序中對於DsgnIntf的引用,需要改為對一個新的單元的引用:DesignIntf。可能還得加上DesignEditors、Editors 和RTLConsts 幾個單元到你的引用列表中。除此之外你還得將designide加入到你的包的Requires的列表中。另外,對dsnide50的引用可能得手動改為DesignIde,如果Delphi沒有自動更改的話。
任何引用了IDesigner的運行期包,需要改為IDesignerHook以防止運行期時對於designide單元的引用要求。在運行期代碼中,IDesignerHook 功能足夠使用,無需擔心。設計期時可以使用IDesigner,如以下代碼一樣:
var
RealDesigner: IDesigner;
...
SomeDesignerHook.QueryInterface(IDesigner,RealDesigner);
...
來獲得IDesignerHook 提供的IDesigner的接口。IDesinerHook的使用只需要引用Classes和Forms兩個單元。但是IDesigner還得加上DesignIntf單元,由於該單元被包含在許多其它包中,而其中的一些包可能是不能二次分發的。
七.有關組件編輯器的變化
Delphi 6中,TComponentEditor類有了不同的祖先。在Delphi 5中,它從TInterfacedObject
繼承而來;現在它從一個新的類,TBaseComponentEditor繼承而來。同時,TComponentEditorClass也變為TbaseComponentEditor的類類型,而不是TComponentEditor的類類型。這些體系結構上的變化可能需要你修改老的Delphi程序。
八.TDesignWindow 的變化
許多變化都和類TDesignWindow有關。它的聲明被移到單元DesignWindows中,並且FromClosed方法被替換為DesignerClosed。以往,在FromClosed事件中可以通過訪問參數Aform來訪問Form。而在新的事件DesignerClosed中,我們需要通過Designer的Root屬性來訪問Form。
在FormClosed事件中,我們可以通過調用TDesignerSelectionList.Create 或者 TComponentList.Create來創建選擇列表。而在DesignerClosed事件中做同樣操作得使用IDesignerSelections接口。你可以調用CreateSelectionList函數來獲得一個接口。
SelectionClosed方法的參數也和Delphi 5版本中的有所不同。
九.VCL 包的變化
一些VCL相關的包已經被重新分配到其他的包裡。假如你在工程中引用了vcl50.dcp,那麼你需要將這個引用改為引用vcl.dcp和rtl.dcp。
十.OpenGL 接口單元改到rtl.dcp中
Borland OpenGL接口單元(opengl.dcu)在Delphi 5的庫單元目錄中是一個獨立的單元。在Delphi 6中它被合並到rtl.dcp中。這可能導致某些Delphi 5的工程升級到Delphi 6時引發一些問題。
舉個例子來說。在Delphi 5的工程中,可能你會將與OpenGL單元同名的單元放置在工程目錄中,以覆蓋系統提供的OpenGL單元。而在Delphi 6中,假如有任何組件引用了rtl.dcp,則將導致命名沖突,非得更改名稱才行。
十一.HTTPApp.pas 單元中的一些類型聲明移動到 HTTPProd.pas單元中
HTTPApp 單元中的一部分類型被移動到了HTTPProd 單元中。他們是THTMLBgColor,THTMLAlign 和THTMLVAlign。如果你的工程中使用了這些類,那麼需要將引用的單元由HTTPProd改為 HTTPApp 。
十二.Search 單元被刪除,SearchBuf例程做了修改並被移動
單元Search在Delphi 6中不再保留。SearchBuf例程,用來在一個文本的緩沖區中