Einzelnen Beitrag anzeigen

Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#9

Re: Auf Fehlerrückgabe prüfen

  Alt 25. Jul 2007, 13:16
@Sir: Das ist auch richtig. SAFECALL hat aber neben der Angabe über Parameterübergabe etc. auch noch einen weiteren Hintergrund. Eine SafeCall-Funktion hat immer zwei Rückgabewerte (eine Prozedur dementsprechend immer einen), zum einen das "echte Ergebnis", zum anderen einen Fehlercode.
Hintergrund ist der, dass man in der OOP ja keine Klassen kreuz und quer durch verschiedene Adressbereiche bzw. Speichermanager etc. schieben kann. Konkret (wobei ... jetzt bin ich mir nicht 100% sicher): Du kannst keine Klasse in einer Library erstellen und in deiner Main-Exe freigeben (ohne Sharemem etc.). Bei Exceptions (in OOP) würde genau das passieren. Beim Werfen der Exception wird die Klasse erstellt und hinterm nächsten except gekillt. -->CRASH

Dagegen gibts SafeCall: Du machst die Exceptionbehandlung innerhalb der Bibliothek und gibst neben dem eigentlichen Ergebnis auch einen Fehlercode mit zurück. Der Compiler prüft nach dem Aufruf einer SafeCall-Funktion automatisch den Fehlercode und ruft gegebenenfalls die Funktion in der Variablen SafeCallErrorProc auf (die normalerweise nil ist). Ausserdem wirft er erneut eine SafeCallException.
Das ist das besondere an SafeCall und entspricht so ziemlich dem was DelpiManiac als Funktionsköpfe hatte.
Also eine Funktion
function xyz(a,b,c,...:integer; var result:integer):TErrorCode; stdcall; ist dasselbe wie
function xyz(a,b,c,...:integer):integer; safecall; vom Header her (mit TErrorCode=integer)

So, und jetzt wirds dirty (vielleicht gehts auch einfacher, aber Delphi übergibt sonst immer denselben Fehlercode):
Delphi-Quellcode:
//Die Funktion in einer Bibliothek
function test(var erg:integer):cardinal;stdcall;
//hier allerdings lieber stdcall, weil wir wollen ja den ErrorCode selber setzen
const Error=$80000000; //Vorzeichenbit muss gesetzt sein für Fehler
begin
  //der eigentliche Funktionsinhalt
  erg:=-5;


  
  //wenn Fehler dann
  result:=120+error; //120 unser Fehlercode
  //sonst
  result:=0; //hauptsache nicht negativ
end;
Und im Hauptprogramm:
Delphi-Quellcode:
var ExceptionType:integer;

procedure SafecallError;
asm
  //die ersten beiden Zeilen nutzen wenn keine Exception geworfen werden soll
  //pop ecx
  //mov [esp],edx

  //Ergebnis in Exceptiontype schreiben
  and eax,$7FFFFFFF
  mov ExceptionType,eax
end;

procedure TForm1.Button1Click(Sender: TObject);
var mytest:function:integer;safecall;
begin
  
  mytest:=@test;
  try
    edit1.Text:=inttostr(mytest);
  except
    on ESafeCallException do
      edit1.text:=inttostr(Exceptiontype);
    else raise;
  end;
end;
Soweit, so gut. Und irgendwo vorher muss noch
safecallerrorProc:=@SafeCallError; gesetzt werden.

War hier nur so ne Idee...die auch erstmal funktioniert

Edit:
Wenn man in SafeCallError alle auskomentierten Zeilen so lässt, geht es auch ohne ASM:
Delphi-Quellcode:
procedure safecallerror(ErrorCode:integer;NonExceptionAddr:pointer);
begin
  ExceptionType:=Errorcode and $7FFFFFFF;
end;
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat