form position 的設定 |
答題得分者是:歸木淡
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
請問各位:
一般 MDI 的 FORM 都有一個 FORM.POSITION 可以指定顯示在螢幕上的參數, 那如果是 Application.MessageBox() 這個函數所建立的 Dialog 是否有可能也可以指定位置 ps:我知道有其他的函數有這個功能, 如 MessageDlgPos , 或者自己寫一支也可以, 但這不是我想知道的答案 因為手上有一支程式大量使用Application.MessageBox() 功能, 我只想知道有沒有最快的方式可以達成 另外寫一支同名的 Application.MessageBox, 再用 overload 方式取代也不是我想要知道的, 謝謝各位! |
pedro
尊榮會員 發表:152 回覆:1187 積分:892 註冊:2002-06-12 發送簡訊給我 |
您好
根據,以下所講的 http://www.swissdelphicenter.ch/torry/showcode.php?id=352 我試了一下,在我的環境有用,修改mx及my變數,訊息提示位置就不一樣,不知道在你的環境可不可以用? [code delphi] const mbMessage = WM_USER 1024; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } procedure ChangeMessageBoxPosition(var Msg: TMessage); message mbMessage; public { Public declarations } end; var Form1: TForm1; msgCaption: PChar; // variable to hold the caption const mx=200; my=100; implementation {$R *.dfm} { TForm1 } procedure TForm1.ChangeMessageBoxPosition(var Msg: TMessage); var MbHwnd: longword; MbRect: TRect; x, y, w, h: integer; begin MbHwnd := FindWindow(MAKEINTRESOURCE(WC_DIALOG), msgCaption); if (MbHwnd <> 0) then begin GetWindowRect(MBHWnd, MBRect); with MbRect do begin w := Right - Left; h := Bottom - Top; end; // center horzontal x := mx; // keep on screen if x < 0 then x := 0 else if x w > Screen.Width then x := Screen.Width - w; //center vertical y := my; // keep on screen if y < 0 then y := 0 else if y h > Screen.Height then y := Screen.Height - h; // set new windows position SetWindowPos(MBHWnd, 0, x, y, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER); end; end; procedure TForm1.Button1Click(Sender: TObject); begin PostMessage(Handle, mbMessage, 100, 0); msgCaption := 'Confirm'; if Application.MessageBox('Has our MessageBox moved ?',msgCaption,MB_ICONQUESTION or MB_YESNO)=IDYES then begin end; end; [/code]
編輯記錄
pedro 重新編輯於 2009-09-04 17:07:19, 註解 無‧
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
|
歸木淡
中階會員 發表:1 回覆:49 積分:75 註冊:2005-09-07 發送簡訊給我 |
|
pedro
尊榮會員 發表:152 回覆:1187 積分:892 註冊:2002-06-12 發送簡訊給我 |
的確在整合入現有的程式有點麻煩
我嘗試放在ApplicationEvent裡 或如您所述放在oncreate及onshow都不行 還要再想想 或試一下歸木淡的建議 ===================引 用 P.D. 文 章=================== 感謝 P兄提供的方式, 我按表操課, 試了一下, 確實可以改變 Application.MessageBox 的位置 但現在有一個問題是 這支程式有數十支MessageBox, caption 不盡相同, 這樣的做法, 我必須在每一個Application 前加上?PosMesage 的動作 我嘗試放在一啟動(oncreate)或 (onactive)上, 就沒有辦法調位置了, 是否能有下一次動作, 之後的Application.MessageBox都可以變成我想要的位置的方式?
編輯記錄
pedro 重新編輯於 2009-09-06 22:09:47, 註解 無‧
|
歸木淡
中階會員 發表:1 回覆:49 積分:75 註冊:2005-09-07 發送簡訊給我 |
封裝好了, 在project中uses wcMessageboxEx;即可.
剛開始時處理的是HCBT_CREATEWND, 浪費了不少時間, 後來發現應該是HCBT_ACTIVATE [code delphi] unit wcMessageboxEx; interface uses Windows, Forms; procedure InstallHook; procedure UninstallHook; var MessageBoxLeft: integer = 100; MessageBoxTop: integer = 100; AllowReposition: boolean = true; implementation var hCBTHook: HHOOK = 0; function GetWindowClassName(hwnd: THandle): string; var ps: array[0..254] of Char; begin GetClassName(hwnd, ps, 255); result:=ps; end; function MessageBoxHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin if AllowReposition and (Code = HCBT_ACTIVATE) and (GetParent(wParam) = Application.Handle) and (GetWindowClassName(wParam) = '#32770') then SetWindowPos(wParam, HWND_TOP, MessageBoxLeft, MessageBoxTop, 0, 0, SWP_NOACTIVATE SWP_NOOWNERZORDER SWP_NOSIZE SWP_NOZORDER); Result:=CallNextHookEx(hCBTHook, Code, wParam, lParam); end; procedure InstallHook; begin if hCBTHook = 0 then hCBTHook := SetWindowsHookEx(WH_CBT, @MessageBoxHookProc, Hinstance, GetCurrentThreadId()); end; procedure UninstallHook; begin if hCBTHook <> 0 then begin UnHookWindowsHookEx(hCBTHook); hCBTHook := 0; end; end; initialization InstallHook; finalization UninstallHook; end. [/code] 關鍵的兩行是 [code delphi] (GetParent(wParam) = Application.Handle) and (GetWindowClassName(wParam) = '#32770') then[/code] 這兩行, 沒有前者則所有的prgram的messagebox都會被改, 沒有一句則dialogs.Showmessage也會被改變. |
Coffee
版主 發表:31 回覆:878 積分:561 註冊:2006-11-15 發送簡訊給我 |
|
RootKit
資深會員 發表:16 回覆:358 積分:419 註冊:2008-01-02 發送簡訊給我 |
HOOK 可能很受傷
也有可能誤改其他的對話視窗,像儲存開啟...... 另一種至換函數作法,直接建立單元引用或放在MainForm http://www.swissdelphicenter.com/torry/showcode.php?id=1422 [code delphi] type TSaveRedir = packed record Addr: Pointer; Bytes: array[0..4] of Byte; end; PSaveRedir = ^TSaveRedir; procedure RedirectCall(FromAddr, ToAddr: Pointer; SaveRedir: PSaveRedir); var OldProtect: Cardinal; NewCode: packed record JMP: Byte; Distance: Integer; end; begin if not VirtualProtect(FromAddr, 5, PAGE_EXECUTE_READWRITE, OldProtect) then RaiseLastWin32Error; if Assigned(SaveRedir) then begin SaveRedir^.Addr := FromAddr; Move(FromAddr^, SaveRedir^.Bytes, 5); end; NewCode.JMP := $E9; NewCode.Distance := PChar(ToAddr) - PChar(FromAddr) - 5; Move(NewCode, FromAddr^, 5); if not VirtualProtect(FromAddr, 5, OldProtect, OldProtect) then RaiseLastWin32Error; end; procedure UndoRedirectCall(const SaveRedir: TSaveRedir); var OldProtect: Cardinal; begin if not VirtualProtect(SaveRedir.Addr, 5, PAGE_EXECUTE_READWRITE, OldProtect) then RaiseLastWin32Error; Move(SaveRedir.Bytes, SaveRedir.Addr^, 5); if not VirtualProtect(SaveRedir.Addr, 5, OldProtect, OldProtect) then RaiseLastWin32Error; end; // Example: Replace Application.MessageBox with your own. function MyNewMessageBox(Self: TApplication; const Text, Caption: PChar; Flags: Longint): Integer; begin ShowMessage('New Messagebox'); //.... end; procedure TForm1.Button1Click(Sender: TObject); begin Application.MessageBox('You'll never see this Text / Diesen Text wirst du nie sehen', '...', MB_OK); end; var S: TSaveRedir; initialization RedirectCall(@TApplication.MessageBox, @MyNewMessageBox, @S); finalization UndoRedirectCall(S); [/code] 參考。 |
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
個人推rookit所講的這種方式。看到DELPHI裡有人寫出這樣低階的程式,真的感動! 忍不住想補充一下…當然直接抄就可以用了…
這樣的方式應該是最佳的,因為真的是有深入的內含在其中… 首先要了解的是在呼叫vcl函式時,比如說 foo ( ) ,它的組語是像 call 0x00044123 其中後面的位址就是 foo 的位址所在。但是… 0x00044123 這個地方放的卻不是foo裡的程式碼而是再跳到另一個真正的 foo 的程式碼,這種再跳的概念又稱 thunk。 那到底這個址方放的是啥東西… 就是一個5bytes的機器碼。以組語來說像是 JMP DWORD PTR [XXXXXXXX] 以機器言語來說就是 E9 XXXXXXXX 其中 XXXXXXXX這個數值表示真的放foo程式碼的地方。 E9這個值(又稱opcode)就是對應到組語的 jmp near rel32的格式。 我把概念圖放上來參考 了解thunk的原理後,大概可以知道那程式的寫法是如何的原理。 1/ VirtualProtect 這個api是用來解除 虛擬記憶體的寫入等權限,要打開才好在MEMORY中插入機器碼 2/ TSaveRedir的第一個成員就是為了要放thunk的位址,而後面的5bytes就是要放該thunk裡面的機器碼(即JMP DWORD PTR [XXXXXXXX] ) 3/ 把原來的先存入TSaveRedir 4/ 找出舊的thunk位址與新的程式位址的差距 5/ 填入E9 位移 的資料在舊的thunk裡 於是…當你呼叫舊的時候候,會先到舊的thunk位址,然後該位置的內容是 E9 位移 (位移是新thunk與舊thunk的差),cpu讀到這裡就jump到新函式的真實程式所在位址 所以整個換的過程,就是讓舊thunk跳至自製程式段。 知道為何是5 了吧? 因為 jmp near 的opcode是 一個byte 即 0xE9 而後面的位移是32位元,所以是4個byte,共5byte 結論: 重點:別以為呼叫vcl function時,是直接到該function的位址執行程式碼。其實他是先跳到一個thunk上,然後再跳一次的! 注意: 經過我實做為bcb的程式過程,發現一般的function是不用thunk的… (難怪昨天我回憶以前好像是這樣)。以前我的自學得到的是加載dll時是用thunk的方式,然後找import table的資料。然而,bpl,它也是dll那類的動態函式庫,所以也用了thunk。
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
taishyang
站務副站長 發表:377 回覆:5490 積分:4563 註冊:2002-10-08 發送簡訊給我 |
|
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
有個問題,我希望有人接手下去…
我一時無法把method的pointer轉成一般的pointer。 delphi真的太方便了,一個@ 就搞定… 下面的程式必需把中斷設在application->messageboxa地方,然後移一下cursor看到它的位址,然後把值設進p裡,然重run一次! ps 會看到我努力的想把method的指標做轉換的失敗過程 ^_^ [code cpp] //--------------------------------------------------------------------------- #include #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; #pragma pack(push, 1) typedef struct tagSaveRedir { void *thunk_addr; BYTE machine_code[5]; }TSaveRedir; typedef struct tagThunkCode { BYTE JMP; int Displacement; }TThunkCode; #pragma pack(pop) void RedirectCall(void *FromAddr, void *ToAddr, TSaveRedir &SaveRedir) { DWORD OldProtect; TThunkCode NewCode; if (!VirtualProtect(FromAddr, 5, PAGE_EXECUTE_READWRITE, &OldProtect)) RaiseLastWin32Error; SaveRedir.thunk_addr = FromAddr; ::memcpy(&SaveRedir.machine_code,FromAddr,5); NewCode.JMP = 0xE9; NewCode.Displacement = (char*)ToAddr - (char*)FromAddr - 5; ::memcpy(FromAddr,&NewCode,5); if(!VirtualProtect(FromAddr, 5, OldProtect, &OldProtect)) RaiseLastWin32Error; } void UndoRedirectCall(TSaveRedir &SaveRedir) { DWORD OldProtect; if (!VirtualProtect(SaveRedir.thunk_addr, 5, PAGE_EXECUTE_READWRITE, &OldProtect)) RaiseLastWin32Error; ::memcpy(SaveRedir.thunk_addr,SaveRedir.machine_code,5); if (!VirtualProtect(SaveRedir.thunk_addr, 5, OldProtect, &OldProtect)) RaiseLastWin32Error; } // Example: Replace Application.MessageBox with your own. int __fastcall MyNewMessageBox(TApplication *self, char const *Text, char const *Caption,long Flags) { ShowMessage("New Messagebox"); return 0; //.... } TSaveRedir S; void *p = (void*)0x004025B0; //typedef int (_fastcall TApplication::*MP)(const char *,const char *,int); // //void *t = (void*) ap->MethodAddress("MessageBoxA"); void start(void) { //MP p = TApplication::MessageBoxA; //int pp = p; RedirectCall(p,(void*)MyNewMessageBox,S); //RedirectCall(p,(void*)MyNewMessageBox,S); } void unload(void) { UndoRedirectCall(S); } #pragma startup start #pragma exit unload //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { Application->MessageBoxA("OLD_ONE","OLD_CAP",MB_OK); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { RedirectCall(p,(void*)MyNewMessageBox,S); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button3Click(TObject *Sender) { UndoRedirectCall(S); } //--------------------------------------------------------------------------- [/code]
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
感謝各位大內高手出手相救, rootkit 兄的程式, 老實說小弟能力有限, 實無法看懂, 但我實做是確實是可以把程式中的 Application.MessageBox 給換掉, 不過這並不是我想要的, 因為我不是要換掉程式中的 MessageBox 的訊息, 而是要改變 MessageBox 的位置, 或許能力還不夠, 利用R兄的程式, 我無法改成我想要達到的目的,
再者 淡兄的程式我也實作, 也的確可以操作, 同時也能改變 MessageBox 的位置, 而且直接 uses unit , 在其他的程式中也確實都不用改到任何程式碼, 就令 MessageBox 位置變到指定的位置了, 不過還有一個問題, 因為我這支程式(其實不是我寫的, 有source code), 其中的Application.MessageBox 很多, 我接手的客戶要求Application.MessageBox 的訊息必須出現在該Form呼叫的center, 例如, Form1 中呼叫 Application.MessageBox, 則這個 MessageBox就一定要出現在 Form1 的中間, 又如果 Form1 移動了位置, MessageBox 還是要出現在 新的Form1 的中間, 所以這個位置是隨時會變動的, 以淡兄的程式, 我還在嘗試要如何能以這個 UNIT 取得呼叫該 MessageBox 的 Form 是那一組, 及該 Form 的 width, height 及目前的 left, Top 位置, 這樣我才能算出其正中間的位置 我使用 P 兄的程式來改, 雖然每一個 FORM 上都要加上這段碼, 但至少是可以達到我想要的, 只是相對程式碼多了很多 以下是我改 P兄的程式碼, 有些非相關的我就省略掉了, 這只是其中一支 Pas, 其中還有近100支form 要改 ps. 以下程式碼中 [code delphi] unit P_LoginIB; interface uses Windows, SysUtils, Forms, IBCustomDataSet, IBQuery, IBDatabase, Db, Delay, DBTables, xTable, DiskInfo, Controls, StdCtrls, Mask, Classes, ini, CL_crypt32, DosMove, ExtCtrls, Graphics, Messages; procedure ChangeMessageBoxPosition(var Msg: TMessage); message mbMessage; public { Public declarations } end; var Form_LoginIB: TForm_LoginIB; implementation uses DLLver, U_VarDef, U_Default, UT_SYS, P_Serial {$R *.DFM} PostMessage(Handle, mbMessage, 0, 0); Application.MessageBox('兩次均輸入錯誤' #13 '系統結束',msgCaption,MB_OK); ==>這是原來設計的MessageBox U_VarDef.isNormalClose:= False; U_VarDef.stopRun:= True; .... Form_LoginIB.Close; end [/code] |
歸木淡
中階會員 發表:1 回覆:49 積分:75 註冊:2005-09-07 發送簡訊給我 |
|
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
TO: taishyang
最後我忍不住用硬幹的方法來把 method 指標轉一般指標。因為我們知道無論是哪一種,指標就是指標就是32位元數。型別是讓高階語言在compile時做匹配,必免錯誤。於是…我就用組語來處理囉,試了果然可以,參考看看。 此外,這篇本來是pd兄為了要解決messagebox的位置問題,卻有變稍偏了… 感覺用這方法似乎還要再多動一點手腳才可以答成他要的結果。我一時興奮都把問題的要求要點給忘了@@ 最後pd兄有解答就好… 我算是有點插花 ^_^ 不過透過這樣的順便機會,也希望讓想要了解原理的人,可以借此增進功力了! (程式中有用一些少見的技巧,比如pragma的一些應用等…) [code cpp] #include #pragma hdrstop #include "HookFunctionMain.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; #pragma pack(push, 1) typedef struct tagSaveRedir { void *thunk_addr; BYTE machine_code[5]; }TSaveRedir; typedef struct tagThunkCode { BYTE JMP; int Displacement; }TThunkCode; #pragma pack(pop) void RedirectCall(void *FromAddr, void *ToAddr, TSaveRedir &SaveRedir) { DWORD OldProtect; TThunkCode NewCode; if (!VirtualProtect(FromAddr, 5, PAGE_EXECUTE_READWRITE, &OldProtect)) RaiseLastWin32Error; SaveRedir.thunk_addr = FromAddr; ::memcpy(&SaveRedir.machine_code,FromAddr,5); NewCode.JMP = 0xE9; NewCode.Displacement = (char*)ToAddr - (char*)FromAddr - 5; ::memcpy(FromAddr,&NewCode,5); if(!VirtualProtect(FromAddr, 5, OldProtect, &OldProtect)) RaiseLastWin32Error; } void UndoRedirectCall(TSaveRedir &SaveRedir) { DWORD OldProtect; if (!VirtualProtect(SaveRedir.thunk_addr, 5, PAGE_EXECUTE_READWRITE, &OldProtect)) RaiseLastWin32Error; ::memcpy(SaveRedir.thunk_addr,SaveRedir.machine_code,5); if (!VirtualProtect(SaveRedir.thunk_addr, 5, OldProtect, &OldProtect)) RaiseLastWin32Error; } int __fastcall MyNewMessageBox(TApplication *self, char const *Text, char const *Caption,long Flags) { ShowMessage("New Messagebox"); return 0; //.... } TSaveRedir S; void *p; typedef int (_fastcall TApplication::*MP)(const char *,const char *,int); MP mp = TApplication::MessageBoxA; void start(void) { asm { push eax; mov eax, DWORD ptr[mp]; mov p,eax; pop eax; } RedirectCall(p,(void*)MyNewMessageBox,S); } void unload(void) { UndoRedirectCall(S); } #pragma startup start #pragma exit unload //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { Application->MessageBoxA("OLD_ONE","OLD_CAP",MB_OK); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { RedirectCall(p,(void*)MyNewMessageBox,S); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button3Click(TObject *Sender) { UndoRedirectCall(S); } //--------------------------------------------------------------------------- [/code]
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan |
taishyang
站務副站長 發表:377 回覆:5490 積分:4563 註冊:2002-10-08 發送簡訊給我 |
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
其實我想要做到的就是上面圖的部份 form1 call application.messagebox, messagebox 要放在 form1 的正中間 form1 用 screen.activeform 可以取得 width, height 利用 clienttoscreen 可以取得 form1 目前的位置 但現在 messagebox 我無法得知其 width, height, 故無法計算出中間值 abs(Screen.ActiveForm.Width-w) div 2) // w 就是 messagebox 的width 但又因為每一組 MessageBox 都會因為 Message的內容不同會所有大小不同 不知要如何取得? 之前利用 PosMessage() 可以取得, 但以 淡兄的程式則應如何才能得到 MessageBox 的 Rect 值? |
GrandRURU
站務副站長 發表:240 回覆:1680 積分:1874 註冊:2005-06-21 發送簡訊給我 |
|
歸木淡
中階會員 發表:1 回覆:49 積分:75 註冊:2005-09-07 發送簡訊給我 |
[code delphi]
unit wcMessageboxEx; interface uses Windows, Forms; procedure InstallHook; procedure UninstallHook; type tMessageBoxPosition = (mbpDefault, mbpFixed, mbpCenterOfActiveform); var MessageBoxLeft: integer = 100; MessageBoxTop: integer = 100; MessageBoxPosition: tMessageBoxPosition = mbpCenterOfActiveform; implementation var hCBTHook: HHOOK = 0; function GetWindowClassName(hwnd: THandle): string; var ps: array[0..254] of Char; begin GetClassName(hwnd, ps, 255); result:=ps; end; function MessageBoxHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var x, y: integer; r: tRect; begin if (Code = HCBT_ACTIVATE) and (MessageBoxPosition <> mbpDefault) and (GetParent(wParam) = Application.Handle) and (GetWindowClassName(wParam) = '#32770') then begin if (MessageBoxPosition = mbpCenterOfActiveform) and Assigned(Screen.ActiveCustomForm) then begin GetWindowRect(wParam, r); with Screen.ActiveCustomForm.BoundsRect do begin x := (Right Left - (r.Right-r.Left)) div 2; y := (Bottom Top - (r.Bottom-r.Top)) div 2; end; SetWindowPos(wParam, HWND_TOP, x, y, 0, 0, SWP_NOACTIVATE SWP_NOOWNERZORDER SWP_NOSIZE SWP_NOZORDER); end else SetWindowPos(wParam, HWND_TOP, MessageBoxLeft, MessageBoxTop, 0, 0, SWP_NOACTIVATE SWP_NOOWNERZORDER SWP_NOSIZE SWP_NOZORDER); end; Result:=CallNextHookEx(hCBTHook, Code, wParam, lParam); end; procedure InstallHook; begin if hCBTHook = 0 then hCBTHook := SetWindowsHookEx(WH_CBT, @MessageBoxHookProc, Hinstance, GetCurrentThreadId()); end; procedure UninstallHook; begin if hCBTHook <> 0 then begin UnHookWindowsHookEx(hCBTHook); hCBTHook := 0; end; end; initialization InstallHook; finalization UninstallHook; end. [/code] |
yckuo
高階會員 發表:55 回覆:389 積分:238 註冊:2003-03-07 發送簡訊給我 |
|
aftcast
站務副站長 發表:81 回覆:1485 積分:1763 註冊:2002-11-21 發送簡訊給我 |
再另提一個解決的方法給pd兄參考。即把pedro兄與rootkit二人所提的方式合而為一。我以bcb實做,delphi太久太久沒使用了,也沒裝…
主要是在hook function的地方去實做 postmessage 與 再度呼叫 messagebox,當然,其實也可以只在裡面寫一行MessageDlgPos來取代,也可以在那裡寫n多行…看怎用。 bcb要達成delphi的同等功能常常要轉n個灣才可以,所以程式碼會比較多,也比較tricky。 [code cpp] protected: void __fastcall ChangeMessageBoxPosition(TMessage& msg); BEGIN_MESSAGE_MAP MESSAGE_HANDLER(WM_USER,TMessage,ChangeMessageBoxPosition) END_MESSAGE_MAP(TForm) [/code] [code cpp] TForm1 *Form1; #pragma pack(push, 1) typedef struct tagSaveRedir { void *thunk_addr; BYTE machine_code[5]; }TSaveRedir; typedef struct tagThunkCode { BYTE JMP; int Displacement; }TThunkCode; #pragma pack(pop) TSaveRedir S; void *p; void RedirectCall(void *FromAddr, void *ToAddr, TSaveRedir &SaveRedir) { DWORD OldProtect; TThunkCode NewCode; if (!VirtualProtect(FromAddr, 5, PAGE_EXECUTE_READWRITE, &OldProtect)) RaiseLastWin32Error; SaveRedir.thunk_addr = FromAddr; ::memcpy(&SaveRedir.machine_code,FromAddr,5); NewCode.JMP = 0xE9; NewCode.Displacement = (char*)ToAddr - (char*)FromAddr - 5; ::memcpy(FromAddr,&NewCode,5); if(!VirtualProtect(FromAddr, 5, OldProtect, &OldProtect)) RaiseLastWin32Error; } void UndoRedirectCall(TSaveRedir &SaveRedir) { DWORD OldProtect; if (!VirtualProtect(SaveRedir.thunk_addr, 5, PAGE_EXECUTE_READWRITE, &OldProtect)) RaiseLastWin32Error; ::memcpy(SaveRedir.thunk_addr,SaveRedir.machine_code,5); if (!VirtualProtect(SaveRedir.thunk_addr, 5, OldProtect, &OldProtect)) RaiseLastWin32Error; } //--------------------------------------------------------------------------- int __fastcall MyNewMessageBox(TApplication *self, char const *Text, char const *Caption,long Flags) { UndoRedirectCall(S); PostMessage(Form1->Handle, WM_USER, 100, 0); Application->MessageBoxA(Text,Caption,Flags); // ShowMessage("ShowMessage"); // MessageDlgPos(Text,mtCustom, TMsgDlgButtons()< return 0; } typedef int (_fastcall TApplication::*MP)(const char *,const char *,int); MP mp = TApplication::MessageBoxA; void start(void) { asm { push eax; mov eax, DWORD ptr[mp]; mov p,eax; pop eax; } RedirectCall(p,(void*)MyNewMessageBox,S); } void unload(void) { UndoRedirectCall(S); } #pragma startup start #pragma exit unload //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { Application->MessageBoxA("二次輸入均錯誤","系統訊息",MB_OK); } //--------------------------------------------------------------------------- void __fastcall TForm1::ChangeMessageBoxPosition(TMessage& msg) { HANDLE MbHwnd; RECT MbRect; int x, y, w, h; int mx =50, my=50; MbHwnd = FindWindow(MAKEINTRESOURCE(WC_DIALOG), "系統訊息"); if (MbHwnd) { GetWindowRect(MbHwnd, &MbRect); w = MbRect.right - MbRect.left; h = MbRect.bottom - MbRect.top; // center horzontal x = mx; // keep on screen if (x < 0) x = 0; else if (x w > Screen->Width) x = Screen->Width - w; //center vertical y = my; // keep on screen if (y < 0) y = 0; else if (y h > Screen->Height) y = Screen->Height - h; // set new windows position SetWindowPos(MbHwnd, 0, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); } } [/code] 此外,我覺得歸木淡兄寫的也非常的好,而且它用的是thread hooks,而非全系統的資源,效能不會有什麼大問題。選哪一種都很不錯,最重要的是大家都因此而學到不少額外的東西!
------
蕭沖 --All ideas are worthless unless implemented-- C++ Builder Delphi Taiwan G+ 社群 http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2009-09-09 15:21:12, 註解 無‧
|
RootKit
資深會員 發表:16 回覆:358 積分:419 註冊:2008-01-02 發送簡訊給我 |
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
很感謝淡兄提供的程式, 雖然裡面很多我還是無法看懂的地方, 不過現在先應急把程式照抄上去, 果然確實完全達成我想要的效果, 但是在此也感謝P兄首帖回覆的方式, 也是可以達到需求, 還有其他回帖的前輩們, 一併致謝了, 基於答題的精神, 我還是把得分給淡兄了, 其他前輩抱歉啦!
===================引 用 歸木淡 文 章=================== [code delphi] unit wcMessageboxEx; interface uses ? Windows, Forms; procedure InstallHook; procedure UninstallHook; type ? tMessageBoxPosition = (mbpDefault, mbpFixed, mbpCenterOfActiveform); var ? MessageBoxLeft: integer = 100; ? MessageBoxTop: integer = 100; ? MessageBoxPosition: tMessageBoxPosition = mbpCenterOfActiveform; implementation var ? hCBTHook: HHOOK = 0; function GetWindowClassName(hwnd: THandle): string; var ? ps: array[0..254] of Char; begin ? GetClassName(hwnd, ps, 255); ? result:=ps; end; function MessageBoxHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var ? x, y: integer; ? r: tRect; begin ? if (Code = HCBT_ACTIVATE) and ? ? ?(MessageBoxPosition <> mbpDefault) and ? ? ?(GetParent(wParam) = Application.Handle) and ? ? ?(GetWindowClassName(wParam) = '#32770') then ? begin ? ? if (MessageBoxPosition = mbpCenterOfActiveform) and ? ? ? ?Assigned(Screen.ActiveCustomForm) then ? ? begin ? ? ? GetWindowRect(wParam, r); ? ? ? with Screen.ActiveCustomForm.BoundsRect do ? ? ? begin ? ? ? ? x := (Right Left - (r.Right-r.Left)) div 2; ? ? ? ? y := (Bottom Top - (r.Bottom-r.Top)) div 2; ? ? ? end; ? ? ? SetWindowPos(wParam, HWND_TOP, ? ? ? ? x, y, 0, 0, ? ? ? ? SWP_NOACTIVATE SWP_NOOWNERZORDER SWP_NOSIZE SWP_NOZORDER); ? ? end else ? ? ? SetWindowPos(wParam, HWND_TOP, ? ? ? ? MessageBoxLeft, MessageBoxTop, 0, 0, ? ? ? ? SWP_NOACTIVATE SWP_NOOWNERZORDER SWP_NOSIZE SWP_NOZORDER); ? end; ? Result:=CallNextHookEx(hCBTHook, Code, wParam, lParam); end; procedure InstallHook; begin ? if hCBTHook = 0 then ? ? hCBTHook := SetWindowsHookEx(WH_CBT, @MessageBoxHookProc, ? ? ? ? ? Hinstance, GetCurrentThreadId()); end; procedure UninstallHook; begin ? if hCBTHook <> 0 then ? begin ? ? UnHookWindowsHookEx(hCBTHook); ? ? hCBTHook := 0; ? end; end; initialization ? InstallHook; finalization ? UninstallHook; end. [/code] |
pedro
尊榮會員 發表:152 回覆:1187 積分:892 註冊:2002-06-12 發送簡訊給我 |
原本看標題以為問題很簡單,看似簡單的問題,也是這麼的難哩
到後來看歸木淡、aftcast、RootKit們回應,使出本領,越來越深入 才知道已經超出我能力範圍太多太多了 ===================引 用 P.D. 文 章=================== 很感謝淡兄提供的程式, 雖然裡面很多我還是無法看懂的地方, 不過現在先應急把程式照抄上去, 果然確實完全達成我想要的效果, 但是在此也感謝P兄首帖回覆的方式, 也是可以達到需求, 還有其他回帖的前輩們, 一併致謝了, 基於答題的精神, 我還是把得分給淡兄了, 其他前輩抱歉啦! |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |