![]() |
MessageBox ersetzen
Hallo zusammen.
Ich programmiere mir ein kleines Tool, welches einige Daten auf meinem Server sammelt (Speicherauslastung,An- und Abmeldeereignisse). Das Problem ist, dass bei einem Fehler eine MessageBox aufgeht und das Programm lahmlegt, weil niemand an dem Rechner ist und auf OK drücken könnte. Es gibt ja eine undokumentierte Funktion MessageBoxTimeOut, welche sich nach x Sekunden selbst schließt. Das geht auch ganz gut, nur rufen die Delphi-Bibliotheken selbst ja MessageBox und nicht MEssageBoxTimeOut auf. Kann man irgendwie alle Aufrufe von MessageBox nach MessageBoxTimeOut "umbiegen" :gruebel: |
Re: MessageBox ersetzen
Bin mir nicht sicher, aber irgendwie könnte das gehen. ggf. mit Hooks. Da hab ich aber (noch) keine Ahnung von.
Ne andere (einfachere) Möglichkeit is es das MessageBox-Fenster einfach nach x-Sekunden abzuschießen. Such mal nach FindWindow(Ex)... mfg Christian |
Re: MessageBox ersetzen
Zitat:
vermeide einfach, daß Fehler auftauchen die eine Messagebox anzeigen könnten. Fange an kritischen Stellen Fehler mit try..execpt ab und reagiere entsprechend darauf (in ein Logbuch eintragen, Mail an den Admin schicken...). Das ganze wird auf jeden Fall eine ganze Menge mehr Testaufwand bedeuten. Zu empfehlen wären da automatisierte Unittests mit DUnit oder anderen Testtools um die Serverapplikation auf mögliche Fehlerquellen abzuklopfen. Es ist auf jeden Fall nicht besonders elegant die Symptome (die Messageboxen) zu beseitigen die Krnkheit (die auftretenden Fehler) jedcoh im Programm zu lassen :wink: Ciao, Ralf |
Re: MessageBox ersetzen
Liste der Anhänge anzeigen (Anzahl: 1)
Diese undokumentierte Funktion ist mir unbeaknnt,. Ich habe aber mal eine Klasse geschriben TDemoProtect, die dies kann. Unit ist im Anhang. Wäre es aber nicht sinnvoller, statt Messageboxen anzuzeigen, eine Logdatei zu schreiben?
|
Re: MessageBox ersetzen
Erst mal danke für die Antworten.
Zitat:
![]() Zitat:
Zitat:
|
Re: MessageBox ersetzen
nach "etwas" rumprobieren hab ichs hinbekommen die MessageBox zu ersetzen.
Dazu hab ich folgende Funktion geschrieben (die Funktion "ersetzt" die ursprungsfunktion):
Delphi-Quellcode:
Die Alte Funktion und die neue Funktion müssen zu 100 Identisch sein.
function ReplaceFunktion(AOldFunction, ANewFunction: Pointer): Boolean;
var lProcess, lWritten : Cardinal; lBuffer : Array[0..(1 + 4 + 1)-1] of Byte; begin lProcess := OpenProcess(PROCESS_VM_WRITE or PROCESS_VM_OPERATION, True, GetCurrentProcessId); if (lProcess <> 0) then begin PByte(@lBuffer)^ := $68; PPointer(@lBuffer[1])^ := ANewFunction; PByte(@lBuffer[5])^ := $C3; if WriteProcessMemory(lProcess, AOldFunction, @lBuffer, SizeOf(lBuffer), lWritten) then result := lWritten = SizeOf(lBuffer) else result := False; end else result := False; end; Für dein Beispiel würde der Aufruf wie folgt aussehen (MessageBoxB ist meine neue Funktion):
Delphi-Quellcode:
//Messagebox-Ausgaben in Applicationtitle ausgaben
function MessageBoxB(AHandle: HWND; AMsg, ATitle: PChar; uType: Cardinal): Integer; stdcall; begin Application.Title := String(AMsg); end; [...] begin ReplaceFunktion(@MessageBox, @MessageBoxB); //Und siehe da, der Fehler wird nicht mehr als herkömliche Messagebox angezeigt StrToInt('abc'); end; |
Re: MessageBox ersetzen
Zitat:
Meiner Meinung nach kann man JEDEN Fehler und JEDEN Hinweis der von irgendwem (Delphi, Windoes, Komponenten) angezeigt werden soll, abfangen und einen Eintrag in ein Logfile schreiben. Ich finde es uncool, die roten Tupfer (MessageBoxen) zu überschminken, wenn ich Masern hab (ein Fehler vorkommt), nur um nicht zu zeigen, dass ich krank bin (nicht alle Fehler gesucht und gefunden habe). |
Re: MessageBox ersetzen
in Bezug auf die Fehler wäre die Verwendung von Application.OnException sinnvoller.
Das ersetzen der MessageBox ist dann sinnvoll wenn diese nicht ins Design passt. |
Re: MessageBox ersetzen
Das sieht ja super aus. Ich werd das heute abend direkt mal ausprobieren. Schon mal danke, ich werd Rückmeldung geben, wie es gelaufen ist :dp:
|
Re: MessageBox ersetzen
Zitat:
Und was heißt dann zu 100% identisch? Du meinst in den Aufrufparametern und im Namen, oder? |
Re: MessageBox ersetzen
100%: die Parameter müssen übereinstimmen (denk ich mal)
und so wie das aussieht überschreibt man damit die ersten Bytes der Funktion ... also mit einem Sprung in die neue Funktion ... demnach könnte man damit alles ersetzten, zerstört damit aber die Originalfunktion, diese ist dann also nicht mehr nutzbar? mir fällt grad ein, daß an Posiion @MessageBoxA doch auch nur ein Jump steht :gruebel: @Bärchen: wirde es dann denn nicht ausreichen, wenn du den Jump-Befehl stehen läßt und nur die Adresse änderst? |
Re: MessageBox ersetzen
Ich habs mal ausprobiert und irgendwie bekomme ich immer eine Schutzverletzung. Hast du vielleicht ein Beispielprojekt?
|
Re: MessageBox ersetzen
Liste der Anhänge anzeigen (Anzahl: 1)
Warum dieser Umstand und dieses rumgehacke im Quellcode? Du hast doch selber eine Möglichkeit gefunden (MessageboxTimeOut) und ich habe dir noch eine weitere gezeigt? Warum nimmst du nicht eine davon, wenn du schon nicht alles in ein Log schreiben willst.
Im Anhang noch mal beide Versionen in einer Demo von mir. |
Re: MessageBox ersetzen
Zitat:
Also Idealer Weise so:
Delphi-Quellcode:
@Codewalker: Wenn du eine AV bekommst ist dein Funktionrumpf nicht mit dem originalen Identisch. Die Parameter müssen gleich sein und auch die Aufrufkonvention. Wenn du zum Beispiel "stdcall" weglässt geht es schon schief.
var lLib: Cardinal;
begin lLib := LoadLibrary('user32.dll'); if (lLib <> 0) then begin ReplaceFunktion(GetProcAddress(lLib, 'MessageBoxA'), @MessageBoxB); FreeLibrary(lLIb); end; end; Im falle von MessageBoxA bzw. MessageBox muss dein Funktionskopf exakt so aussehen (ausgenommen der Funktionsname):
Delphi-Quellcode:
Es darf also keine Methode etc. sein sondern muss eben exakt mit der declaration der Originalfunktion übereinstimmen.
function Funktionsname(AHandle: HWND; AMsg, ATitle: PChar; uType: Cardinal): Integer; stdcall;
Das die Originale Funktion dabei zerstört wird ist richtig. Aus dem Grund hab ich vor das ganze in eine Klasse zu packen so das man eine Funktion ersetzen kann und später auch wieder herstellen (so das beim ersetzen der Teil welcher überschrieben wird, gesichert wird). |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:44 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz