Skip to content

fschetterer/Delphi-WinMD-Generator

Repository files navigation

Delphi WinMD Parser & Code Generator

This fork extends Paul Toth's WinMD Parser into a full Win32 API code generator producing ready-to-use Delphi units covering the entire Windows.Win32 namespace — functions, records, enums, callbacks, and COM interfaces.

Generator (WinMDGen.exe):

  • Two output modes: Alias (compatible with VCL/RTL/third-party) and Native (strict handle-type checking)
  • Correct parameter directions (out/var/[Ref] const) derived from WinMD metadata
  • Automatic circular unit reference detection and breaking
  • {$EXTERNALSYM} annotations and XML doc comments from WinMD
  • Optional delayed DLL loading (delayed keyword on all externals; disable with --no-delay)

Parser extensions:

  • Parameter direction flags read from the Param metadata table
  • Enum [Ref] const unwrapping, void-buffer out-param detection
  • Nested/anonymous type inlining, fixed-size array fields
  • SQLite metadata DB for offline inspection and cycle analysis

Use --help for all command-line options.

Prerequisites

  • Windows.Win32.winmd — download from NuGet, extract Windows.Win32.winmd and place in bin/ (or supply the path as the first argument)
  • SQLite DLL (sqlite3.dll) — required for the metadata DB. If not already on your system PATH, place sqlite3.dll in bin/. Download from sqlite.org (Precompiled Binaries for Windows, 64-bit DLL).

Documentation


Original Parser

The WinMD metadata parser was created by Paul Toth.

This Delphi application allows you to read Windows Metadata (WinMD) files.

You can find some WinMD files in C:\Windows\System32\WinMetadata

But the main purpose of this project is to read Windows.Win32.winmd, the metafile of Win32 API, like CsWin32 but to generate Delphi files.

GUI Browser

screenshot


Generation Modes

WinMDGen supports two output modes, selected via the --native command-line flag.

Default (Alias) Mode — recommended for general Delphi development

NativeSwappable types (BOOL, HANDLE, HWND, RECT, etc.) are declared as aliases in Winmd.Winapi.Windows.pas, resolving to the same underlying types that Winapi.Windows and the Delphi RTL already use:

HWND    = Winapi.Windows.HWND     // = NativeUInt
HANDLE  = THandle                  // = NativeUInt
BOOL    = LongBool
BOOLEAN = ByteBool
RECT    = System.Types.TRect       // has Width, Height, helpers

All generated units are fully compatible with VCL, RTL, third-party component libraries, and existing Delphi code that uses Winapi.Windows.

Trade-off: No compile-time distinction between handle types — the compiler accepts an HFONT where HWND was expected, since both resolve to NativeUInt.

Native Mode — standalone Win32 projects only

Handle and struct types generate as WinMD record wrappers, exactly as the metadata defines them:

HWND    = record Value: NativeUInt; end;
HANDLE  = record Value: NativeUInt; end;
HFONT   = record Value: NativeUInt; end;
HRESULT = record Value: LONG; end;
RECT    = record left, top, right, bottom: INT32; end;

Primitive boolean and string-pointer types flatten to Delphi built-ins:

BOOL    = LongBool    // 32-bit integer, any nonzero = True (matches Win32 BOOL = int)
BOOLEAN = ByteBool    // 8-bit integer, any nonzero = True (matches Win32 BOOLEAN = BYTE)
PWSTR   = PWideChar
PSTR    = PAnsiChar

Gain: The compiler enforces handle type correctness — passing HFONT where HWND is expected is a compile error, matching C's typedef-based type checking.

Pitfalls — do not use Native mode if your project:

Scenario Problem
Uses VCL TWinControl.Handle returns Winapi.Windows.HWND = NativeUInt, not a record — every SendMessage / PostMessage call fails with E2010
Uses RTL Win32 wrappers LocalFree, CreateFile, FindFirstFile etc. take Winapi.Windows handle types — type mismatch at every call
Uses third-party components DevExpress, Indy, FastReport and virtually every Delphi component library uses Winapi.Windows types — incompatible
Uses COM/OLE OleCheck, Succeeded, Failed expect HRESULT = Longint; native HRESULT = record breaks all COM interop
Uses TRect helpers Native RECT is a bare record with no Width, Height, Union, Intersect methods

Native mode is viable only for a self-contained project with no dependency on Winapi.Windows, VCL, or third-party Delphi components — for example, a pure Win32 service or tool that controls all its type dependencies end-to-end.

Enum parameters and [Ref] const

Win32 APIs that accept a pointer to an enum (e.g. PFIRMWARE_TYPE, PFILE_COMPRESSION_TYPE) are generated as [Ref] const parameters — the pointer is stripped and Delphi passes the value by hidden const reference, matching the C calling convention.

By default the parameter is emitted with its enum type:

function SetupDecompressOrCopyFile(SourceFile: PWSTR; TargetFile: PWSTR;
  [Ref] const CompressionType: FILE_COMPRESSION_TYPE): DWORD; stdcall;

Delphi 12/13 workaround: a compiler bug (F2084/C2792) fires when a typed [Ref] const EnumType parameter is nested inside certain expressions. If you hit this, define WINMD_UNTYPED_ENUM_REFCONST in the WinMDGen project options and recompile the generator. The output will switch to an untyped form:

function SetupDecompressOrCopyFile(SourceFile: PWSTR; TargetFile: PWSTR;
  [Ref] const CompressionType): DWORD; stdcall;

The untyped form is fully ABI-compatible and works on all supported Delphi versions.

Boolean type semantics

Both modes correctly distinguish the two Windows boolean types:

Win32 type C definition Delphi mapping Semantics
BOOL typedef int (32-bit) LongBool Any nonzero = True
BOOLEAN typedef BYTE (8-bit) ByteBool Any nonzero = True

Using Boolean (strict 0/1) for either would silently misclassify Win32 API return values that use nonzero values other than 1 to signal success.

Building

Requires Delphi 10 Seattle or later.

cd src
~BuildDEBUG.cmd

Resources

About

Delphi WinMD Parser & Code Generator

Resources

License

Stars

Watchers

Forks

Contributors

Languages