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

如何更新內建 VCL 元件

 
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-05-28 16:33:05 IP:61.231.xxx.xxx 未訂閱
先說明,小弟是使用 BCB5 在應用 TMemIniFile 時發現其 ReadString() 有問題,其他如 ReadSections() 等也有問題,而在 BCB6 中則沒有問題,於是想把 BCB6 中的 inifiles.pas 中有關的部分更新到 BCB5 的 inifiles.pas,再重新組譯 inifiles.pas。 可是,要如何才能將它更新到 VCL50.bpl(VCL50.dpl) 內呢? 不知道有沒有人在 Delphi 或 BCB 中更新過內建的 VCL 元件?
------
http://www.ViewMove.com
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#2 引用回覆 回覆 發表時間:2002-05-29 10:30:03 IP:61.231.xxx.xxx 未訂閱
我找到 TMemIniFile 中可能發生的錯誤, BCB5(inifiles.pas)
procedure TMemIniFile.SetStrings(List: TStrings);
var
  I: Integer;
  S: string;
  Strings: TStrings;
begin
  Clear;
  Strings := nil;
  for I := 0 to List.Count - 1 do
  begin
    S := List[I];
    if (S <> '') and (S[1] <> ';') then
      if (S[1] = '[') and (S[Length(S)] = ']') then
        Strings := AddSection(Copy(S, 2, Length(S) - 2))
      else
        if Strings <> nil then Strings.Add(S);
  end;
end;
BCB6(inifiles.pas)
procedure TMemIniFile.SetStrings(List: TStrings);
var
  I, J: Integer;
  S: string;
  Strings: TStrings;
begin
  Clear;
  Strings := nil;
  for I := 0 to List.Count - 1 do
  begin
    S := Trim(List[I]);
    if (S <> '') and (S[1] <> ';') then
      if (S[1] = '[') and (S[Length(S)] = ']') then
      begin
        Delete(S, 1, 1);
        SetLength(S, Length(S)-1);
        Strings := AddSection(Trim(S));
      end
      else
        if Strings <> nil then
        begin
          J := Pos('=', S);
          if J > 0 then // remove spaces before and after '='
            Strings.Add(Trim(Copy(S, 1, J-1))   '='   Trim(Copy(S, J 1, MaxInt)) )
          else
            Strings.Add(S);
        end;
  end;
end;
現在找到問題了,我只需更新此函式即可,但有誰能告訴我要如何更新內建的 VCL 元件?
------
http://www.ViewMove.com
ccchen
版主


發表:61
回覆:940
積分:1394
註冊:2002-04-15

發送簡訊給我
#3 引用回覆 回覆 發表時間:2002-05-29 16:05:26 IP:163.29.xxx.xxx 未訂閱
引言: 先說明,小弟是使用 BCB5 在應用 TMemIniFile 時發現其 ReadString() 有問題,其他如 ReadSections() 等也有問題,而在 BCB6 中則沒有問題,於是想把 BCB6 中的 inifiles.pas 中有關的部分更新到 BCB5 的 inifiles.pas,再重新組譯 inifiles.pas。 可是,要如何才能將它更新到 VCL50.bpl(VCL50.dpl) 內呢? 不知道有沒有人在 Delphi 或 BCB 中更新過內建的 VCL 元件?
直接更新內建的 VCL 元件我想問題很多, 我也找不到Entry, 但我想即使找到也很難維護,如果只改一個Unit則所有其他相關Unit均會出現Version 問題 以下提供我們修正Source Code之方法,希望能有用 1.以一個New Unit重新宣告 TMemIniFile,並完成修改部分 unit NewIni; interface uses inifiles; type TMemIniFile = class(inifiles.TMemIniFile) <--關鍵行 public procedure SetStrings(List: TStrings);override <--將被修改 end; 2. 於implementation 完成SetStrings 3. 使用時Uses Newini則你的TMemIniFile已被修正 [NOTE] 若有一Unit同時uses inifiles及Newini, 則Newini必須在後
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#4 引用回覆 回覆 發表時間:2002-05-30 10:26:13 IP:61.231.xxx.xxx 未訂閱
感謝 ccchen ,小弟會試試您的方法... 可能還要試一下在 BCB 中如何將
引言: TMemIniFile = class(inifiles.TMemIniFile) <--關鍵行
用對應的 C 作出來。 目前我已經將整個 TMemIniFile 用 C 改寫了,不過,我是另外取一個新的名字 TMyMemIniFile (繼承自 TCustomIniFile)。 在改寫的過程中,我發現 Object Pascal 與 C 有很大的不同,像在 C 中如果是宣告在 private 區,就只有自己可以用,而在 Object Pascal 中,繼承的物件也可以使用,如果您手邊也有 VCL 原始碼的話,可以看看 TMemIniFile 中 Rename 的 procedure ,它就用到 TCustomIniFile 的 private FFileName,這使得我在重寫 TMemIniFile 時無法重作出 Rename。 另外,在 C 中,如果在宣告函式時沒有加上 virtual ,繼承者就無法 override ,但在 Object Pascal 中,繼承者只要加上 override 的字眼就可以 override,不論原物件是否開放 override。這也是我無法繼承 TMemIniFile 只修改 SetStrings 而需要整個改寫的原因,在 C 中 TMemIniFile 的 SetStrings 並沒有 virtual 的字眼。
class DELPHICLASS TMemIniFile;
class PASCALIMPLEMENTATION TMemIniFile : public TCustomIniFile 
{
        typedef TCustomIniFile inherited;
public:
        void __fastcall SetStrings(Classes::TStrings* List);
};
看來好像 Object Pascal 的自由度比較大...... 也許等有空時,研究一下相異性,就轉到 Delphi 的平台也說不定...
------
http://www.ViewMove.com
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#5 引用回覆 回覆 發表時間:2002-05-30 13:14:34 IP:61.231.xxx.xxx 未訂閱
我在 BCB 的專案中新增一個 pascal 的 UNIT NewMemIniFile.pas 如下:
unit NewMemIniFile;    interface    uses SysUtils, Classes, IniFiles;    type    TMemIniFile = class(IniFiles.TMemIniFile)    public    procedure SetStrings(List: TStrings); override;    end;    implementation    procedure TMemIniFile.SetStrings(List: TStrings);
var
  I, J: Integer;
  S: string;
  Strings: TStrings;
