Getlasterror delphi коды ошибок

APIs that require a call to GetLastError() need special treatment to work correctly. If you call such an API through a P/Invoke declaration and then try calling the GetLastError() API through another P/Invoke declaration, you can get inconsistent results. The CLR might actually make other API calls of its own in between your first call returning and the call through to GetLastError(). As a result of this, the error code returned by GetLastError() might have actually been set by a completely different API routine, and thereby give thoroughly misleading information. Because of this, it is considered bad practice to call the GetLastError() API directly.

The DllImportAttribute field SetLastError is provided to help with this situation. It defaults to False, but if set to True, it means that the P/Invoke mechanism will call GetLastError() for you after the routine exits and will store the result value. When you need it, you can get it with a call to Marshal.GetLastWin32Error(). The Borland.Delphi.System unit that is implicitly in the uses clause of all Delphi for .NET source files has a wrapper function called GetLastError() that calls this routine. Additionally, to avoid any ambiguity in the case in which you are calling Win32 routines and have Borland.Vcl.Windows (or simply Windows) in your uses clause, that unit does not define a P/Invoke import declaration for GetLastError(). Instead, it contains a simple implementation of GetLastError() that calls the wrapper routine in Borland.Delphi.System.

NOTE

All the P/Invoke import declarations provided in the Borland import units for Win32 APIs that use this error code model have the SetLastError field set to True. However, if you know you do not need the error code, it is a pointless exercise having the CLR make the GetLastError() call. You can make a very minor performance improvement by redeclaring the API import and omitting the SetLastError field.

If you were accustomed to using the Win32 API helper routines supplied in the Delphi RTL, you will be relieved to know that they are still there:

  • SysErrorMessage() will turn a Win32 error code into a descriptive string.
  • RaiseLastWin32Error() is deprecated as in Delphi 7 and 6 in favor of RaiseLastOSError().
  • RaiseLastOSError() calls GetLastError() (the Borland.Delphi.System wrapper); if it is a nonzero error code, an EOSError exception is raised with the error description (from SysErrorMessage) as its message.
  • Win32Check() takes a Boolean API return value; if it is False, it calls RaiseLastOSError().

As an example to show the principle, we can call the GetUserName() API. This is not required in normal programming scenarios because the logged on user can be identified through the System.Windows.Forms.Systemlnformation.UserName static property, but it will serve as an example. GetUserName is defined in the Boriand.vci.windows P/Invoke import unit like this:

function GetUserName(lpBuffer: StringBuilder; var nSize: DWORD): BOOL;

[DllImport(advapi32, CharSet = CharSet.Auto, SetLastError = True,

EntryPoint = ‘GetUserName’)] function GetUserName; external;

If the buffer passed in is too small, the function sets an error code and returns False. We can avoid writing code to check the return value and branch by using win32Check() as in Listing 16.12.

LISTING 16.12 Using Win32CheckO to Generate Exceptions

1: uses

2: Windows, SysUtils, System.Text; 3:

4: procedure frmWin32Example.frmWin32Example_Load(sender: System.Object; 5: e: System.EventArgs); 6: var

7: UserName: StringBuilder; 8: UserNameLen: DWord; 9: begin

10: UserName := StringBuilder.Create;

11: //Make room for 5 characters, not including a null terminator 12: UserName.Capacity := 5;

13: //Pass in the buffer size including the null terminator

14: UserNameLen := Succ(UserName.Capacity);

15: Win32Check(GetUserName(UserName, UserNameLen));

