app.dhover×224 error×65all
// F11 — Scroll fidelity, Win32 implementation (../../../features/f11-scroll.md).
// Extends the scaffold (../scaffold/app.d) into a wheel-message observatory:
//
//   * WM_MOUSEWHEEL / WM_MOUSEHWHEEL handlers log every event's raw signed
//     wheelDelta (GET_WHEEL_DELTA_WPARAM), key state, and screen position.
//   * The ACCUMULATION CONTRACT is implemented and proved: sub-WHEEL_DELTA
//     remainders are carried in an accumulator until |acc| >= 120, then turned
//     into line scrolls (`acc=… detents=…` in every scroll line). The buggy
//     per-event truncation model runs side by side, and a per-gesture summary
//     diffs the two; WSI_TRUNCATE=1 makes the BUGGY model drive the ruler.
//   * Gestures are injected via SendInput MOUSEEVENTF_WHEEL / _HWHEEL with
//     mouseData = ±120 (one detent), ±40 (sub-detent, precision-touchpad
//     style), +360 (multi-detent), and a +40/-40/+40 jitter burst (net 40 —
//     must produce ZERO lines).
//   * Routing probe: a second window is created beside the main one; with
//     focus on MAIN and the cursor parked over OTHER, a wheel event is
//     injected and the receiving window logged (focus routing vs
//     window-under-cursor routing; SPI_GETMOUSEWHEELROUTING is probed).
//   * SPI_GETWHEELSCROLLLINES / SPI_GETWHEELSCROLLCHARS are logged; a
//     scrollable ruler (tick every line, numbered every 5) renders the
//     line-scroll output so over/under-scroll is visible.
//
// WSI_AUTO_EXIT=1 bounds the run (~1.5 s); exit 0 in all modes.
//
// Only druntime's built-in core.sys.windows bindings — no third-party packages.
module 
(module) app
app
;
import
(package) core
core
.
(package) core.sys
sys
.
(package) core.sys.windows
windows
.
(module) core.sys.windows.windows

Windows API header module

Translated from MinGW API for MS-Windows 4.0

Source

core/sys/windows/windows.d

