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

Delphi有沒有辦法替換一個Object的public method?

答題得分者是:aftcast
marklai
一般會員


發表:2
回覆:8
積分:2
註冊:2007-09-03

發送簡訊給我
#1 引用回覆 回覆 發表時間:2011-05-03 16:36:23 IP:183.37.xxx.xxx 訂閱
各位大大,小弟向各位請教一個問題,如果有個class :
TTest = class
...
public
procedure DoSomething(aParam: string);
....
end;

另一個class:

THook = class
...
public
procedure DoSomething(aParam: string);
....
end;

TTest 和THook,有一個一樣的method, DoSomething.

現在有兩個TTest和THook 的Instance,

Test := TTest.Create;
Hook:=THook.Create;

在程式中,有沒有辦法可以用Hook的DoSomething替換Test的DoSomething呢?

我在網上找了很久都沒找到,不知道有沒有大大高人可以指點一下~~萬分感謝~~!!!
sryang
尊榮會員


發表:38
回覆:741
積分:875
註冊:2002-06-27

發送簡訊給我
#2 引用回覆 回覆 發表時間:2011-05-05 07:38:01 IP:211.79.xxx.xxx 訂閱
找不到方法是正常的,因為沒有辦法做
因為這兩個 class 是彼此獨立的,沒有任何的關係
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
marklai
一般會員


發表:2
回覆:8
積分:2
註冊:2007-09-03

發送簡訊給我
#3 引用回覆 回覆 發表時間:2011-05-05 12:40:33 IP:183.37.xxx.xxx 訂閱
多謝sryang,確實兩具class是沒有任何關係,我祇是想試試有沒有類似Hook,或其它方法,可以做到類似的效果,替換掉一個class object的method.
===================引 用 sryang 文 章===================
找不到方法是正常的,因為沒有辦法做
因為這兩個 class 是彼此獨立的,沒有任何的關係
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2011-05-05 13:51:00 IP:210.64.xxx.xxx 訂閱
很好奇會有這樣的應用?   你最終目的到底是什麼?

你這個想法是一定到不了,我極度肯定! 但若改個做法,也許可以達成你最終的目的,但重點是你的最終目的你沒說…

===================引 用 marklai 文 章===================
多謝sryang,確實兩具class是沒有任何關係,我祇是想試試有沒有類似Hook,或其它方法,可以做到類似的效果,替換掉一個class object的method.
===================引 用 sryang 文 章===================
找不到方法是正常的,因為沒有辦法做
因為這兩個 class 是彼此獨立的,沒有任何的關係
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
marklai
一般會員


發表:2
回覆:8
積分:2
註冊:2007-09-03

發送簡訊給我
#5 引用回覆 回覆 發表時間:2011-05-05 16:02:00 IP:183.37.xxx.xxx 訂閱
多謝aftcast 的關注!

我之所以會有這個想法,其實是因為我的專案是用delphi 2007做的,要求support unicode,所以用了比較舊的免費版Tnt controls。
專案裡有不少地方直接用了raise Exception.create,來raise exception,這樣會有一個messagebox。但是後來要求這些exception message都要support widestring。
我在VCL sources裡跟蹤了好久,發現有些地方會直接用 Application.ShowException將Exception顯示出來。但是TApplication.ShowException祇是一個普通的method,無法修改。
因為我記得以前在網上曾經看到過,有人可以用特殊的方法,修改一個Object的Private的資料,所以我就想有沒有可能能過某種方法將這個Application.ShowException替換掉。
正如aftcast 你所說的,因為找不到這樣的方法,所以我最後還是放棄了這個想法,另外找方法去代替。

現在我純粹是好奇,想知道有沒有什麼方法可以把一個object的method替換掉。我知道這不是一個正常的需求,這樣其實也是不符合OO的,我祇是好奇,想和大家分享而已。

===================引 用 aftcast 文 章===================
很好奇會有這樣的應用? 你最終目的到底是什麼?

