DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: jeff1314
今日帖子: 10
在线用户: 5
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/5/11 21:44:33
标题:
About indiscriminate use of "GetLastError()" function in Delphi or any other language 浏览:4387
加入我的收藏
楼主: About indiscriminate use of "GetLastError()" function in Delphi or any other language

Let's remember that this function is specific to "try" to capture the code of the last error occurred in the layer of the operating system, and not, necessarily, of the programming language in use.

NOTE: the return-value can be override in any time!!!
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/5/11 21:48:17
1楼: ----------
Microsoft is clear and explicit in stating the following:

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

Remarks
Functions executed by the calling thread set this value by calling the SetLastError function. You should call the GetLastError function immediately when the function's return value indicates that such a call will return useful data. That is because some functions call SetLastError with a zero when they succeed, wiping out the error code set by the most recently failed function.

To obtain an error string for system error codes, use the FormatMessage function. For a complete list of error codes provided by the operating system, see System Error Codes.

The error codes returned by a function are not part of the Windows API specification and can vary by operating system or device driver. For this reason, we cannot provide the complete list of error codes that can be returned by each function. There are also many functions whose documentation does not include even a partial list of error codes that can be returned.

Error codes are 32-bit values ​​(bit 31 is the most significant bit). Bit 29 is reserved for application-defined error codes; no system error code has this bit set. If you are defining an error code for your application, set this bit to one. That indicates that the error code has been defined by an application, and ensures that your error code does not conflict with any error codes defined by the system.

To convert a system error into an HRESULT value, use the HRESULT_FROM_WIN32 macro.

Microsoft
https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror

Debug code errors MS:
https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes

System Error Codes (0-499) (WinError.h) - Win32 apps
Describes error codes 0-499 defined in the WinError.h header file and is intended for developers.

System Error Codes (500-999) (WinError.h) - Win32 apps
Describes error codes 500-999 defined in the WinError.h header file and is intended for developers.

System Error Codes (1300-1699) (WinError.h) - Win32 apps
Describes error codes 1300-1699 defined in the WinError.h header file and is intended for developers.

System Error Codes (1000-1299) (WinError.h) - Win32 apps
Describes error codes 1000-1299 defined in the WinError.h header file and is intended for developers.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/5/11 21:49:17
2楼: Article: Win Error Codes
Last Updated on Tue, 10 May 2022 | Delphi for Dot NET

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.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/5/11 21:57:03
3楼: PInvoke Magic
Last Updated on Sun, 03 Apr 2022 | Dotnet 2.0 for Delphi

Moving into the slightly more esoteric topics, Delphi for .NET supports two Platform Invoke (P/Invoke) technologies called Reverse P/Invoke (or Unmanaged Exports) and Dynamic P/Invoke (or Virtual Library Interfaces).

Reverse P/Invoke lets you write a .NET DLL that can be used like any other DLL from Win32 code. It is a quick way of introducing .NET functionality into a Win32 application without performing a complete porting process or hosting the CLR explicitly.

Unmanaged exports must reside within a library project and generate thunks of unmanaged code, so you must turn {$UNSAFECODE ON}. The syntax is the same exports declaration as is used in Win32 Delphi. Only global-level routines can be exported, not class methods.

library ReversePInvoke; procedure Foo(const S: string); function Bar: integer; function Greeting(Name: string): string; //...

{$UNSAFECODE ON} exports Foo, Bar,

Greeting;

On the Win32 side, you import these routines just like you would import any other DLL, using external declarations.

const

LibName = 'ReversePInvoke.DLL';

procedure Foo(const S: string); stdcall; external LibName;

function Bar: integer; stdcall; external LibName;

function Greeting(Name: string): PChar; stdcall; external LibName;

■Caution Not all managed types can be used as parameters in exported routines. Generally you can use simple types and strings. String input parameters map to Win32 AnsiString, string results and output parameters map to PChar.

Virtual Library Interfaces use Dynamic P/Invoke to load a Win32 DLL at run time by using an interface to specify what routines to import. The DLL can be seen as a singleton object that implements the interface. The advantage is that you can use the Supports function from the Borland.Delphi.Win32 unit to check if the DLL and all the methods are available.

uses

Win32; type

IMyInterface = interface procedure Foo(const S: string); function Bar: integer;

function Greeting(const Name: string): string; end;

procedure Test; var

MyInterface: IMyInterface; begin if Supports('Win32NativeDLL.DLL', TypeOf(IMyInterface), MyInterface) then begin

Writeln('.NET App dynamically calling into Win32 DLL'); Writeln('The Answer is ', MyInterface.Bar); MyInterface.Foo('.NET client'); Writeln(MyInterface.Greeting('Ida')); end else

Writeln('Cannot find Win32NativeDLL.DLL!');

end;

In effect you are dynamically loading the DLL if and only if it is available. If not, the application can continue running, but with reduced functionality. It also allows the application to control the folder the native DLL is loaded from—this can be tricky to do otherwise.

Tip Use the LibraryInterface attribute to control calling convention and the wideness of string parameters. The defaults are CharSet.Auto (PChar on Win9x and PWideChar on WinNT) and CallingConvention.Winapi (or stdcall).
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2022/5/11 21:58:07
4楼: Using the Dll Import Custom Attribute
Last Updated on Tue, 10 May 2022 | Delphi for Microsoft
You can call unmanaged Win32 APIs (and other unmanaged code) by prefixing the function declaration with the DllImport custom attribute. This attribute resides in the System.Runtime.interopServices namespace, as shown below:

Program HellowWorld2;
Don't forget to include the InteropServices unit when using the DllImport attribute. uses System.Runtime.InteropServices;
DllImport('user32.dll')]
function MessageBeep(uType : LongWord) : Boolean; external; begin

MessageBeep(LongWord(-1));

end.

Note the external keyword is still required, to replace the block in the function declaration. All other attributes, such as the calling convention, can be passed through the DllImport custom attribute.
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行99.60938毫秒 RSS