Search code examples
delphiwinapierror-handlingdelphi-xe8

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)


Solution

  • 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.