你這個想法是一定到不了,我極度肯定! 但若改個做法,也許可以達成你最終的目的,但重點是你的最終目的你沒說…

===================引 用 marklai 文 章===================
多謝sryang,確實兩具class是沒有任何關係,我祇是想試試有沒有類似Hook,或其它方法,可以做到類似的效果,替換掉一個class object的method.
===================引 用 sryang 文 章===================
找不到方法是正常的,因為沒有辦法做
因為這兩個 class 是彼此獨立的,沒有任何的關係
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#6 引用回覆 回覆 發表時間:2011-05-05 16:21:10 IP:210.64.xxx.xxx 訂閱
瞭解了!

method不能換掉最主要的原因是 物件導向的方法,它隱含了self (在c 叫this) 這個指標參數。
它不像一般的 function pointer 僅4bytes檔指標就可,它至少要是 8bytes,一個是法方的位置,一個是將被帶入的 self 的實例(instance)。換方法的位置可能還有可行性,若要連 instance 的位置也換了,恐不是易事。即時我不敢說100%不行,但只能說若要達成恐要相當的心力去做低階的動態的切換instance 的所在。我對組語熟,都覺得超級的難到可說是近不可能了。

以上也是純討論。


------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
sryang
尊榮會員


發表:38
回覆:741
積分:875
註冊:2002-06-27

發送簡訊給我
#7 引用回覆 回覆 發表時間:2011-05-05 20:16:04 IP:140.115.xxx.xxx 訂閱
樓主,您的問題是有解的。請看以下程式碼:
這是 TApplication.HandleException 的程式碼[code delphi]
procedure TApplication.HandleException(Sender: TObject);
begin
if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
if ExceptObject is Exception then
begin
if not (ExceptObject is EAbort) then
if Assigned(FOnException) then // 當 OnException 事件有處理程式時
FOnException(Sender, Exception(ExceptObject)) // 就執行 OnException 事件
else
ShowException(Exception(ExceptObject)); // 否則執行 ShowException
end else
SysUtils.ShowException(ExceptObject, ExceptAddr);
end;
[/code]
所以您只要撰寫一個 Application.OnException 事件處理程式就可以了。例如:[code delphi]
TMainForm = class(TForm)
procedure OnCreate(Sender: TObject);
public
procedure ApplicationOnException(Sender: TObject; E: Exception);
end;

implementation

