app.dhover×155 error×45all
// F14 — Window state & vetoable close, Win32 implementation
// (../../../features/f14-window-state.md). Extends the scaffold
// (../scaffold/app.d) into a state-transition observatory:
//
//   * ShowWindow(SW_MAXIMIZE / SW_MINIMIZE / SW_RESTORE) for the real states,
//     and the borderless-fullscreen IDIOM for fullscreen (Win32 has no
//     fullscreen window state): save GetWindowLongPtrW(GWL_STYLE) +
//     GetWindowRect, strip WS_OVERLAPPEDWINDOW, SetWindowPos to the
//     MonitorFromWindow rect with SWP_FRAMECHANGED; exit reverses it.
//   * Every message until the state settles is logged with decoded payloads:
//     WM_SIZE wParam (SIZE_RESTORED/MINIMIZED/MAXIMIZED/…),
//     WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED (flags + rect),
//     WM_GETMINMAXINFO (ptMaxSize/ptMaxPosition), WM_ACTIVATE (state +
//     minimized flag + peer hwnd), WM_SETFOCUS/WM_KILLFOCUS (peer hwnd — the
//     "where does focus go on minimize" probe), WM_SYSCOMMAND, WM_SHOWWINDOW.
//   * After each transition, GetWindowPlacement is logged (showCmd decode +
//     rcNormalPosition) — the normal-rect memory across max/min/fullscreen.
//   * Vetoable close: a "dirty" flag (key D toggles it interactively). On
//     WM_CLOSE with dirty set: log close_requested veto=1, clear the flag,
//     return 0 WITHOUT DefWindowProcW — Win32's first-class veto (not
//     forwarding to DefWindowProc IS the refusal; no DestroyWindow happens).
//     Second WM_CLOSE → DefWindowProcW → DestroyWindow → WM_DESTROY →
//     PostQuitMessage. The close source is visible because the demo drives it
//     through the real chain: WM_SYSCOMMAND SC_CLOSE (what the title-bar X
//     sends) → DefWindowProc → WM_CLOSE.
//   * WSI_AUTO_EXIT=1 runs the scripted tour: maximize → restore → minimize →
//     restore → fullscreen on → fullscreen off → dirty + SC_CLOSE (vetoed) →
//     SC_CLOSE (closes). Exit 0. Without it: M maximize toggle, N minimize,
//     F fullscreen toggle, R restore, D dirty toggle, close via the X button.
//
// 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:
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.TICKS_PER_STEP = 25
TICKS_PER_STEP
= 25; // ~400 ms settle time between scripted transitions
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
;
bool
(field) bool app.Demo.autoExit
autoExit
;
int
(field) int app.Demo.step
step
; // scripted-tour position
bool
(field) bool app.Demo.dirty
dirty
; // vetoable-close flag
bool
(field) bool app.Demo.closeFromSelf
closeFromSelf
; // we sent the WM_SYSCOMMAND that produced WM_CLOSE
// Borderless-fullscreen idiom state: bool
(field) bool app.Demo.fullscreen
fullscreen
;
LONG_PTR
(field) _error_ app.Demo.savedStyle
savedStyle
;
undefined identifier `LONG_PTR`
RECT
(field) _error_ app.Demo.savedRect
savedRect
;
undefined identifier `RECT`
} __gshared
(struct) app.Demo
Demo
_error_ app.g
g
;
// --------------------------------------------------------------------------- // Backbuffer (scaffold-identical). 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)
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
);
logEvent("buffer_alloc size=%dx%d", w, h);
undefined identifier `logEvent`
} void
void app.drawGradient() nothrow
drawGradient
() 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
;
const
(local variable) const(_error_) blue
blue
= (g.
(field) _error_ g.frame
frame
* 4) & 0xff;
// Red border band when dirty, so the veto state is visible interactively. foreach (
(parameter) y
y
; 0 .. h)
{ uint*
_error_ row
row
= g.
g.pixels
pixels
+ cast(size_t) y * w;
const
_error_ green
green
= h > 1 ? (y * 255) / (h - 1) : 0;
foreach (
(parameter) x
x
; 0 .. w)
{ const
_error_ red
red
= w > 1 ? (x * 255) / (w - 1) : 0;
row[x] = cast(uint)((red << 16) | (green << 8) | blue); if (g.
g.dirty
dirty
&& (x < 8 || y < 8 || x >= w - 8 || y >= h - 8))
row[x] = 0xcc2222; } } } // --------------------------------------------------------------------------- // Decoders + placement probe. const(char)*
app.sizeKind
sizeKind
(WPARAM
(parameter) WPARAM w
w
) nothrow @nogc
undefined identifier `WPARAM`
{ switch (w) { case SIZE_RESTORED: return "SIZE_RESTORED"; case SIZE_MINIMIZED: return "SIZE_MINIMIZED"; case SIZE_MAXIMIZED: return "SIZE_MAXIMIZED"; case SIZE_MAXSHOW: return "SIZE_MAXSHOW"; case SIZE_MAXHIDE: return "SIZE_MAXHIDE"; default: return "?"; } } const(char)*
app.showCmdName
showCmdName
(UINT c) nothrow @nogc
undefined identifier `UINT`
{ switch (c) { case SW_SHOWNORMAL: return "SW_SHOWNORMAL"; case SW_SHOWMINIMIZED: return "SW_SHOWMINIMIZED"; case SW_SHOWMAXIMIZED: return "SW_SHOWMAXIMIZED"; default: return "other"; } } const(char)*
app.activateKind
activateKind
(WPARAM
(parameter) WPARAM w
w
) nothrow @nogc
undefined identifier `WPARAM`
{ switch (LOWORD(w)) { case WA_INACTIVE: return "WA_INACTIVE"; case WA_ACTIVE: return "WA_ACTIVE"; case WA_CLICKACTIVE: return "WA_CLICKACTIVE"; default: return "?"; } } // GetWindowPlacement: showCmd + the remembered normal rect — logged after // every transition to prove the normal-rect memory survives max/min/fullscreen. void
app.logPlacement
logPlacement
(HWND
(parameter) HWND hwnd
hwnd
, const(char)* when) nothrow
undefined identifier `HWND`
{ WINDOWPLACEMENT
_error_ wp
wp
;
wp.length = WINDOWPLACEMENT.sizeof; if (!GetWindowPlacement(hwnd, &wp)) return; const
_error_ r
r
= wp.rcNormalPosition;
logEvent("placement when=%s showCmd=%s normal_rect=%ld,%ld-%ldx%ld iconic=%d zoomed=%d", when, showCmdName(wp.showCmd), r.left, r.top, r.right - r.left, r.bottom - r.top, IsIconic(hwnd) ? 1 : 0, IsZoomed(hwnd) ? 1 : 0); } // --------------------------------------------------------------------------- // The borderless-fullscreen idiom. Win32 has no fullscreen STATE — this is // the documented community idiom (Raymond Chen, "How do I switch a window // between normal and fullscreen?"): save style+rect, strip the frame, size to // the monitor, restore both on the way out. void
app.enterFullscreen
enterFullscreen
(HWND
(parameter) HWND hwnd
hwnd
) nothrow
undefined identifier `HWND`
{ if (g.
g.fullscreen
fullscreen
)
return; g.
g.savedStyle
savedStyle
= GetWindowLongPtrW(hwnd, GWL_STYLE);
GetWindowRect(hwnd, &g.
g.savedRect
savedRect
);
MONITORINFO
_error_ mi
mi
;
mi.cbSize = MONITORINFO.sizeof; GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mi); const
_error_ r
r
= mi.rcMonitor;
logEvent("state_request kind=fullscreen_enter monitor=%ld,%ld-%ldx%ld saved_rect=%ld,%ld-%ldx%ld", r.left, r.top, r.right - r.left, r.bottom - r.top, g.
g.savedRect
savedRect
.left, g.
g.savedRect
savedRect
.top,
g.
g.savedRect
savedRect
.right - g.
g.savedRect
savedRect
.left, g.
g.savedRect
savedRect
.bottom - g.
g.savedRect
savedRect
.top);
SetWindowLongPtrW(hwnd, GWL_STYLE, g.
g.savedStyle
savedStyle
& ~cast(LONG_PTR) WS_OVERLAPPEDWINDOW);
SetWindowPos(hwnd, HWND_TOP, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOOWNERZORDER | SWP_FRAMECHANGED); g.
g.fullscreen
fullscreen
= true;
logPlacement(hwnd, "fullscreen_enter"); } void
app.exitFullscreen
exitFullscreen
(HWND
(parameter) HWND hwnd
hwnd
) nothrow
undefined identifier `HWND`
{ if (!g.
g.fullscreen
fullscreen
)
return; logEvent("state_request kind=fullscreen_exit"); SetWindowLongPtrW(hwnd, GWL_STYLE, g.
g.savedStyle
savedStyle
);
const
_error_ r
r
= g.
g.savedRect
savedRect
;
SetWindowPos(hwnd, null, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED); g.
g.fullscreen
fullscreen
= false;
logPlacement(hwnd, "fullscreen_exit"); } // --------------------------------------------------------------------------- // Scripted tour (WSI_AUTO_EXIT=1), one step every TICKS_PER_STEP timer ticks. void
app.runStep
runStep
(HWND
(parameter) HWND hwnd
hwnd
, int
(parameter) int n
n
) nothrow
undefined identifier `HWND`
{ switch (n) { case 0: logPlacement(hwnd, "initial"); break; case 1: logEvent("state_request kind=maximize api=ShowWindow(SW_MAXIMIZE)"); ShowWindow(hwnd, SW_MAXIMIZE); logPlacement(hwnd, "after_maximize"); break; case 2: logEvent("state_request kind=restore api=ShowWindow(SW_RESTORE)"); ShowWindow(hwnd, SW_RESTORE); logPlacement(hwnd, "after_restore"); break; case 3: logEvent("state_request kind=minimize api=ShowWindow(SW_MINIMIZE)"); ShowWindow(hwnd, SW_MINIMIZE); logPlacement(hwnd, "after_minimize"); logEvent("focus_probe foreground=%p focus=%p self=%p", GetForegroundWindow(), GetFocus(), hwnd); break; case 4: logEvent("state_request kind=restore api=ShowWindow(SW_RESTORE)"); ShowWindow(hwnd, SW_RESTORE); logPlacement(hwnd, "after_restore"); break; case 5: enterFullscreen(hwnd); break; case 6: exitFullscreen(hwnd); break; case 7: g.
g.dirty
dirty
= true;
logEvent("dirty set=1"); // Drive the close through the real user chain: the title-bar X sends // WM_SYSCOMMAND SC_CLOSE, which DefWindowProc turns into WM_CLOSE. g.
g.closeFromSelf
closeFromSelf
= true;
logEvent("state_request kind=close api=WM_SYSCOMMAND(SC_CLOSE) attempt=1"); SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); break; case 8: g.
g.closeFromSelf
closeFromSelf
= true;
logEvent("state_request kind=close api=WM_SYSCOMMAND(SC_CLOSE) attempt=2"); SendMessageW(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0); 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: g.
g.memDc
memDc
= CreateCompatibleDC(null);
return 0; case WM_SHOWWINDOW: logEvent("msg name=WM_SHOWWINDOW shown=%d", cast(int) wParam); goto default; case WM_GETMINMAXINFO: // Sent when the size/position is about to change — notably on // maximize, letting the app override the maximized size/position. auto
_error_ mmi
mmi
= cast(MINMAXINFO*) lParam;
logEvent("msg name=WM_GETMINMAXINFO maxSize=%ldx%ld maxPos=%ld,%ld", mmi.ptMaxSize.
mmi.ptMaxSize.x
x
, mmi.ptMaxSize.
mmi.ptMaxSize.y
y
, mmi.ptMaxPosition.
mmi.ptMaxPosition.x
x
, mmi.ptMaxPosition.
mmi.ptMaxPosition.y
y
);
goto default; case WM_WINDOWPOSCHANGING: auto
_error_ wpg
wpg
= cast(WINDOWPOS*) lParam;
logEvent("msg name=WM_WINDOWPOSCHANGING rect=%d,%d-%dx%d flags=0x%x", wpg.
wpg.x
x
, wpg.
wpg.y
y
, wpg.cx, wpg.cy, wpg.flags);
goto default; case WM_WINDOWPOSCHANGED: auto
_error_ wpd
wpd
= cast(WINDOWPOS*) lParam;
logEvent("msg name=WM_WINDOWPOSCHANGED rect=%d,%d-%dx%d flags=0x%x", wpd.
wpd.x
x
, wpd.
wpd.y
y
, wpd.cx, wpd.cy, wpd.flags);
goto default; // DefWindowProc synthesizes WM_SIZE/WM_MOVE case WM_SIZE: const
_error_ w
w
= cast(int)(lParam & 0xffff);
const
_error_ h
h
= cast(int)((lParam >> 16) & 0xffff);
logEvent("state_changed via=WM_SIZE kind=%s size=%dx%d", sizeKind(wParam), w, h); if (wParam == SIZE_MINIMIZED) return 0; if (w != g.
g.width
width
|| h != g.
g.height
height
)
createBackbuffer(w, h); return 0; case WM_ACTIVATE: logEvent("focus state=%s reason=WM_ACTIVATE minimized=%d other=%p", activateKind(wParam), HIWORD(wParam) ? 1 : 0, cast(void*) lParam); goto default; case WM_ACTIVATEAPP: logEvent("msg name=WM_ACTIVATEAPP active=%d", cast(int) wParam); goto default; case WM_SETFOCUS: logEvent("focus state=in reason=WM_SETFOCUS prev=%p", cast(void*) wParam); return 0; case WM_KILLFOCUS: // wParam = the window RECEIVING focus (may be null) — the // where-does-focus-go-on-minimize probe. logEvent("focus state=out reason=WM_KILLFOCUS next=%p", cast(void*) wParam); return 0; case WM_SYSCOMMAND: logEvent("msg name=WM_SYSCOMMAND cmd=0x%llx", cast(ulong)(wParam & 0xfff0)); goto default; case WM_CLOSE: if (g.
g.dirty
dirty
)
{ // The first-class veto: return 0 WITHOUT calling DefWindowProcW. // DefWindowProc's WM_CLOSE handling is what calls DestroyWindow; // not forwarding IS the refusal — no further protocol required. logEvent("close_requested veto=1 src=%s dirty=1", g.
g.closeFromSelf
closeFromSelf
? "self_syscommand".ptr : "external".ptr);
g.
g.dirty
dirty
= false;
g.
g.closeFromSelf
closeFromSelf
= false;
return 0; } logEvent("close_requested veto=0 src=%s dirty=0", g.
g.closeFromSelf
closeFromSelf
? "self_syscommand".ptr : "external".ptr);
g.
g.closeFromSelf
closeFromSelf
= false;
goto default; // DefWindowProcW → DestroyWindow case WM_ERASEBKGND: return 1; case WM_PAINT: PAINTSTRUCT
_error_ ps
ps
;
HDC
_error_ hdc
hdc
= BeginPaint(hwnd, &ps);
++g.
g.frame
frame
;
drawGradient(); 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_KEYDOWN: switch (wParam) { case 'M': logEvent("state_request kind=%s api=ShowWindow", IsZoomed(hwnd) ? "restore".ptr : "maximize".ptr); ShowWindow(hwnd, IsZoomed(hwnd) ? SW_RESTORE : SW_MAXIMIZE); logPlacement(hwnd, "after_key_m"); break; case 'N': logEvent("state_request kind=minimize api=ShowWindow(SW_MINIMIZE)"); ShowWindow(hwnd, SW_MINIMIZE); break; case 'R': logEvent("state_request kind=restore api=ShowWindow(SW_RESTORE)"); ShowWindow(hwnd, SW_RESTORE); logPlacement(hwnd, "after_key_r"); break; case 'F': if (g.
g.fullscreen
fullscreen
)
exitFullscreen(hwnd); else enterFullscreen(hwnd); break; case 'D': g.
g.dirty
dirty
= !g.
g.dirty
dirty
;
logEvent("dirty set=%d", g.
g.dirty
dirty
? 1 : 0);
InvalidateRect(hwnd, null, FALSE); break; default: break; } return 0; case WM_TIMER: if (wParam != TIMER_ID) return 0; ++g.
g.ticks
ticks
;
InvalidateRect(hwnd, null, FALSE); if (g.
g.autoExit
autoExit
&& g.
g.ticks
ticks
% TICKS_PER_STEP == 0)
runStep(hwnd, g.
g.step
step
++);
return 0; case WM_DESTROY: logEvent("msg name=WM_DESTROY"); 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.wantAutoExit() nothrow
wantAutoExit
() nothrow
{ WCHAR[8]
(local variable) _error_ buf
buf
;
undefined identifier `WCHAR`
const
(local variable) const(_error_) n
n
= GetEnvironmentVariableW("WSI_AUTO_EXIT"w.ptr, buf.ptr, buf.length);
undefined identifier `GetEnvironmentVariableW`
return n >= 1 && n < buf.length && buf[0] == '1'; } int
int D main()
main
()
{ instrumentInit("f14_state_win32");
undefined identifier `instrumentInit`
logEvent("init_start");
undefined identifier `logEvent`
g.
g.autoExit
autoExit
= wantAutoExit();
logEvent("mode auto_exit=%d", g.
g.autoExit
autoExit
? 1 : 0);
undefined identifier `logEvent`
HINSTANCE
(local variable) _error_ hInst
hInst
= GetModuleHandleW(null);
undefined identifier `HINSTANCE`
undefined identifier `GetModuleHandleW`
auto
(local variable) wstring clsName
clsName
= "wsi-f14-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 = LoadCursorW(null, IDC_ARROW); if (!RegisterClassExW(&wc))
undefined identifier `RegisterClassExW`
return 1; HWND
(local variable) _error_ hwnd
hwnd
= CreateWindowExW(0, clsName.ptr, "wsi-f14-window-state"w.ptr,
undefined identifier `HWND`
undefined identifier `CreateWindowExW`
WS_OVERLAPPEDWINDOW, 60, 40, 480, 320, null, null, hInst, null); if (hwnd is null) { logEvent("error what=CreateWindowExW code=%lu", GetLastError());
undefined identifier `logEvent`
return 1; } logEvent("window_created hwnd=%p", hwnd);
undefined identifier `logEvent`
ShowWindow(hwnd, SW_SHOW);
undefined identifier `ShowWindow`
UpdateWindow(hwnd);
undefined identifier `UpdateWindow`
SetTimer(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; }