Einzelnen Beitrag anzeigen

Benutzerbild von mael
mael

Registriert seit: 13. Jan 2005
391 Beiträge
 
Delphi XE3 Professional
 
#1

GetLastError und falsche Fehlermeldungen, z.b. in TFileStream

  Alt 8. Feb 2016, 10:44
Hallo,

Nach einer kurzen Diskussion in der Shoutbox wollte ich mal ein konkretes Beispiel geben. Man kann sich da nur zu kurz und daher unklar ausdrücken, und wahrscheinlich meinten wir dasselbe.

Der folgende Code gibt den Fehler 3 aus.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  Filename: string;
begin
  Filename := '';
  if CreateFile(PChar(Filename), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0) = INVALID_HANDLE_VALUE then
    ShowMessage(IntToStr(GetLastError));
end;
Dieser aber 123 weil vorher noch ExpandFileName aufgerufen wird.
Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var
  Filename: string;
begin
  Filename := '';
  if CreateFile(PChar(Filename), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0) = INVALID_HANDLE_VALUE then
  begin
    ExpandFileName(Filename); // ruft WinAPI funktionen auf
    ShowMessage(IntToStr(GetLastError));
  end;
end;
So ein ähnliches Problem kriegt man auch mit TFileStream.Create wo das nicht so direkt zu erkennen ist:
Delphi-Quellcode:
    inherited Create(FileCreate(AFileName, LShareMode, Rights));
    if FHandle = INVALID_HANDLE_VALUE then
      raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(AFileName), SysErrorMessage(GetLastError)]);
So eine Art Code ist leider in vielen Teilen der VCL zu finden, zumindest in XE3. Das heißt es könnten manchmal falsche Fehlermeldungen kommen. Hier ist es nicht so auffällig weil:

SysErrorMessage(123) = 'Die Syntax für den Dateinamen, Verzeichnisnamen oder die Datenträgerbezeichnung ist falsch' und
SysErrorMessage(3) = 'Das System kann den angegebenen Pfad nicht finden'

Ruft man TFileStream.Create folgendermaßen auf bekommt man auch ganz folgerichtig die Fehlermeldung für SysErrorMessage(123) und nicht SysErrorMessage(3):
TFileStream.Create('', fmOpenRead or fmShareDenyNone);

Das ist in dem Fall nicht so schlimm, aber prinzipiell ist es unsauber und hat Potenzial für unerklärliche Probleme.

Es ist also besser den Fehlercode nach einem WinAPI-Aufruf zu speichern wenn man denn diesen Fehlercode ausgeben möchte (falls diese WinAPI-Funktion False zurückgegeben hat oder anders einen Fehler signalisiert hat). Ruft man aber dazwischen noch eine andere WinAPI-Funktion auf, auch wenn das implizit geschieht durch andere Funktionen, gibt es das Potenzial dafür dass GetLastError den "falschen" Fehlercode zurückgibt.

Daher ist es gut dass wenn man den Fehlercode benötigt, ihn direkt nach dem API-Aufruf speichert, ohne sonstige Funktionen dazwischen aufzurufen, und dann an der gewünschten Stelle ausgibt, z.B. mit Hilfe von SysErrorMessage().
HxD, schneller Hexeditor:
http://mh-nexus.de/hxd

Geändert von mael ( 8. Feb 2016 um 11:05 Uhr)
  Mit Zitat antworten Zitat