In the Windows SDK, many pointer types are simple typedefs:
typedef WCHAR *PWSTR;
typedef CHAR *PSTR;In alias mode (the default), the WinMD generator maps these directly to their Delphi
equivalents (PWideChar, PAnsiChar, etc.), so passing nil works as expected.
In native mode, the generator produces the actual WinMD struct definitions. Microsoft
encodes pointer typedefs in WinMD metadata as value-type structs tagged with a
[NativeTypedef] attribute:
PWSTR = record
Value: PWideChar;
end;
This is intentional — it lets the metadata distinguish between PWSTR and PSTR even
though both are pointer-sized. Without the struct wrapper, the metadata would lose that
semantic distinction.
Because PWSTR (and similar types) are Delphi records in native mode, you cannot
pass nil or use a typed cast like PWSTR(nil) — neither is valid for a record type.
// Fails in native mode:
GetComputerNameEx(ComputerNameNetBIOS, nil, Size);
GetComputerNameEx(ComputerNameNetBIOS, PWSTR(nil), Size);Use Default(T) to zero-initialise the record. This sets all fields to zero/nil,
so Value becomes nil — identical to what the Win32 API receives when a null
pointer is passed directly.
// Works in both alias and native mode:
GetComputerNameEx(ComputerNameNetBIOS, Default(PWSTR), Size);Default(T) is the correct Delphi idiom for a "null" value of any type, including
records. The Win32 API cannot distinguish between a null pointer and a zero-initialised
single-field record whose field is nil — both result in a null pointer on the stack.
Any type in the [NativeSwappable] section of Windows.Win32.typemap that is a
pointer typedef in the original C SDK. Common examples:
| Type | C SDK | Native mode |
|---|---|---|
PWSTR |
WCHAR * |
record Value: PWideChar end |
PSTR |
CHAR * |
record Value: PAnsiChar end |
HANDLE |
void * |
record Value: THandle end |
HWND |
void * (window handle) |
record Value: ... end |
| Mode | nil |
PWSTR(nil) |
Default(PWSTR) |
|---|---|---|---|
| Alias | ✓ | ✓ | ✓ |
| Native | ✗ | ✗ | ✓ |
Always use Default(T) when passing a null value for a pointer-typedef type if your
code needs to compile in both modes.