2016-04-08 10 views
0

Wenn ich diesen Code ohne Laufzeit-Pakete ausführen, habe ich einen 32-Code-Fehler, das ist richtig. Aber wenn ich activite Laufzeit-Packages (z.Bsp nur mit "FireDACASADriver; YmagControlDB") wird der Fehlercode ist immer "0"Delphi GetLastError mit Ausführen von Paketen

procedure TForm1.Button1Click(Sender: TObject); 
Var 
    Stream: TStream; 
    iError : integer; 
begin 
    Stream := nil; 
    iError := -1; 
    try 
     try 
     Stream := TFileStream.Create('d:\toto.docx', fmOpenRead); 
     except 
     begin 
      iError := GetLastError; 
     end; 
     end; 
    finally 
     if Assigned(Stream) then 
     Stream.Free; 
    end; 
    showmessage('Erreur : ' + inttostr(iError)); 
end; 

Wie kann ich das GetLastError mit Runtime-Paketen beheben kann?

Antwort

4

Es ist einfach nicht sinnvoll, dort GetLastError anzurufen. Sie mischen zwei verschiedene Fehlerbehandlungsmodelle.

Rufen Sie GetLastError sofort nach einem API-Aufruf fehl, wenn die Dokumentation dazu sagt. Wenn Sie es aufrufen, könnte eine andere Funktion SetLastError aufgerufen haben und den Wert zurücksetzen.

Es ist also falsch, GetLastError aufzurufen, da Sie keine Win32-Funktionen verwenden und den Anruf zu GetLastError entfernen sollten. Der Code sollte sein:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    Stream: TStream; 
begin 
    Stream := TFileStream.Create('d:\toto.docx', fmOpenRead); 
    try 
    // ....  
    finally 
    Stream.Free; 
    end; 
end; 

Wenn ein Fehler auftritt, wird eine Ausnahme ausgelöst werden, die von den obersten Ebene Exception-Handler gemeldet werden.

Laufzeitpakete sollten keinen Einfluss darauf haben, wie dieser Code ausgeführt wird.

Mögliche Ursachen für einen Fehler sind, dass die Datei nicht existiert oder dass sie gesperrt ist.

Sie schrieb:

if Assigned(Stream) then 
    Stream.Free; 

, die immer sinnlos ist, da die Free Verfahren prüft auch, ob die Objektreferenz nil zu sein. In der Tat ist der Code entspricht:

if Assigned(Stream) then 
    if Assigned(Stream) then 
    Stream.Destroy; 

So ist es sauberer auf Test verlassen innen Free und einfach schreiben:

Stream.Free; 

In den Kommentaren erklären Sie, dass Sie tatsächlich testen möchten ob die Datei gesperrt ist oder nicht Verwenden Sie keinen Dateistream dafür. Stattdessen gehen Sie wie folgt vor:

  • Anruf CreateFile die Datei zu öffnen.
  • Überprüfen Sie das zurückgegebene Handle gegen INVALID_HANDLE_VALUE, um Fehler zu erkennen.
  • Verwenden Sie im Fehlerfall GetLastError, um die Fehlerursache herauszufinden.
  • Andernfalls den Griff mit CloseHandle schließen.

Dies ist jedoch nicht zu empfehlen. Sie können diesen Ansatz verwenden, um festzustellen, dass die Datei nicht gesperrt ist, aber zu dem Zeitpunkt, zu dem Sie versuchen, sie zu lesen, wurde sie gesperrt. Es gibt eine inhärente Wettlaufbedingung.

Als eine allgemeine Richtlinie ist es besser, Vergebung als Erlaubnis zu bitten.

+0

Ok, aber ich schreibe diesen Code, um ein gesperrtes Dokument zu erkennen. Der getLastError ohne das Runtime-Paket hatte den Code 32. Was ist der beste Weg, um zu erkennen, dass die Datei gesperrt ist? – Joc02

+0

Siehe meine letzte Änderung –

0

Durch das Auslösen einer Ausnahme kann der Fehlercode des aufrufenden Threads zurückgesetzt werden. Es ist einfach nicht angemessen, GetLastError() innerhalb eines Ausnahmebehandlers aufzurufen.

aber sagen, dass wenn TFileStream die Datei nicht geöffnet wird, eine Ausnahme ausgelöst, die eine vom System bereitgestellte enthält Fehlermeldung (aber nicht die tatsächliche Fehlercode), zB:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    Stream: TStream; 
begin 
    try 
    Stream := TFileStream.Create('d:\toto.docx', fmOpenRead); 
    try 
     // use Stream as needed 
    finally 
     Stream.Free; 
    end; 
    except 
    on E: Exception do 
     ShowMessage('Erreur : ' + E.Message); 
    end; 
end; 

Wenn Sie Zugriff benötigen dem Fehlercode können Sie nicht TFileStream verwenden, haben Sie CreateFile() direkt stattdessen verwenden:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    hFile: THandle; 
    iError: DWORD; 
begin 
    hFile := CreateFile('d:\toto.docx', GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); 
    if hFile <> INVALID_HANDLE_VALUE then 
    begin 
    try 
     // use hFile as needed... 
     // 
     // if you need to access the file as a TStream, you can 
     // instantiate a THandleStream passing hFile to its constructor... 
     // 
    finally 
     CloseHandle(hFile); 
    end; 
    end else 
    begin 
    iError := GetLastError; 
    ShowMessage('Erreur : ' + IntToStr(iError)); 
    if iError = ERROR_SHARING_VIOLATION then 
    begin 
     // do something... 
    end; 
    end; 
end; 

Alternativ:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    hFile: THandle; 
begin 
    hFile := CreateFile('d:\toto.docx', GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); 
    try 
    Win32Check(hFile <> INVALID_HANDLE_VALUE); 
    try 
     // use hFile as needed... 
    finally 
     CloseHandle(hFile); 
    end; 
    except 
    on E: EOSError do 
    begin 
     ShowMessage('Erreur : ' + IntToStr(E.ErrorCode)); 
     if E.ErrorCode = ERROR_SHARING_VIOLATION then 
     begin 
     // do something... 
     end; 
    end; 
    end; 
end;