// Application.OnException 處理程式
procedure TMainForm.ApplicationOnException(Sender: TObject; E: Exception);
begin
// 在這裡就可以自己顯示例外訊息,例如:
ShowMessage('應用程式出現例外狀況:'#10 E.Message);
end;

procedure TMainForm.OnCreate(Sender: TObject);
begin
// 幫 Application 掛上 OnException 事件
Application.OnException := ApplicationOnException;
end;
[/code]
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
編輯記錄
sryang 重新編輯於 2011-05-05 06:21:26, 註解 無‧
herbert2
尊榮會員


發表:58
回覆:632
積分:878
註冊:2004-04-16

發送簡訊給我
#8 引用回覆 回覆 發表時間:2011-05-05 21:25:01 IP:202.39.xxx.xxx 訂閱
小弟是使用 BCB5, 也有用 Application->OnException = MyErrHandleFunction 達 9 年之久;

只是不知為何, 並非全部的 Exception 都會跑進 MyErrHandleFunction!

不知 S 兄可有遇到這狀況?
sryang
尊榮會員


發表:38
回覆:741
積分:875
註冊:2002-06-27

發送簡訊給我
#9 引用回覆 回覆 發表時間:2011-05-05 21:39:00 IP:140.115.xxx.xxx 訂閱
回 herbert2 網友
如果 Exception 已經被 try except (try catch) 處理掉了,就不會跑到 TApplication.HandleException
有些元件會自己處理 exception,並且在 except (catch) 中顯示錯誤訊息
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
herbert2
尊榮會員


發表:58
回覆:632
積分:878
註冊:2004-04-16

發送簡訊給我
#10 引用回覆 回覆 發表時間:2011-05-05 21:57:13 IP:202.39.xxx.xxx 訂閱
謝謝 S兄!

有自己的 Exception 處理的地方, 確實不會有 Exception 丟到 Application->OnException,
通常自己開發的元件, 都儘可能自行處理 Exception, 或以 Default 值避免不必要的問題.
而至於非自己開發的元件, 確實未詳細去瞭解, 無 Source 者也無從瞭解.
小弟納悶的是, 那些 Exception 看似該丟至 Application->OnException 的,
卻沒被丟來, 所以才有此疑惑!
syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#11 引用回覆 回覆 發表時間:2011-05-06 08:41:31 IP:59.120.xxx.xxx 訂閱
有試過直接修改 物件的成員 Table 嗎?
Table 相關資訊可參考 Inside VCL 或是 Google 一下,若帶入參數不相同的話,會需要額外的處理

===================引 用 aftcast 文 章===================
瞭解了!

method不能換掉最主要的原因是 物件導向的方法,它隱含了self (在c 叫this) 這個指標參數。
它不像一般的 function pointer 僅4bytes檔指標就可,它至少要是 8bytes,一個是法方的位置,一個是將被帶入的 self 的實例(instance)。換方法的位置可能還有可行性,若要連 instance 的位置也換了,恐不是易事。即時我不敢說100%不行,但只能說若要達成恐要相當的心力去做低階的動態的切換instance 的所在。我對組語熟,都覺得超級的難到可說是近不可能了。

以上也是純討論。


aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#12 引用回覆 回覆 發表時間:2011-05-06 14:54:18 IP:210.64.xxx.xxx 訂閱
syntax 好久不見,好像一陣子沒看到你了…

想透過vmt解決這個問題,就如我原來說的,幾乎是不可能。因原就是我說的 self 這個instance該怎麼去取代? 除非把整個process的memory裡,關於doSomething呼叫前的move EAX, [....] (虛碼) 的部份全取代成自己的instance 的self。否則,光是把法方的位址換掉是沒用的。

順便借這個機會讓大家也知道一下,我發現李維的 Inside VCL 講到關於vmt 與self的部份,他寫錯了。page 2-68 中他說 「看到ClassType回傳的結果就是Self指到的目的地」這是錯的,而這個錯還相印證在他page 2-65 圖2-19 上。(註2)
依我的研究,正確的是 : 「看到ClassType回傳的結果就是Self指到的目的地的地址」,差三個字整個觀念就差很多,而且他有點不像是誤寫,因為連他的圖2-19也印證他當時想法"也許"是錯的。(註2)

圖2-19應該改成

Foo :

ptrToVmt : Pointer // 隱藏的
aStr
aField


instance(或有人喜歡叫object)的self是指向instance的開頭位址,而那個開頭的地方其實放的是一個指標(就是上面我打的 ptrToVmt,這個名稱是我自己說的,文件上沒有看到)。而這個隱形指標則指向vmt的開始位址。

所以圖應該是 self --> ptrToVmt -> vmt 而不是李維所畫的,self--> vmt 。

如果是self --> vmt 那整個物件的概念就全會亂掉,錯掉。 self 當然是指向 instance 本身的。

註1: 事實上 delphi的 self 比較機車一點,他還有另一個意思,是用在class function的,在那裡,self 就是指向 vmt 的所在。然而,instance上的觀念則不一樣,不能混為一談!

註2: 剛打完後,突有個想法,也許李維的那個圖是沒錯的。是否他用self 來表我所講的ptrToVmt,若是如此,太容易混淆。 雖然他也許交插的用註1的觀念,但該圖講的是instance,而非class。加上他在page 2-68上的文字部份,會讓人有很大的誤會!




===================引 用 syntax 文 章===================
有試過直接修改 物件的成員 Table 嗎?
Table 相關資訊可參考 Inside VCL 或是 Google 一下,若帶入參數不相同的話,會需要額外的處理




------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2011-05-06 01:18:23, 註解 無‧
aftcast 重新編輯於 2011-05-06 01:25:58, 註解 無‧
aftcast 重新編輯於 2011-05-06 01:28:25, 註解 無‧
marklai
一般會員


發表:2
回覆:8
積分:2
註冊:2007-09-03

發送簡訊給我
#13 引用回覆 回覆 發表時間:2011-05-20 10:53:03 IP:183.37.xxx.xxx 訂閱
多謝 sryang 的回覆,你所說的方法,其實我已經試過。這個方法可以在一定程度上解決問題,但其實有點小問題,我覺得並不是完美的方法。
當在專案的某個地方,例如MainForm,加上一個TApplicationEvents的component,在TAppliationEvents的OnException寫入程式碼,想另外特別處理Exception的時候,會發現這個OnException根本就用不到,仍然會跑到MainForm的ApplicationOnException中。

原因在於,AppEvnts這個unit在initialization的部分,會create一個TMultiCaster的object,所有TAppliationEvents在Create的時候,都會將自己加入到MultiCaster中.而MulitCaster恰恰就是會替換掉Application.OnException event。

[code delphi]
constructor TMultiCaster.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FAppEvents := TComponentList.Create(False);
with Application do
begin
OnActionExecute := DoActionExecute;
OnActionUpdate := DoActionUpdate;
DoActivate;
DoDeactivate;
OnException := DoException;
DoHelp;
OnHint := DoHint;
OnIdle := DoIdle;
DoMessage;
OnMinimize := DoMinimize;
OnRestore := DoRestore;
DoShowHint;
OnShortCut := DoShortcut;
OnSettingChange := DoSettingChange;
OnModalBegin := DoModalBegin;
OnModalEnd := DoModalEnd;
end;
end;

[/code]
而在TMultiCaster的DoException可以看到,TMultiCaster會檢查所有的ApplicationEvents有否有處理OnException,如果有就會Call ApplicationEvents的OnException,否則,就直接Call Application.ShowException。

[code delphi]
procedure TMultiCaster.DoException(Sender: TObject; E: Exception);
var
I: Integer;
FExceptionHandled: Boolean;
begin
BeginDispatch;
FExceptionHandled := False;
try
for I := Count - 1 downto 0 do
begin
if Assigned(AppEvents[I].OnException) then
begin
FExceptionHandled := True;
AppEvents[I].DoException(Sender, E);
if FCancelDispatching then Break;
end;
end;
finally
if not FExceptionHandled then
if not (E is EAbort) then
Application.ShowException(E);
EndDispatch;
end;
end;

[/code]

所以,如果使用這個方法的話,日後如果在專案的其它地方使用了TApplicationEvents,想另外處理Exception的話,可能就會無法處理。

因為TMulitcaster是在AppEvnts的Implementation中。在其它unit根本無法得到TMulticaster,所以MainForm上的ApplicationOnException也無法由Multicaster去找到專案中的其它TApplicationEvents。我曾經嘗試過這樣做,不過最終都不成功。或者有前輩可以指點一下是不是有方法可以這樣做。

另外,如果日後在專案的某個地方,如果加入的TApplicationEvents是在MainForm Create之後,那麼,可能就會出現,MainForm上的AppliationOnException反而無效,因為已經被後來的MultiCaster替換掉Application.OnException。
這樣的話,其實是有點混亂的。
我最後使用的方法,是在專案開始的地方,先加入一個TApplicationEvents,用這個TApplicationEvents的OnException去處理,我始終覺得這並不是一個完美的方法。

因為看到TMulticaster對於未被處理的Exception會直接call Application.ShowException,所以我就想,最好是能替換掉Application.ShowException這個Method。這樣的話,我們可以放心的使用類似下面的程式碼:


[code delphi]
procedure ABC;
begin
if ..... then
raise EUniCodeException.Create('UniCode Message')
end;

procedure CallABC;
begin
ABC;
ShowMessage('OK');
end;
[/code]


在CallABC中,沒有用try except去處理exception,不管有沒有用TApplicationEvents,或者有沒有替換Application.OnException,user都可以正常看到的ABC中產生的unicode Exception message。

我想,如果能夠替換了Application.ShowException,那麼應該是最徹底,最一勞永逸的方法。所有才有這樣一個問題想和大家一起討論分享

sryang
尊榮會員


發表:38
回覆:741
積分:875
註冊:2002-06-27

發送簡訊給我
#14 引用回覆 回覆 發表時間:2011-05-20 11:33:41 IP:118.171.xxx.xxx 訂閱
marklai 網友,這種狀況的話,要請您在掛上 Application.OnException 時儲存原來的 Application.OnException (例如叫做 OldAppOnException)
而在你的 ApplicationOnException 處理常式中,要檢查 OldAppOnException 是否被 Assigned
如果有就執行他,這樣就會接回 TMultiCaster 的處理了

[code delphi]
TMainForm = class(TForm)
procedure FormCreate(Sender: TObject);
private
OldAppOnException: TExceptionEvent; // 儲存舊的 Application.OnException 處理常式
public
procedure ApplicationOnException(Sender: TObject; E: Exception);
end;

implementation

// Application.OnException 處理程式
procedure TForm1.ApplicationOnException(Sender: TObject; E: Exception);
begin
// 在這裡就可以自己顯示例外訊息,例如:
ShowMessage('應用程式出現例外狀況:'#10 E.Message);

// 接回原先的例外處理常式
if Assigned(OldAppOnException) then
OldAppOnException(Sender, E);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
// 幫 Application 掛上 OnException 事件
OldAppOnException := Application.OnException;
Application.OnException := ApplicationOnException;
end;
[/code]
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
編輯記錄
sryang 重新編輯於 2011-05-19 21:44:27, 註解 無‧
sryang 重新編輯於 2011-05-19 21:52:38, 註解 補充程式碼‧
marklai
一般會員


發表:2
回覆:8
積分:2
註冊:2007-09-03

發送簡訊給我
#15 引用回覆 回覆 發表時間:2011-05-20 12:18:27 IP:183.37.xxx.xxx 訂閱
非常感謝aryang你的關注,你說得很對。 但是如果當我們指定Application.OnException的時候,TMulticaster還沒有被create,而是後來才create的,那我們儲存的那個OldApplicationOnException就會無效了,因為TMulitcaster替換前並不會檢查是否已經Assigned Application.OnException。
還有一個,就是如果有其它地方直接Call Appliation.ShowException的情況,當然,可能這種情況非常少見。
正如之前說的,解決一個問題可能可以有多種上途徑,其實,對於我最初的Exception處理的問題,論用Assign Application.OnException或者TApplicationEvents都可以解決大部分的問題,這已經足夠了,哪種方法其實都可以選擇使用。我祇是覺得,替換掉Application.OnException要比替換掉Application.ShowException容易得多(當然,我是假設可以替換掉ShowException ),如果可以替換掉ShowException,那麼,我們的處理方法就比較不容易被破壞了。

我最後祇是想知道有沒有可能去替換一個Object的Method,這個問題,其實或許沒有什麼實用價值,祇是我覺得挺有趣而已。
編輯記錄
marklai 重新編輯於 2011-05-19 22:41:33, 註解 無‧
sryang
尊榮會員


發表:38
回覆:741
積分:875
註冊:2002-06-27

發送簡訊給我
#16 引用回覆 回覆 發表時間:2011-05-20 12:37:18 IP:118.171.xxx.xxx 訂閱
TMulticaster 的 Create 動作,是放在 AppEvnts 單元的 initialization 區段
[code delphi]
initialization
GroupDescendentsWith(TCustomApplicationEvents, Controls.TControl);
MultiCaster := TMultiCaster.Create(Application);
[/code]
只要你的主程式有 uses AppEvnts,就會在主程式載入記憶體時,執行到 initialization 區段中的程式
所以,在 Form 執行 OnCreate 事件時,MultiCaster 物件就是已經建立好的了
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
marklai
一般會員


發表:2
回覆:8
積分:2
註冊:2007-09-03

發送簡訊給我
#17 引用回覆 回覆 發表時間:2011-05-20 12:51:14 IP:183.37.xxx.xxx 訂閱
多謝sryang,我當然知道uses Appevnts就會建立MultiCaster,但是如果是專案不祇一個Exe,是由Exe和bpl,dll組成, 而exe 並沒有用TApplicationEvents,而是有其它runtime時在後期再加入的package中才用到TApplicationEvents,是不是有可能在MainForm create之後再有TMultiCaster.Create 呢?我沒有試過這種情況,所以我不確定會不會出現我說的情況,當然這些都可以處理。例如,在Exe中uses AppEvnts就可以確保不會了出現。我想說,替換Application.OnException要做哪些善後處理,我們都可以做得好好,可以慢慢完善,所以這些並不是主要的問題。

我很多謝
sryang你的關注,但是我現在關心的並不是怎樣處理Application.OnException去處理Exception,祇是想知道有沒有辦法去替換一個Object的Method.

我記得好久之前曾經在網上看到過,用特別的方法,好像是用pointer,再用直接read / write memory的方法去取得和修改某個Object 的Private 內容。 如果是在一般的物件導向層面上我覺得應該是不可能去替換Method的,祇是好奇想知道有沒有網友知道方法而已。 我不熟悉組語,前面看aftcast從組語的層面說到不可能做到,我想可能真是不可能做到的。呵呵
編輯記錄
marklai 重新編輯於 2011-05-19 22:54:56, 註解 無‧
marklai 重新編輯於 2011-05-19 23:06:59, 註解 無‧
marklai
一般會員


發表:2
回覆:8
積分:2
註冊:2007-09-03

發送簡訊給我
#18 引用回覆 回覆 發表時間:2011-05-20 13:19:13 IP:183.37.xxx.xxx 訂閱
多謝syntax和affcast ,我曾經想過可能要從vmt上做手腳,不過不知道怎麼試驗。我很喜歡Inside VCL這本書,到無奈對組語不熟悉,所以書中很多用組語的地方,都只是部分看得懂,部分看不懂。曾經都想學一下組語,但總是覺得太過難,太多細節的東西要記住,所以最的都沒學會,就是知道一點皮毛。有機會一定要好好向affcast你請教呀!

===================引 用 aftcast 文 章===================
syntax 好久不見,好像一陣子沒看到你了…

想透過vmt解決這個問題,就如我原來說的,幾乎是不可能。因原就是我說的 self 這個instance該怎麼去取代? 除非把整個process的memory裡,關於doSomething呼叫前的move EAX, [....] (虛碼) 的部份全取代成自己的instance 的self。否則,光是把法方的位址換掉是沒用的。

順便借這個機會讓大家也知道一下,我發現李維的 Inside VCL 講到關於vmt 與self的部份,他寫錯了。page 2-68 中他說 「看到ClassType回傳的結果就是Self指到的目的地」這是錯的,而這個錯還相印證在他page 2-65 圖2-19 上。(註2)
依我的研究,正確的是 : 「看到ClassType回傳的結果就是Self指到的目的地的地址」,差三個字整個觀念就差很多,而且他有點不像是誤寫,因為連他的圖2-19也印證他當時想法"也許"是錯的。(註2)

圖2-19應該改成

Foo :

ptrToVmt : Pointer // 隱藏的
aStr
aField


instance(或有人喜歡叫object)的self是指向instance的開頭位址,而那個開頭的地方其實放的是一個指標(就是上面我打的 ptrToVmt,這個名稱是我自己說的,文件上沒有看到)。而這個隱形指標則指向vmt的開始位址。

所以圖應該是 self --> ptrToVmt -> vmt 而不是李維所畫的,self--> vmt 。

如果是self --> vmt 那整個物件的概念就全會亂掉,錯掉。 self 當然是指向 instance 本身的。

註1: 事實上 delphi的 self 比較機車一點,他還有另一個意思,是用在class function的,在那裡,self 就是指向 vmt 的所在。然而,instance上的觀念則不一樣,不能混為一談!

註2: 剛打完後,突有個想法,也許李維的那個圖是沒錯的。是否他用self 來表我所講的ptrToVmt,若是如此,太容易混淆。 雖然他也許交插的用註1的觀念,但該圖講的是instance,而非class。加上他在page 2-68上的文字部份,會讓人有很大的誤會!




===================引 用 syntax 文 章===================
有試過直接修改 物件的成員 Table 嗎?
Table 相關資訊可參考 Inside VCL 或是 Google 一下,若帶入參數不相同的話,會需要額外的處理




aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#19 引用回覆 回覆 發表時間:2011-05-20 13:27:44 IP:122.126.xxx.xxx 訂閱
如果方法要可以被取代,前題是你必需還是要用TApplication 來實作另一個方法。但這與你開始說的,用不同的物件的方法來取代,我想幾近不可能(不是做不到,而是要做到可能花上浩大的程式)。

如果你可以接受不使用別的物件,而是使用TApplication,那解法就有,而且算不是很難。

宣告一個類似如下的函式(非方法喔,前面沒有 類別:: )

int __fastcall MyNewException(TApplication *self, Exception* E)
{
//這裡搞自己的做法
}

然後用將原來的方法的thunk換成上面的那個thunk。

註: thunk由 oxE9 法方位移值 組成的 5個bytes結構,0xE9 這個機器碼表是組語之 JMP

註2: 我已對delphi的語法不熟了,用的是c 的用法,但原理是同樣的。


===================引 用 marklai 文 章===================

我記得好久之前曾經在網上看到過,用特別的方法,好像是用pointer,再用直接read / write memory的方法去取得和修改某個Object 的Private 內容。 如果是在一般的物件導向層面上我覺得應該是不可能去替換Method的,祇是好奇想知道有沒有網友知道方法而已。 我不熟悉組語,前面看aftcast從組語的層面說到不可能做到,我想可能真是不可能做到的。呵呵
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2011-05-19 23:35:47, 註解 無‧
aftcast 重新編輯於 2011-05-19 23:39:27, 註解 無‧
marklai
一般會員


發表:2
回覆:8
積分:2
註冊:2007-09-03

發送簡訊給我
#20 引用回覆 回覆 發表時間:2011-05-20 14:04:15 IP:183.37.xxx.xxx 訂閱
非常感激aftcast你的回覆,不好意思,有些地方我不是太懂。希望你不要介意。

“如果你可以接受不使用別的物件,而是使用TApplication,"<--不用別的物件當然沒有問題,能用一般的函式其實我覺得更好。因為我知道instance的方法,和一般的函式不一樣,所以我想當然的以為同樣用一個instance的方法去替換另一個instance的方法會比較容易。可能是我想錯了。聽到你說不算很難我覺得看到希望了,呵呵。

另外,比如我要替換的就是Application.ShowException這個方法,
“然後用將原來的方法的thunk換成上面的那個thunk。“<-----“原來方法”是指原來的Appliatino.ShowException這個方法嗎?我不明白怎麼樣“換thunk”呢

“註: thunk由 oxE9 法方位移值 組成的 5個bytes結構,0xE9 這個機器碼表是組語之 JMP”<---這個我猜想,你是不是要jump到我們自己的MyNewException裡?這個是要用組語來實做嗎?這個在什麼時候去做呢?怎麼實做呢?

C 也沒問題,主要是我不太懂這兩行的意思, 這個對我來說似乎有點深奧哦

另外,請問MyNewException這個函式在哪裡使用呢?

===================引 用 aftcast 文 章===================
如果方法要可以被取代,前題是你必需還是要用TApplication 來實作另一個方法。但這與你開始說的,用不同的物件的方法來取代,我想幾近不可能(不是做不到,而是要做到可能花上浩大的程式)。

如果你可以接受不使用別的物件,而是使用TApplication,那解法就有,而且算不是很難。

宣告一個類似如下的函式(非方法喔,前面沒有 類別:: )

int __fastcall MyNewException(TApplication *self, Exception* E)
{
//這裡搞自己的做法
}

然後用將原來的方法的thunk換成上面的那個thunk。

註: thunk由 oxE9 法方位移值 組成的 5個bytes結構,0xE9 這個機器碼表是組語之 JMP

註2: 我已對delphi的語法不熟了,用的是c 的用法,但原理是同樣的。


===================引 用 marklai 文 章===================

我記得好久之前曾經在網上看到過,用特別的方法,好像是用pointer,再用直接read / write memory的方法去取得和修改某個Object 的Private 內容。 如果是在一般的物件導向層面上我覺得應該是不可能去替換Method的,祇是好奇想知道有沒有網友知道方法而已。 我不熟悉組語,前面看aftcast從組語的層面說到不可能做到,我想可能真是不可能做到的。呵呵
中雨
一般會員


發表:8
回覆:5
積分:7
註冊:2006-07-09

發送簡訊給我
#21 引用回覆 回覆 發表時間:2011-06-15 17:14:04 IP:218.5.xxx.xxx 未訂閱
这个其实不难实现,替换掉方法的内存地址就可以了。

我写了一段测试代码,你看下是不是你想要的:-)


[code delphi]
type
TTest = class
public
procedure DoSomething(aParam: string);
end;

THook = class
public
procedure DoSomething(aParam: string);
end;

TJMPCode = packed record
JMP: Byte;
Distance: Integer;
end;


procedure ReplaceMethod(AOldMethod, ANewMethod: Pointer);
var
AProtect: Cardinal;
ANewCode: TJMPCode;
begin
if not VirtualProtect(AOldMethod, 5, PAGE_EXECUTE_READWRITE, AProtect) then
RaiseLastOSError;

ANewCode.JMP := $E9;
ANewCode.Distance := PChar(ANewMethod) - PChar(AOldMethod) - 5;
Move(ANewCode, AOldMethod^, 5);
if not VirtualProtect(AOldMethod, 5, AProtect, AProtect) then
RaiseLastOSError;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
ATest: TTest;
AHook: THook;
begin
ATest := TTest.Create;
AHook := THook.Create;
try
ATest.DoSomething('');
ReplaceMethod(@TTest.DoSomething, @THook.DoSomething);
ATest.DoSomething('');
finally
ATest.Free;
AHook.Free;
end;
end;

{ TTest }

procedure TTest.DoSomething(aParam: string);
begin
ShowMessage('TTest.DoSomething!');
end;

{ THook }

procedure THook.DoSomething(aParam: string);
begin
ShowMessage('THook.DoSomething!');
end;

[/code]

inungh
初階會員


發表:0
回覆:27
積分:25
註冊:2011-06-19

發送簡訊給我
#22 引用回覆 回覆 發表時間:2011-06-25 20:37:00 IP:173.178.xxx.xxx 訂閱
 Did you try CAST?
In Delphi, you can use CAST to use one class as other class.


Inung
------
Inung Huang
系統時間:2017-10-23 17:37:51
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!