Skip to content

Latest commit

 

History

History
75 lines (55 loc) · 2.38 KB

File metadata and controls

75 lines (55 loc) · 2.38 KB

Passing nil in Native Mode

Background

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.

The Problem

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);

The Fix

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.

Affected Types

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

Summary

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.