16: lblUserName.Text := System.String.Format(

. Find the code on the CD: \Chapter i6\Ex07.

Lines 10 and 12 set up a StringBuilder object with enough room for five characters (deliberately small, so some usernames won’t fit). Line 14 initializes the length variable with the buffer size; in the case of this API, the size value must include the space for the null terminator. Line 15 makes use of the win32Check() helper routine. If all goes well (if you have a short username), it is displayed on a label on the form. If not, an exception is raised describing the problem.

Continue reading here: Result Error Codes

Was this article helpful?

 
Smithson
 
(2003-01-16 11:57)
[0]

Не могу найти не в Source, не в Help. Подскажите, где посмотреть?


 
Игорь Шевченко
 
(2003-01-16 12:02)
[1]

Platform SDK\Include\winerror.h

Или в любом сишном компиляторе под win32


 
Smithson
 
(2003-01-16 12:03)
[2]

Немае. Пишу же — Delphi 5


 
Игорь Шевченко
 
(2003-01-16 12:06)
[3]

Блин, сбил ты меня с толку! :-)

Source\Rtl\Win\windows.pas


 
neXt
 
(2003-01-16 12:06)
[4]

MSDN/Platform SDK Documentation/Win32 API/Reference/Compatibility with the Windows API/Win32 Error Codes

ЗЫ: только у меня старая MSDN может адрес щас другой


 
neXt
 
(2003-01-16 12:09)
[5]



> Игорь Шевченко © (16.01.03 12:06)

> Блин, сбил ты меня с толку! :-)

> Source\Rtl\Win\windows.pas



Там function GetLastError: DWORD; stdcall;, а просят вроде коды ошибок.


 
Smithson
 
(2003-01-16 12:09)
[6]

MSDN у меня тоже нету — Рихтером обхожусь.

Слушайт, а можешь поглядишь — код ошибкии 997 (десятичный)?


 
neXt
 
(2003-01-16 12:11)
[7]

997 Overlapped I/O operation is in progress. ERROR_IO_PENDING


 
Smithson
 
(2003-01-16 12:12)
[8]

Нет, коды там тоже есть. Я вроде нашел, но ни черта не понял. У меня

рушится сокетный ввод-вывод с кодом 997. Что это может быть?


 
neXt
 
(2003-01-16 12:13)
[9]

> Игорь Шевченко © (16.01.03 12:06)

сори, есть там коды только до 4000

> Smithson © (16.01.03 12:09)

и 997 тоже есть в \Source\Rtl\Win\windows.pas

{ Overlapped I/O operation is in progress. }

ERROR_IO_PENDING = 997; { dderror }

{$EXTERNALSYM ERROR_IO_PENDING}


 
Mystic
 
(2003-01-16 12:17)
[10]

Если нужно по коду ошибки получить описание, может помочь функция FormatMessage с флагом FORMAT_MESSAGE_FROM_SYSTEM.


 
Anatoly Podgoretsky
 
(2003-01-16 12:24)
[11]

Коды ошибок есть в хелпе, так и называются error codes


 
Digitman
 
(2003-01-16 12:27)
[12]

см. Win32Check(), RaiseLastWin32Error()

…………………………………..

Checks the return value of a Windows API call and raises an appropriate exception when it indicates failure.

Unit

Sysutils

Category

exception handling routines

function Win32Check(RetVal: BOOL): BOOL;

Description

Call Win32Check with the return value of a Windows API call that returns a Boolean to indicate success or failure. If the Windows API returns False (indicating failure), Win32Check calls RaiseLastWin32Error to raise an exception. If the Windows function returns True, Win32Check returns True.

…………………………………..

procedure RaiseLastWin32Error;

Description

Call RaiseLastWin32Error to raise an EWin32Error exception for the last Windows API call that failed. RaiseLastWin32Error retrieves the code for the last occurring Win32 error, if any. If Windows returns a previously occurring error code, RaiseLastWin32Error raises an EWin32Error exception with the error code and message associated with that error.


 
Anatoly Podgoretsky
 
(2003-01-16 12:33)
[13]

Если нужны не коды, а тексты ошибок, то надо использовать FormatMessage


 
Anatoly Podgoretsky
 
(2003-01-16 12:39)
[14]

Если нет противопоказания к использованию VCL, то наиболее удобно SysErrorMessage(GetLastError)


 
Smithson
 
(2003-01-16 12:46)
[15]

Спасибо, я его поборол.