begin
  Clear;
  Strings := nil;
  for I := 0 to List.Count - 1 do
  begin
    S := Trim(List[I]);
    if (S <> '') and (S[1] <> ';') then
      if (S[1] = '[') and (S[Length(S)] = ']') then
      begin
        Delete(S, 1, 1);
        SetLength(S, Length(S)-1);
        Strings := AddSection(Trim(S));
      end
      else
        if Strings <> nil then
        begin
          J := Pos('=', S);
          if J > 0 then // remove spaces before and after '='
            Strings.Add(Trim(Copy(S, 1, J-1))   '='   Trim(Copy(S, J 1, MaxInt)) )
          else
            Strings.Add(S);
        end;
  end;
end;    end.
Compile 時出現以下錯誤: [Pascal Error] NewMemIniFile.pas(22): Cannot override a static method [Pascal Error] NewMemIniFile.pas(44): Undeclared identifier: 'AddSection' 第一個錯誤表示無法 override SetStrings(), 所以,還是需要原物件就要宣告 virtual; 其繼承者才能 override。 第二個錯誤我就不太懂了... 因為,我最不懂的是 TMemIniFile = class(IniFiles.TMemIniFile) 所代表的真正意義?是表示這個 TMemIniFile 是繼承 IniFiles.TMemIniFile 還是 取代 呢?因為兩者不是同名嗎?
------
http://www.ViewMove.com
ccchen
版主


發表:61
回覆:940
積分:1394
註冊:2002-04-15

發送簡訊給我
#6 引用回覆 回覆 發表時間:2002-05-30 18:35:50 IP:203.217.xxx.xxx 未訂閱
1.實在很抱歉, 沒注意到SetStrings為Static, 如此就無法Override了. 我原來是用此方法來擴充TDBGrid,TQuery等之功能,並未測試此Cass, 只是理所當然的寫下去了. 2. 另寫一分也是方法, 只是已完成之程式ClassName均須修改了 3. TMemIniFile = class(IniFiles.TMemIniFile)是繼承也是取代,可避免須更改ClassName. 4. 另外將inifiles copy一份到Project中直接修改也是方法, 由於此Unit並無DesignTime 物件,遇到VerSion問題之機會並不多 5.[Pascal Error] NewMemIniFile.pas(44): Undeclared identifier: 'AddSection' 因AddSection為private method, 只能在inifiles.pas中用
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#7 引用回覆 回覆 發表時間:2002-05-31 09:22:41 IP:61.231.xxx.xxx 未訂閱
引言: 1.實在很抱歉, 沒注意到SetStrings為Static, 如此就無法Override了. 我原來是用此方法來擴充TDBGrid,TQuery等之功能,並未測試此Cass, 只是理所當然的寫下去了. 2. 另寫一分也是方法, 只是已完成之程式ClassName均須修改了
沒辦法,如果找不到取代的好辦法,只有這樣作...
引言: 3. TMemIniFile = class(IniFiles.TMemIniFile)是繼承也是取代,可避免須更改ClassName. 4. 另外將inifiles copy一份到Project中直接修改也是方法, 由於此Unit並無DesignTime 物件,遇到VerSion問題之機會並不多
不知道您有沒有用過 BCB,如果在 BCB 中我要使用這個 Class 就要 include 它的 header 檔(在 Delphi 是用 uses),如果我用 TMemIniFile = class(IniFiles.TMemIniFile) 取代或是將整個改後的 infiles.pas 加到我的 project 中(當然目標是名稱相同),這樣在最後 links 的時候 BCB 能知道 TMemIniFile 要去 link 那一個嗎?又如果最後的 .exe 不想包 vcl*.bpl 那會不會與 vcl*.bpl 內的 TMemIniFile 衝突呢?
引言: 5.[Pascal Error] NewMemIniFile.pas(44): Undeclared identifier: 'AddSection' 因AddSection為private method, 只能在inifiles.pas中用
謝謝您的解釋,讓我更了解 Object Pascal。
------
http://www.ViewMove.com
ccchen
版主


