Kendall Lister
Kendall Lister

Reputation: 335

Why does GetLastError have an error before my program begins?

While using GetLastError after calling a Windows API function wrapper like ExtractShortPathName I noticed that GetLastError returns a non-zero error code regardless of whether the call to ExtractShortPathName succeeded or failed. In fact, there seems to be a "last error" before my program even executes, e.g.

program TestGetLastError;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils;

var
  ErrorCode: Integer;

begin
  try
    ErrorCode := GetLastError;
    if ErrorCode <> 0 then
      RaiseLastOSError;
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;
end.

results in:

EOSError: System Error.  Code: 122.
The data area passed to a system call is too small

Am I misunderstanding something or doing something wrong?

If the Delphi run-time is doing something that results in GetLastError being set, what is the correct way to clear that error before my program starts executing? Should I use SetLastError(ERROR_SUCCESS); like this example from the Delphi API documentation:

procedure TForm2.btRaiseLastClick(Sender: TObject);
begin
  { Set the last OS error to a bogus value. }
  System.SetLastError(ERROR_ACCESS_DENIED);

  try
    RaiseLastOSError();
  except
    on Ex : EOSError do
      MessageDlg('Caught an OS error with code: ' + IntToStr(Ex.ErrorCode), mtError, [mbOK], 0);
  end;

  { Let the Delphi Exception dialog appear. }
  RaiseLastOSError(ERROR_NOT_ENOUGH_MEMORY);

  { Finally set the last error to none. }
  System.SetLastError(ERROR_SUCCESS);

  if GetLastError() <> ERROR_SUCCESS then
    MessageDlg('Whoops, something went wrong in the mean time!', mtError, [mbOK], 0);

  { No exception should be thrown here because last OS error is "ERROR_SUCCESS". }
  CheckOSError(GetLastError());
end;

http://docwiki.embarcadero.com/CodeExamples/Tokyo/en/LastOSError_(Delphi)

Upvotes: 3

Views: 1180

Answers (2)

Ken White
Ken White

Reputation: 125757

GetLastError's documentation indicates that is only of use if

  • an API call fails, and
  • the function that fails indicates that you can use GetLastError for more information about why. From that documentation (emphasis mine)

The return value is the calling thread's last-error code.

The Return Value section of the documentation for each function that sets the last-error code notes the conditions under which the function sets the last-error code. Most functions that set the thread's last-error code set it when they fail. However, some functions also set the last-error code when they succeed. If the function is not documented to set the last-error code, the value returned by this function is simply the most recent last-error code to have been set; some functions set the last-error code to 0 on success and others do not.

This indicates that calling it without first having a failure in a function documented to set it on failure is meaningless. You can't call GetLastError unless you know an error occurred, and only if you're calling it after a specific function you called indicates it failed.

Upvotes: 4

Nat
Nat

Reputation: 5453

The value returned by GetLastError() is only relevant immediately after a Windows API call that has failed and where the documentation for that function specifies that extended error information is available by calling GetLastError().

Calling it outside of that context will return something from an earlier call, which could be from your code, the Delphi runtime, a DLL that you have called or even something in the Windows API...

As the Windows API documentation for GetLastError() states:

You should call the GetLastError function immediately when a function's return value indicates that such a call will return useful data.

Upvotes: 13

Related Questions