windows
;
import instrument;
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
unable to read module `instrument` Expected 'instrument.d' or 'instrument/package.d' in one of the following import paths:
// Missing from druntime's core.sys.windows.winuser: enum DWORD
(constant) _error_ app.MOUSEEVENTF_HWHEEL = __error
MOUSEEVENTF_HWHEEL
= 0x1000; // SendInput horizontal-wheel flag
undefined identifier `DWORD`
enum UINT
(constant) _error_ app.SPI_GETWHEELSCROLLCHARS = __error
SPI_GETWHEELSCROLLCHARS
= 0x006C;
undefined identifier `UINT`
enum UINT
(constant) _error_ app.SPI_GETMOUSEWHEELROUTING = __error
SPI_GETMOUSEWHEELROUTING
= 0x201C;
undefined identifier `UINT`
// SPI_GETMOUSEWHEELROUTING values: // 0 = MOUSEWHEEL_ROUTING_FOCUS, 1 = MOUSEWHEEL_ROUTING_HYBRID (Win8/8.1), // 2 = MOUSEWHEEL_ROUTING_MOUSE_POS (Win10+ "scroll inactive windows" default) enum UINT_PTR
(constant) _error_ app.TIMER_ID = __error
TIMER_ID
= 1;
undefined identifier `UINT_PTR`
enum
(constant) int app.TICK_MS = 16
TICK_MS
= 16;
enum
(constant) int app.LINE_PX = 14
LINE_PX
= 14; // ruler row height
// --------------------------------------------------------------------------- // Per-axis scroll state: the correct carry-the-remainder accumulator next to // the buggy per-event-truncation model. struct
(struct) app.Axis
Axis
{ int
(field) int app.Axis.acc
acc
; // carried sub-120 remainder (correct model)
int
(field) int app.Axis.detents
detents
; // total detents emitted by the correct model
int
(field) int app.Axis.truncDetents
truncDetents
; // total detents emitted by per-event truncation (buggy)
int
(field) int app.Axis.gEvents
gEvents
,
(field) int app.Axis.gDelta
gDelta
,
(field) int app.Axis.gDetents
gDetents
,
(field) int app.Axis.gTruncDetents
gTruncDetents
; // per-gesture counters
} struct
(struct) app.Demo
Demo
{ HDC
(field) _error_ app.Demo.memDc
memDc
;
undefined identifier `HDC`
HBITMAP
(field) _error_ app.Demo.dib
dib
,
(field) _error_ app.Demo.stockBmp
stockBmp
;
undefined identifier `HBITMAP`
undefined identifier `HBITMAP`
uint*
(field) uint* app.Demo.pixels
pixels
;
int
(field) int app.Demo.width
width
,
(field) int app.Demo.height
height
;
uint
(field) uint app.Demo.frame
frame
,
(field) uint app.Demo.ticks
ticks
;
HWND
(field) _error_ app.Demo.hwnd
hwnd
,
(field) _error_ app.Demo.other
other
;
undefined identifier `HWND`
undefined identifier `HWND`
bool
(field) bool app.Demo.autoExit
autoExit
;
bool
(field) bool app.Demo.truncate
truncate
; // WSI_TRUNCATE=1: the buggy model drives the ruler
(struct) app.Axis
Axis
(field) app.Axis app.Demo.v
v
,
(field) app.Axis app.Demo.h
h
;
int
(field) int app.Demo.scrollLines
scrollLines
= 3; // SPI_GETWHEELSCROLLLINES
int
(field) int app.Demo.rulerLine
rulerLine
; // ruler offset in lines (driven by v-axis detents)
const(char)*
(field) const(char)* app.Demo.gesture
gesture
= "";
} __gshared
(struct) app.Demo
Demo
_error_ app.g
g
;
// --------------------------------------------------------------------------- // Wheel handling: one handler for both axes and both windows. void
app.onWheel
onWheel
(HWND
(parameter) HWND hwnd
hwnd
, const(char)* axis, ref
(struct) app.Axis
Axis
(parameter) Axis ax
ax
, WPARAM wParam, LPARAM lParam) nothrow
undefined identifier `HWND`
undefined identifier `WPARAM`
undefined identifier `LPARAM`
{ const
_error_ delta
delta
= GET_WHEEL_DELTA_WPARAM(wParam); // signed; multiple/fraction of 120
const
_error_ target
target
= hwnd is g.
g.hwnd
hwnd
? "main".ptr : "other".ptr;
// Correct model: accumulate, emit detents, CARRY the remainder. // (D's / truncates toward zero, so the remainder keeps the right sign.) ax.
ax.acc
acc
+= delta;
const
_error_ d
d
= ax.
ax.acc
acc
/ WHEEL_DELTA;
ax.
ax.acc
acc
-= d * WHEEL_DELTA;
// Buggy model: truncate each event in isolation — ±40 events vanish. const
_error_ td
td
= delta / WHEEL_DELTA;
ax.
ax.detents
detents
+= d;
ax.
ax.truncDetents
truncDetents
+= td;
ax.
ax.gEvents
gEvents
++;
ax.
ax.gDelta
gDelta
+= delta;
ax.
ax.gDetents
gDetents
+= d;
ax.
ax.gTruncDetents
gTruncDetents
+= td;
logEvent("scroll axis=%s value=%d target=%s screen=%d,%d keys=0x%x acc=%d detents=%d trunc_detents=%d", axis, delta, target, cast(int) cast(short)(lParam & 0xffff), cast(int) cast(short)((lParam >> 16) & 0xffff), cast(uint)(wParam & 0xffff), ax.
ax.acc
acc
, d, td);
if (hwnd is g.
g.hwnd
hwnd
&& axis[0] == 'v')
{ const
_error_ lines
lines
= (g.
g.truncate
truncate
? td : d) * g.
g.scrollLines
scrollLines
;
if (lines != 0) { g.
g.rulerLine
rulerLine
+= lines;
logEvent("ruler scroll lines=%d pos_line=%d", lines, g.
g.rulerLine
rulerLine
);
} } } void
void app.gestureBegin(const(char)* name) nothrow
gestureBegin
(const(char)*
(parameter) const(char)* name
name
) nothrow
{ g.
g.gesture
gesture
= name;
g.
(field) _error_ g.v
v
.
g.v.gEvents
gEvents
= g.
g.v
v
.
g.v.gDelta
gDelta
= g.
g.v
v
.
g.v.gDetents
gDetents
= g.
g.v
v
.
g.v.gTruncDetents
gTruncDetents
= 0;
g.
(field) _error_ g.h
h
.
g.h.gEvents
gEvents
= g.
g.h
h
.
g.h.gDelta
gDelta
= g.
g.h
h
.
g.h.gDetents
gDetents
= g.
g.h
h
.
g.h.gTruncDetents
gTruncDetents
= 0;
logEvent("gesture_begin name=%s", name);
undefined identifier `logEvent`
} void
void app.gestureEnd() nothrow
gestureEnd
() nothrow
{ foreach (
(parameter) i
i
,
(parameter) ax
ax
; [&g.
(field) _error_ g.v
v
, &g.
(field) _error_ g.h
h
])
if (ax.
ax.gEvents
gEvents
!= 0)
logEvent("gesture_summary name=%s axis=%s events=%d delta_total=%d detents=%d trunc_detents=%d acc_left=%d lost_by_truncation=%d", g.
g.gesture
gesture
, i == 0 ? "v".ptr : "h".ptr, ax.
ax.gEvents
gEvents
, ax.
ax.gDelta
gDelta
,
ax.
ax.gDetents
gDetents
, ax.
ax.gTruncDetents
gTruncDetents
, ax.
ax.acc
acc
,
ax.
ax.gDetents
gDetents
- ax.
ax.gTruncDetents
gTruncDetents
);
} // --------------------------------------------------------------------------- // Injection. void
void app.injectWheel(bool horiz, int data) nothrow
injectWheel
(bool
(parameter) bool horiz
horiz
, int
(parameter) int data
data
) nothrow
{ INPUT
(local variable) _error_ inp
inp
;
undefined identifier `INPUT`
inp.type = INPUT_MOUSE; inp.mi.mouseData = cast(DWORD) data; inp.mi.dwFlags = horiz ? MOUSEEVENTF_HWHEEL : MOUSEEVENTF_WHEEL; logEvent("inject axis=%s data=%d", horiz ? "h".ptr : "v".ptr, data);
undefined identifier `logEvent`
if (SendInput(1, &inp, INPUT.sizeof) != 1)
undefined identifier `SendInput`
logEvent("error what=SendInput code=%lu", GetLastError());
undefined identifier `logEvent`
} // --------------------------------------------------------------------------- // Backbuffer + ruler rendering: a tick row every line, a bright major row // every 5 lines, offset by the scrolled line count. void
void app.createBackbuffer(int w, int h) nothrow
createBackbuffer
(int
(parameter) int w
w
, int
(parameter) int h
h
) nothrow
{ if (g.
(field) _error_ g.dib
dib
!is null)
{ SelectObject(g.
g.memDc
memDc
, g.
g.stockBmp
stockBmp
);
undefined identifier `SelectObject`
DeleteObject(g.
g.dib
dib
);
undefined identifier `DeleteObject`
g.
g.dib
dib
= null;
g.
g.pixels
pixels
= null;
g.
g.width
width
= g.
g.height
height
= 0;
} if (
(parameter) int w
w
<= 0 ||
(parameter) int h
h
<= 0)
return; BITMAPINFO
(local variable) _error_ bmi
bmi
;
undefined identifier `BITMAPINFO`
bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biHeight = -h; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; void*
(local variable) void* bits
bits
;
g.
g.dib
dib
= CreateDIBSection(null, &bmi, DIB_RGB_COLORS, &bits, null, 0);
if (g.
(field) _error_ g.dib
dib
is null)
{ logEvent("error what=CreateDIBSection code=%lu", GetLastError());
undefined identifier `logEvent`
return; } g.
g.pixels
pixels
= cast(uint*) bits;
g.
g.width
width
= w;
g.
g.height
height
= h;
g.
g.stockBmp
stockBmp
= cast(HBITMAP) SelectObject(g.
g.memDc
memDc
, g.
g.dib
dib
);
} void
void app.drawFrame() nothrow
drawFrame
() nothrow
{ if (g.
(field) _error_ g.pixels
pixels
is null)
return; const
(local variable) const(_error_) w
w
= g.
(field) _error_ g.width
width
,
(local variable) const(_error_) h
h
= g.
(field) _error_ g.height
height
;
foreach (
(parameter) y
y
; 0 .. h)
{ uint*
_error_ row
row
= g.
g.pixels
pixels
+ cast(size_t) y * w;
// worldLine of this row, given the current scroll offset const
_error_ world
world
= y + g.
g.rulerLine
rulerLine
* LINE_PX;
int
_error_ m
m
= world % LINE_PX;
if (m < 0) m += LINE_PX; const
_error_ lineNo
lineNo
= (world - m) / LINE_PX;
const
_error_ isTick
isTick
= m == 0;
const
_error_ major
major
= isTick && lineNo % 5 == 0;
const
_error_ bg
bg
= cast(uint)(0x101820 + ((lineNo & 1) ? 0x080808 : 0));
const
_error_ tickLen
tickLen
= major ? w : w / 8;
foreach (
(parameter) x
x
; 0 .. w)
row[x] = isTick && x < tickLen ? (major ? 0xffffff : 0x607080) : bg; } } // --------------------------------------------------------------------------- // The bounded-run schedule (one entry per WM_TIMER tick). void
app.runSchedule
runSchedule
(HWND
(parameter) HWND hwnd
hwnd
) nothrow
undefined identifier `HWND`
{ switch (g.
g.ticks
ticks
)
{ case 4: gestureBegin("one_detent_up"); injectWheel(false, WHEEL_DELTA); // +120: away from the user break; case 8: gestureEnd(); break; case 10: gestureBegin("one_detent_down"); injectWheel(false, -WHEEL_DELTA); break; case 14: gestureEnd(); break; case 16: // 3 x +40: each event is sub-detent; only the SUM is one detent gestureBegin("sub_detent_x3"); injectWheel(false, 40); injectWheel(false, 40); injectWheel(false, 40); break; case 22: gestureEnd(); break; case 24: gestureBegin("sub_detent_x3_down"); injectWheel(false, -40); injectWheel(false, -40); injectWheel(false, -40); break; case 30: gestureEnd(); break; case 32: // one event carrying three detents at once gestureBegin("multi_detent"); injectWheel(false, 3 * WHEEL_DELTA); break; case 36: gestureEnd(); break; case 38: // net +40: the accumulator must NOT emit a line (and not lose it) gestureBegin("jitter_no_detent"); injectWheel(false, 40); injectWheel(false, -40); injectWheel(false, 40); break; case 44: gestureEnd(); break; case 46: gestureBegin("horizontal"); injectWheel(true, WHEEL_DELTA); injectWheel(true, -40); injectWheel(true, -40); injectWheel(true, -40); break; case 52: gestureEnd(); break; case 54: // routing: focus on MAIN, cursor over OTHER, who gets the wheel? gestureBegin("routing_probe"); RECT
_error_ rc
rc
;
GetWindowRect(g.
g.other
other
, &rc);
const
_error_ cx
cx
= (rc.left + rc.right) / 2,
_error_ cy
cy
= (rc.top + rc.bottom) / 2;
SetCursorPos(cx, cy); POINT
_error_ p
p
;
GetCursorPos(&p); logEvent("routing_probe focus=%s cursor_over=other requested=%d,%d actual=%d,%d", GetFocus() is g.
g.hwnd
hwnd
? "main".ptr : "other".ptr,
cast(int) cx, cast(int) cy, cast(int) p.
p.x
x
, cast(int) p.
p.y
y
);
break; case 56: injectWheel(false, WHEEL_DELTA); break; case 60: gestureEnd(); RECT
_error_ rc
rc
;
GetWindowRect(hwnd, &rc); SetCursorPos((rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2); break; case 64: logEvent("summary v_detents=%d v_trunc_detents=%d v_acc=%d h_detents=%d h_trunc_detents=%d h_acc=%d ruler_pos_line=%d", g.
g.v
v
.
g.v.detents
detents
, g.
g.v
v
.
g.v.truncDetents
truncDetents
, g.
g.v
v
.
g.v.acc
acc
,
g.
g.h
h
.
g.h.detents
detents
, g.
g.h
h
.
g.h.truncDetents
truncDetents
, g.
g.h
h
.
g.h.acc
acc
, g.
g.rulerLine
rulerLine
);
DestroyWindow(hwnd); break; default: break; } } // --------------------------------------------------------------------------- extern (Windows) LRESULT
app.wndProc
wndProc
(HWND
(parameter) HWND hwnd
hwnd
, UINT
(parameter) UINT msg
msg
, WPARAM wParam, LPARAM lParam) nothrow
undefined identifier `LRESULT`
undefined identifier `HWND`
undefined identifier `UINT`
undefined identifier `WPARAM`
undefined identifier `LPARAM`
{ switch (msg) { case WM_CREATE: if (g.
g.memDc
memDc
is null)
g.
g.memDc
memDc
= CreateCompatibleDC(null);
return 0; case WM_MOUSEWHEEL: onWheel(hwnd, "v", g.
g.v
v
, wParam, lParam);
return 0; case WM_MOUSEHWHEEL: onWheel(hwnd, "h", g.
g.h
h
, wParam, lParam);
return 0; // an app that handles WM_MOUSEHWHEEL must return zero case WM_SIZE: const
_error_ w
w
= cast(int)(lParam & 0xffff);
const
_error_ h
h
= cast(int)((lParam >> 16) & 0xffff);
if (wParam == SIZE_MINIMIZED) return 0; if (hwnd is g.
g.hwnd
hwnd
&& (w != g.
g.width
width
|| h != g.
g.height
height
))
createBackbuffer(w, h); return 0; case WM_PAINT: PAINTSTRUCT
_error_ ps
ps
;
HDC
_error_ hdc
hdc
= BeginPaint(hwnd, &ps);
if (hwnd is g.
g.hwnd
hwnd
)
{ ++g.
g.frame
frame
;
drawFrame(); if (g.
g.pixels
pixels
!is null)
BitBlt(hdc, 0, 0, g.
g.width
width
, g.
g.height
height
, g.
g.memDc
memDc
, 0, 0, SRCCOPY);
} EndPaint(hwnd, &ps); return 0; case WM_TIMER: if (wParam != TIMER_ID) return 0; ++g.
g.ticks
ticks
;
InvalidateRect(hwnd, null, FALSE); if (g.
g.autoExit
autoExit
)
runSchedule(hwnd); return 0; case WM_CLOSE: logEvent("close_requested"); goto default; case WM_DESTROY: if (hwnd !is g.
g.hwnd
hwnd
)
goto default; KillTimer(hwnd, TIMER_ID); createBackbuffer(0, 0); if (g.
g.memDc
memDc
!is null)
{ DeleteDC(g.
g.memDc
memDc
);
g.
g.memDc
memDc
= null;
} PostQuitMessage(0); return 0; default: return DefWindowProcW(hwnd, msg, wParam, lParam); } } // --------------------------------------------------------------------------- bool
bool app.envFlag(const(wchar)* name) nothrow
envFlag
(const(wchar)*
(parameter) const(wchar)* name
name
) nothrow
{ WCHAR[16]
(local variable) _error_ buf
buf
;
undefined identifier `WCHAR`
const
(local variable) const(_error_) n
n
= GetEnvironmentVariableW(name, buf.ptr, buf.length);
undefined identifier `GetEnvironmentVariableW`
return n >= 1 && n < buf.length && buf[0] == '1'; } int
int D main()
main
()
{ instrumentInit("f11_scroll_win32");
undefined identifier `instrumentInit`
logEvent("init_start");
undefined identifier `logEvent`
g.
g.autoExit
autoExit
= envFlag("WSI_AUTO_EXIT"w.ptr);
g.
g.truncate
truncate
= envFlag("WSI_TRUNCATE"w.ptr);
logEvent("mode auto_exit=%d truncate=%d", g.
g.autoExit
autoExit
? 1 : 0, g.
g.truncate
truncate
? 1 : 0);
undefined identifier `logEvent`
// System scroll parameters. UINT
(local variable) _error_ lines
lines
= 3,
(local variable) _error_ chars
chars
= 3;
undefined identifier `UINT`
undefined identifier `UINT`
const
(local variable) const(_error_) okL
okL
= SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &lines, 0);
undefined identifier `SystemParametersInfoW`
const
(local variable) const(_error_) okC
okC
= SystemParametersInfoW(SPI_GETWHEELSCROLLCHARS, 0, &chars, 0);
undefined identifier `SystemParametersInfoW`
if (okL && lines > 0 && lines != WHEEL_PAGESCROLL)
undefined identifier `WHEEL_PAGESCROLL`
g.
g.scrollLines
scrollLines
= cast(int) lines;
logEvent("wheel_params scroll_lines=%u ok=%d scroll_chars=%u ok=%d wheel_delta=%d",
undefined identifier `logEvent`
lines, okL, chars, okC, WHEEL_DELTA); DWORD
(local variable) _error_ routing
routing
= 0xdead;
undefined identifier `DWORD`
SetLastError(0);
undefined identifier `SetLastError`
const
(local variable) const(_error_) okR
okR
= SystemParametersInfoW(SPI_GETMOUSEWHEELROUTING, 0, &routing, 0);
undefined identifier `SystemParametersInfoW`
logEvent("wheel_routing spi=0x201C ok=%d value=%lu err=%lu",
undefined identifier `logEvent`
okR, routing, okR ? 0 : GetLastError()); HINSTANCE
(local variable) _error_ hInst
hInst
= GetModuleHandleW(null);
undefined identifier `HINSTANCE`
undefined identifier `GetModuleHandleW`
HCURSOR
(local variable) _error_ arrow
arrow
= LoadCursorW(null, IDC_ARROW);
undefined identifier `HCURSOR`
undefined identifier `LoadCursorW`
auto
(local variable) wstring clsName
clsName
= "wsi-f11-class"w;
WNDCLASSEXW
(local variable) _error_ wc
wc
;
undefined identifier `WNDCLASSEXW`
wc.cbSize = WNDCLASSEXW.sizeof; wc.lpfnWndProc = &wndProc; wc.hInstance = hInst; wc.lpszClassName = clsName.ptr; wc.hCursor = arrow; if (!RegisterClassExW(&wc))
undefined identifier `RegisterClassExW`
{ logEvent("error what=RegisterClassExW code=%lu", GetLastError());
undefined identifier `logEvent`
return 1; } // Positions chosen to fit a 640x480 Xvfb screen with no overlap, so the // routing probe's cursor-over-other warp stays on-screen under winex11. g.
g.hwnd
hwnd
= CreateWindowExW(0, clsName.ptr, "wsi-f11-scroll"w.ptr,
WS_OVERLAPPEDWINDOW, 20, 140, 480, 320, null, null, hInst, null); if (g.
(field) _error_ g.hwnd
hwnd
is null)
{ logEvent("error what=CreateWindowExW code=%lu", GetLastError());
undefined identifier `logEvent`
return 1; } logEvent("window_created");
undefined identifier `logEvent`
// The routing-probe window: same class (its WM_MOUSEWHEEL logs // target=other), shown beside the main window without taking activation. g.
g.other
other
= CreateWindowExW(0, clsName.ptr, "wsi-f11-other"w.ptr,
WS_OVERLAPPEDWINDOW, 510, 10, 120, 100, null, null, hInst, null); ShowWindow(g.
g.other
other
, SW_SHOWNOACTIVATE);
undefined identifier `ShowWindow`
ShowWindow(g.
g.hwnd
hwnd
, SW_SHOW);
undefined identifier `ShowWindow`
UpdateWindow(g.
g.hwnd
hwnd
);
undefined identifier `UpdateWindow`
// Park the cursor over the main window so cursor-pos routing (if active) // also targets it during the accumulation gestures. RECT
(local variable) _error_ rc
rc
;
undefined identifier `RECT`
GetWindowRect(g.
g.hwnd
hwnd
, &rc);
undefined identifier `GetWindowRect`
SetCursorPos((rc.left + rc.right) / 2, (rc.top + rc.bottom) / 2);
undefined identifier `SetCursorPos`
SetTimer(g.
g.hwnd
hwnd
, TIMER_ID, TICK_MS, null);
undefined identifier `SetTimer`
MSG
(local variable) _error_ msg
msg
;
undefined identifier `MSG`
while (GetMessageW(&msg, null, 0, 0) > 0)
undefined identifier `GetMessageW`
{ TranslateMessage(&msg);
undefined identifier `TranslateMessage`
DispatchMessageW(&msg);
undefined identifier `DispatchMessageW`
} logEvent("exit code=%d", cast(int) msg.wParam);
undefined identifier `logEvent`
return cast(int) msg.wParam; }