發表:61
回覆:940
積分:1394
註冊:2002-04-15

發送簡訊給我
#8 引用回覆 回覆 發表時間:2002-05-31 16:18:55 IP:163.29.xxx.xxx 未訂閱
只在3.0時代用過BCB, 且未用過此方法, 不過我想道理是一樣的 假設在NewUnit.pas中定義TMemIniFile = class(IniFiles.TMemIniFile) 則在NewUnit中須uses(或Include) inifiles 使用時, 在interface part uses NewUnit,實際上會展開, 如同c 亦會展開header中所包含之其他header file 實際上是兩個Unit均link進來, 還是透過inherite關係完成的. 及使Build with RunTime Library,也是沒問題的
dllee
站務副站長


發表:321
回覆:2519
積分:1711
註冊:2002-04-15

發送簡訊給我
#9 引用回覆 回覆 發表時間:2002-08-01 18:14:00 IP:61.231.xxx.xxx 未訂閱
最近 post 了一篇關於讀文字檔速度的問題,後來想使用 TMemo 來取代 TListBox,而在 TMemo 中沒有 TListBox 的 ItemIndex,於是想按 ccchen 的方法,將 TMemo 同名取代,同時加上 ItemIndex 的屬性,初期想先作出可讀,可設,在設的同時將該行反白(也就是選擇),程式碼如下:    
unit MyMemo;    interface    uses Messages, Windows, SysUtils, Classes, Controls, Forms, Menus, Graphics, StdCtrls;    type
  TMemo = class (StdCtrls.TMemo)      protected
    FItemIndex : Integer;
    procedure FSetItemIndex(Value: Integer);      public
    property ItemIndex: Integer read FItemIndex write FSetItemIndex;
  end;    implementation    procedure TMyMemo.FSetItemIndex(Value: Integer);
begin
    FItemIndex := Value;
    Self.SelStart :=SendMessage(Self.Handle, EM_LINEINDEX, FItemIndex, 0);
    Self.SelLength :=Length(Self.Lines.Strings[FItemIndex]);
end;    end.
我把它名為 MyMemo.pas 加入我的 BCB 專案中可以 compile 沒有問題。 不過,當我要使用 Memo1->ItemIndex ,就因沒有 C 的宣告而無法使用,於是再加上物件的宣告:
class PASCALIMPLEMENTATION TMemo : public Stdctrls::TMemo
{
        typedef Stdctrls::TMemo inherited;    protected:
  int FItemIndex;
        void __fastcall FSetItemIndex(int Value);    __published:
        __property int ItemIndex={read=FItemIndex,write=FSetItemIndex};
};
不過,這樣在 compile 時,在 IDE 管理的物件中的 Memo1
class TForm1 : public TForm
{
__published:        // IDE-managed Components
  TMemo *Memo1;
}
會出現 [C Error] LoadFromFileUnit.h(120): E2015 Ambiguity between 'TMemo' and 'Stdctrls::TMemo' 如果手動修改 IDE 自動產生的元件名,那 comiple 時也過不了!! 請問,這樣的方法是否只能在 Delphi 中使用呢?
------
http://www.ViewMove.com
bugmans
高階會員


發表:95
回覆:322
積分:188
註冊:2003-04-12

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-12-07 10:44:23 IP:218.166.xxx.xxx 未訂閱
我找到這篇文章"Delphi 修改 VCL Source Code 需知" http://bbs.ee.ntu.edu.tw/boards/Programming/10/2/13.html 只是手邊沒有Delphi可以實作,有興趣的網友可以試試看是否可行 (0) 備份欲修改部份之 Source Code 以防萬一. (1) 點選 Menu File|New Project 建立一個新的 Project (2) 點選 Menu File|Add File.. 載入欲修改的 VCL Sources Code (3) 設定 Menu Options|Project 下列開關 (否則您的VCL .DCU Size比原本的大一倍都有可能....) Project Options - Compiler Dubugging Group (1) Debug information Turn Off (2) Local symbols Turn Off (3) Symbol info Turn Off Project Options - Linker EXE and DLL options Group (1) Optimize for size and load time Turn ON (2) include TDW debug info Turn OFF (4) 檢查 Unit 中是否已經 Uses 欲修改之 VCL Unit. (5) 以Project Manager再次檢查欲修改的 Source Code Unit是否已 加入 Project 中.加入Project後的Unit會被優先使用,而不再使用 原本\DELPHI\LIB同名的 DCU. (6) 修改完畢後點選Compile|Build All (7) 待完畢無誤後,Close Project.將新產生之 DCU 從 \DELPHI\SOURCE\VCL 搬至 \DELPHI\LIB (8) 點選 Option|Rebuild Library 重新產生 \DELPHI\BIN\COMPLIB.DCL. (9) 撰寫測試程式試之.
系統時間:2024-05-10 11:37:08
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!