NtUtilsLibrary
Delphi library for system programming on Windows using Native API
Install / Use
/learn @diversenok/NtUtilsLibraryREADME
NtUtils Library
NtUtils is a framework for Windows system programming in Delphi that provides a set of functions with better error handling and language integration than regular Winapi/Ntapi headers, combined with frequently used code snippets and intelligent data types.
You can find some example code in a dedicated repository.
Dependencies
Library Structure
The library has a layered structure with three layers in total:
- Headers layer defines data types and annotated function prototypes from Windows and Native API. It brings zero dependencies and contains almost no code. Note that the library is self-sufficient and doesn't import Winapi units that are included with Delphi. It's possible to mix the built-in
Winapi.*.pasand libraryNtapi.*.pasheaders in your program; although, it might require explicitly specifying the namespace prefix in case of conflicting names. - NtUtils layer provides most of the functionality of the library by offering hundreds of wrappers for various categories of OS APIs. It depends exclusively on the headers layer and not even on System.SysUtils, so it barely increases the size of compiled executables.
- NtUiLib layer adds support for reflective data representation meant for the end-users. It depends on NtUtils,
System.SysUtils,System.Rtti, andSystem.Generics.Collections. Update: the library is currently transitioning to our custom lightweight RTTI/reflection engine (without any of above-mentioned dependencies likeSystem.Rtti), so information on this layer is becoming outdated.
Therefore, everything you need is already included with the latest free version of Delphi. As a bonus, compiling console applications without RTTI (aka reflection) yields extremely small executables. See examples for more details.
Unit Auto-discovery
Since including every file from the library into your projects is usually redundant, you can configure Delphi for file auto-discovery. This way, you can specify a unit in the uses section, and Delphi will automatically include it and its dependencies into the project. To configure the folders where Delphi performs the search, go to Project -> Options -> Building -> Delphi Compiler and add the following lines into the Search Path:
.\NtUtilsLibrary
.\NtUtilsLibrary\Headers
.\NtUtilsLibrary\NtUiLib
If the folder names or locations are different for your project, you need to adjust these lines correspondingly.
Error Handling
TNtxStatus
The library indicates failures to the caller by returning unsuccessful TNtxStatus values. TNtxStatus (defined in NtUtils.pas) is a structure that stores an error code (compatible with NTSTATUS, HRESULT, and a Win32 Errors) plus metadata about the nature of the attempted operation, such as the location of the failure, a stacktrace, and other details like expected/requested access mask for open calls or the info class value for query/set calls. To check if TNtxStatus is successful, use its IsSuccess method. To access or set the underlying error code (depending on its type and the caller's preference) use properties such as Status, HResult, HResultAllowFalse, Win32Error, Win32ErrorOrSuccess, IsHResult, IsWin32, etc.
Exceptions
If you prefer using exceptions, you can always call RaiseOnError() on a given TNtxStatus. Note that unless you really want to use exceptions without importing System.SysUtils (which is possible), it's better to include NtUiLib.Exceptions that brings a dedicated ENtError exception class (derived from the built-in EOSError).
Error Representation
NtUiLib.Errors attaches four methods for representing TNtxStatus values as strings. For instance, if the error with value 0xC0000061 comes from an attempt to change a session ID of a token, these methods will return the following information:
Method | Returned string
------------- | ---------------
Name | STATUS_PRIVILEGE_NOT_HELD
Description | A required privilege is not held by the client
Summary | Privilege Not Held
ToString | NtSetInformationToken returned STATUS_PRIVILEGE_NOT_HELD
If you want to go even further and show a pretty message box to the user, NtUiLib.Errors.Dialog offers ShowNtxStatus(). Additionally, including NtUiLib.Exceptions.Dialog will bring necessary reflection support and enrich the dialog even further. Here is an example of how it might look:

Stack Traces & Debug Symbols
TNtxStatus supports capturing stack traces (disabled by default). To enable it, set NtUtils.CaptureStackTraces to True. Keep in mind that displaying stack traces in a meaningful way requires configuring generation of debug symbols for your executable. Unfortunately, Delphi can only output simple text-based .map files while this feature (and 3-rd party debuggers) require either .dbg (older format) or .pdb (newer format) symbols. To automatically generate .pdb files, do the following:
- Enable
.mapfile generation in your project settings: Project -> Options -> Building -> Delphi Compiler -> Linking -> Map File -> "Detailed". - Optionally, if you want to include line number information: Project -> Options -> Building -> Delphi Compiler -> Compiling -> Debugging -> Debug Information -> Select "Debug information". Note that for the change to take effect, you might need to delete existing
.dcufiles and then recompile your project from scratch. - Download or build map2pdb and place its executable where Delphi can find it.
- Add the following post-build event in your project settings (Project -> Options -> Building -> Build Events -> Post-build events -> Commands):
cd $(OUTPUTDIR)
map2pdb.exe -bind:$(OUTPUTFILENAME) $(OUTPUTNAME).map
- Select execute conditions via Project -> Options -> Building -> Build Events -> Post-build events -> Execute when "Target is out of date".
The script will produce a .pdb with debug symbols and attach required metadata (a debug directory) to the executable every time you compile the project.
Automatic Lifetime Management
Delphi does not include a garbage collector, so only a few types are managed out-of-the-box: records, strings, dynamic arrays, and interfaces. Classes and record pointers, on the other hand, require explicit cleanup which (in its safe form) means using try-finally blocks and, therefore, complicates the program significantly. To address this issue, the library includes facilities for automatic lifetime management of memory and other resources, implemented in DelphiUtils.AutoObjects as dedicated wrappers:
graph LR;
subgraph id1[Resources that rely on automatic cleanup]
IAutoReleasable
end
subgraph id2[A THandle value]
IHandle
end
subgraph id3[A Delphi class]
IObject[IObject<T>]
end
subgraph id4[A memory pointer]
IPointer[IPointer<P>]
end
subgraph id5[A memory region]
IMemory[IMemory<P>]
end
subgraph id6[A deferred procedure]
IDeferredOperation
end
IAutoReleasable --> IHandle;
IAutoReleasable --> IObject;
IAutoReleasable --> IPointer;
IPointer --> IMemory;
IAutoReleasable --> IDeferredOperation;
Classes and Records
The recipe for using automatic lifetime management is the following:
-
Define every variable that needs to maintain (a potentially shared) ownership over a resource using one of the interfaces:
- For classes, use IObject<TMyObject>.
- For dynamic memory accessible via a pointer, use IMemory, also known as IMemory<Pointer>.
- For (managed) boxed records, use IMemory<PMyRecord>.
-
Use the Auto helper for allocating/copying/capturing objects:
- Auto.CaptureObject<TMyObject>(...) to capture ownership of a class object derived from TObject.
- Auto.AllocateDynamic(...) and Auto.CopyDynamic(...) to capture ownership over a new dynamic memory allocation.
- Auto.Allocate<TMyRecord>(...) and Auto.Copy<TMyRecord>(...) to capture ownership over a new managed boxed record stored on the heap.
-
Access the underlying resource by using the corresponding method/property on the wrapper:
Selffor classes.DataandSizefor pointers to records.
-
Do not manually call
Destroy,Free,FreeMem,Finalize, or similar functions. It will happen automatically.
By wrapping resources requiring explicit cleanup into dedicated (genetic) interfaces, we instruct the compiler to generate thread- and exception-safe code for counting references and releasing the underlying resource whenever the wrapper goes out of scope.
For example, here is a safe code for working with a TStringList using the classical approach:
var
x: TStringList;
begin
x := TStringList.Create;
try
x.Add('Hi there');
x.SaveToFile('test.txt');
finally
x.Free;
end;
end;
As you can imagine, using more objects in this function can drastically increase its complexity due to nesting try-finally blocks or keeping track of which variables were initialized. Alternatively, here is the equivalent code that uses IObject and scales way better:
uses
DelphiUtils.AutoObjects;
var
x: IObject<TStringList>;
begin
x := Auto.CaptureObject(TStringList.Create);
x.Self.Add('Hi there');
x.Self.SaveToFile('test.txt');
end;
The compiler emits the necessary cle
Related Skills
node-connect
346.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
107.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
346.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
346.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