Но у меня видимо перекрыт хелп — error codes возращает описания, начиная с 1000 кода.


 
Anatoly Podgoretsky
 
(2003-01-16 12:58)
[16]

Smithson © (16.01.03 12:46)

Ты видимо вообще в другом хелпе смотришь, прямо из хелпа

997L ERROR_IO_PENDING


 
Демонов Е.В.
 
(2003-01-16 16:11)
[17]

SysErrorMessage(997)=

Протекает наложенное событие ввода/вывода


I have a problem using a third-party component in Delphi 2006 (also Delphi 7), in which I get an «Unspecified Error» when executing a function call to that component. Do you have example code that utilises GetLastError and FormatMessage in Delphi, that would allow me to access more information about the error ? TIA :)

asked Mar 21, 2009 at 10:10

Drew Gibson's user avatar

3

There is an integrated helper function in Delphi: SysErrorMessage. It’s essentially a wrapper to FormatMessage, but much simpler to use in your case. Just provide the error code you need a textual description for.

For example you can use this to display the last error:

ShowMessage(SysErrorMessage(GetLastError))

If you want to raise an exception with this message, it’s even simpler:

RaiseLastOSError;

Important: Make sure that there is no additional API call between the failing function and your call of GetLastError, otherwise the last error will be reset.

Grim's user avatar

Grim

1,98611 gold badges57 silver badges124 bronze badges

answered Mar 21, 2009 at 10:31

Daniel Rikowski's user avatar

Daniel RikowskiDaniel Rikowski

71.4k58 gold badges251 silver badges329 bronze badges

1

While DR is correct, there is a problem with this approach: It does not allow you to specify the context in which the error occurred. Ever seen the error «An API function failed.» whithout being any wiser which function it was and where it happended?

That’s why I wrote the RaiseLastOsErrorEx and Win32CheckEx functions:

procedure RaiseLastOsErrorEx(const _Format: string);
begin
  RaiseLastOsErrorEx(GetLastError, _Format);
end;

procedure RaiseLastOsErrorEx(_ErrorCode: integer; _Format: string); overload;
var
  Error: EOSError;
begin
  if _ErrorCode <> ERROR_SUCCESS then
    Error := EOSError.CreateFmt(_Format, [_ErrorCode, SysErrorMessage(_ErrorCode)])
  else
    Error := EOsError.CreateFmt(_Format, [_ErrorCode, _('unknown OS error')]);
  Error.ErrorCode := _ErrorCode;
  raise Error;
end;

function GetLastOsError(out _Error: string; const _Format: string = ''): DWORD;
begin
  Result := GetLastOsError(GetLastError, _Error, _Format);
end;

function GetLastOsError(_ErrCode: integer; out _Error: string; const _Format: string = ''): DWORD;
var
  s: string;
begin
  Result := _ErrCode;
  if Result <> ERROR_SUCCESS then
    s := SysErrorMessage(Result)
  else
    s := _('unknown OS error');
  if _Format <> '' then
    try
      _Error := Format(_Format, [Result, s])
    except
      _Error := s;
    end else
    _Error := s;
end;

function Win32CheckEx(_RetVal: BOOL; out _ErrorCode: DWORD; out _Error: string;
  const _Format: string = ''): BOOL;
begin
  Result := _RetVal;
  if not Result then
    _ErrorCode := GetLastOsError(_Error, _Format);
end;

(They are part of unit u_dzMiscUtils of my dzLib library available here:
https://osdn.net/projects/dzlib-tools/svn/view/dzlib/trunk/src/u_dzMiscUtils.pas?view=markup&root=dzlib-tools#l313

answered Jul 13, 2009 at 7:30

dummzeuch's user avatar

dummzeuchdummzeuch

11k4 gold badges51 silver badges159 bronze badges

4

Понравилась статья? Поделить с друзьями:
  • Getcontext 2d ошибка
  • Gepard 23 mtv ошибка f62
  • Genshin impact ошибка подключения к серверу на ps4
  • Genshin impact ошибка 502
  • Getcontact код ошибки 5001