app.dhover×110 error×48all
// Win32 windowing scaffold — the base program every fXX-* Win32 feature demo
// copies. It evolves ../../example/app.d (paint once, then quit) into the shape
// the F01/F02 specs (../../../features/) need:
//
//   * RegisterClassExW -> CreateWindowExW (title "wsi-scaffold") -> ShowWindow,
//     then the canonical GetMessageW/TranslateMessage/DispatchMessageW pump.
//   * A top-down 32-bit DIB section (CreateDIBSection) as the CPU-visible
//     backbuffer: a corner-anchored gradient is drawn into it each frame and
//     presented with BitBlt from a memory DC inside WM_PAINT. The DIB is
//     reallocated on every client-size change (WM_SIZE).
//   * Instrumentation (instrument.d) logs every init step, the first
//     WM_SIZE ("first_configure" — Win32 delivers it *inside* CreateWindowExW),
//     the return of the first BitBlt ("first_pixel_presented"), every resize and
//     buffer (re)allocation, and one "frame_callback" per paint.
//   * WSI_AUTO_EXIT=1 makes the run bounded: a ~16 ms SetTimer tick invalidates
//     the window (animating the gradient); after ~60 ticks a programmatic
//     resize storm (8 SetWindowPos size changes) runs, then DestroyWindow ->
//     WM_DESTROY -> PostQuitMessage -> clean exit 0. Without the env var the
//     demo runs until the user closes the window.
//
// 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:
// --------------------------------------------------------------------------- // Demo state. The WndProc is a static extern(Windows) callback, so the state // it needs lives in one __gshared struct (a real binding would stash a `this` // pointer via SetWindowLongPtrW(GWLP_USERDATA) instead). struct
(struct) app.Demo
Demo
{ HDC
(field) _error_ app.Demo.memDc
memDc
; // memory DC the DIB section is selected into
undefined identifier `HDC`
HBITMAP
(field) _error_ app.Demo.dib
dib
; // top-down 32-bit DIB section (CPU-visible backbuffer)
undefined identifier `HBITMAP`
HBITMAP
(field) _error_ app.Demo.stockBmp
stockBmp
; // the 1x1 stock bitmap displaced by SelectObject
undefined identifier `HBITMAP`
uint*
(field) uint* app.Demo.pixels
pixels
; // DIB bits: 0x00RRGGBB, row-major, row 0 = top row
int
(field) int app.Demo.width
width
,
(field) int app.Demo.height
height
; // current client (= DIB) size, physical pixels
int
(field) int app.Demo.dpi
dpi
= 96; // monitor DPI; scale = dpi / 96
uint
(field) uint app.Demo.frame
frame
; // paint counter (animates the gradient)
uint
(field) uint app.Demo.ticks
ticks
; // WM_TIMER counter (auto-exit schedule)
bool
(field) bool app.Demo.autoExit
autoExit
; // WSI_AUTO_EXIT=1: bounded run
bool
(field) bool app.Demo.firstSizeSeen
firstSizeSeen
;
bool
(field) bool app.Demo.firstPaintDone
firstPaintDone
;
} __gshared
(struct) app.Demo
Demo
_error_ app.g
g
;
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; // ~60 Hz animation tick
enum
(constant) int app.STORM_AFTER_TICKS = 60
STORM_AFTER_TICKS
= 60; // ~1 s of animation before the resize storm
// --------------------------------------------------------------------------- // Backbuffer: a DIB section reallocated on every client-size change. 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) // release the previous buffer first
{ 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; // minimized / degenerate — keep no buffer BITMAPINFO
(local variable) _error_ bmi
bmi
;
undefined identifier `BITMAPINFO`
bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; bmi.bmiHeader.biWidth = w; bmi.bmiHeader.biHeight = -h; // negative height = top-down rows 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
);
logEvent("buffer_alloc size=%dx%d bytes=%d", w, h, w * h * 4);
undefined identifier `logEvent`
} // Corner-anchored diagonal gradient (red tracks x, green tracks y), so any // stretching or stale-buffer artifact during a resize is visible (F02 req. 1). // The blue channel advances per frame so consecutive paints are distinct. 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;
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); } } } // --------------------------------------------------------------------------- // Auto-exit driver: 8 programmatic outer-size changes (each SetWindowPos // dispatches WM_NCCALCSIZE/WM_WINDOWPOSCHANGED/WM_SIZE re-entrantly into the // WndProc before returning), then DestroyWindow ends the run (F02 req. 2). void
app.runResizeStorm
runResizeStorm
(HWND
(parameter) HWND hwnd
hwnd
) nothrow
undefined identifier `HWND`
{ static immutable int[2][8]
int[2][8] sizes
sizes
= [
[520, 360], [360, 520], [640, 240], [240, 640], [800, 600], [300, 300], [1024, 256], [480, 320], ]; logEvent("resize_storm_begin steps=%d", cast(int) sizes.length); foreach (
(parameter) i
i
,
(parameter) s
s
; sizes)
{ logEvent("step name=SetWindowPos i=%d size=%dx%d", cast(int) i, s[0], s[1]); SetWindowPos(hwnd, null, 0, 0, s[0], s[1], SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); // The storm runs inside one WM_TIMER dispatch, so queued WM_PAINTs // would never be seen before DestroyWindow — force one synchronous // paint per step to prove a frame is presented at every new size. // The InvalidateRect is load-bearing: a resize that *shrinks* both // dimensions invalidates nothing by itself (the retained surface // already covers the smaller client area), so without it UpdateWindow // is a no-op and the gradient is left stale (observed under Wine). InvalidateRect(hwnd, null, FALSE); UpdateWindow(hwnd); } logEvent("resize_storm_end"); DestroyWindow(hwnd); } // --------------------------------------------------------------------------- // The window procedure. Lifecycle messages are logged as `msg name=...` so the // observed creation / resize-storm orderings land in the instrument log. 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_NCCREATE: logEvent("msg name=WM_NCCREATE"); goto default; case WM_NCCALCSIZE: logEvent("msg name=WM_NCCALCSIZE"); goto default; case WM_CREATE: logEvent("msg name=WM_CREATE"); g.
g.memDc
memDc
= CreateCompatibleDC(null);
// druntime's core.sys.windows has no GetDpiForWindow (Win10 1607+); // the system DPI from the screen DC is enough for the scale= field. HDC
_error_ screen
screen
= GetDC(null);
g.
g.dpi
dpi
= GetDeviceCaps(screen, LOGPIXELSX);
ReleaseDC(null, screen); return 0; case WM_SHOWWINDOW: logEvent("msg name=WM_SHOWWINDOW shown=%d", cast(int) wParam); goto default; case WM_WINDOWPOSCHANGED: logEvent("msg name=WM_WINDOWPOSCHANGED"); goto default; // DefWindowProcW synthesizes WM_SIZE/WM_MOVE from this case WM_MOVE: logEvent("msg name=WM_MOVE"); return 0; case WM_SIZE: const
_error_ w
w
= cast(int)(lParam & 0xffff);
const
_error_ h
h
= cast(int)((lParam >> 16) & 0xffff);
if (!g.
g.firstSizeSeen
firstSizeSeen
)
{ g.
g.firstSizeSeen
firstSizeSeen
= true;
// Note: this arrives *during* CreateWindowExW, before the // window_created event is logged — see the scaffold findings. logEvent("first_configure size=%dx%d", w, h); } logEvent("resize size=%dx%d scale=%d.%02d", w, h, g.
g.dpi
dpi
/ 96, (g.
g.dpi
dpi
% 96) * 100 / 96);
if (wParam == SIZE_MINIMIZED) return 0; if (w != g.
g.width
width
|| h != g.
g.height
height
)
createBackbuffer(w, h); return 0; case WM_ERASEBKGND: logEvent("msg name=WM_ERASEBKGND"); return 1; // claim erased — WM_PAINT repaints the full client anyway case WM_PAINT: if (!g.
g.firstPaintDone
firstPaintDone
)
logEvent("msg name=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);
if (!g.
g.firstPaintDone
firstPaintDone
)
{ g.
g.firstPaintDone
firstPaintDone
= true;
// F01: "presented" on Win32 = the first BitBlt returned. logEvent("first_pixel_presented size=%dx%d", g.
g.width
width
, g.
g.height
height
);
} logEvent("frame_callback t=%lld frame=%u", nowUs(), g.
g.frame
frame
);
EndPaint(hwnd, &ps); return 0; case WM_TIMER: if (wParam != TIMER_ID) return 0; ++g.
g.ticks
ticks
;
InvalidateRect(hwnd, null, FALSE); // schedule the next WM_PAINT if (g.
g.autoExit
autoExit
&& g.
g.ticks
ticks
== STORM_AFTER_TICKS)
runResizeStorm(hwnd); // ends in DestroyWindow return 0; case WM_CLOSE: logEvent("close_requested"); goto default; // DefWindowProcW responds with DestroyWindow case WM_DESTROY: logEvent("msg name=WM_DESTROY"); KillTimer(hwnd, TIMER_ID); createBackbuffer(0, 0); // frees the DIB section if (g.
g.memDc
memDc
!is null)
{ DeleteDC(g.
g.memDc
memDc
);
g.
g.memDc
memDc
= null;
} PostQuitMessage(0); return 0; case WM_NCDESTROY: logEvent("msg name=WM_NCDESTROY"); goto default; 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("scaffold_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`
logEvent("step name=GetModuleHandleW");
undefined identifier `logEvent`
HINSTANCE
(local variable) _error_ hInst
hInst
= GetModuleHandleW(null);
undefined identifier `HINSTANCE`
undefined identifier `GetModuleHandleW`
// First user32 call of the process — this is where user32 connects to the // session (under Wine: to the wine server), so it gets its own step event. logEvent("step name=LoadCursorW");
undefined identifier `logEvent`
HCURSOR
(local variable) _error_ arrow
arrow
= LoadCursorW(null, IDC_ARROW);
undefined identifier `HCURSOR`
undefined identifier `LoadCursorW`
auto
(local variable) wstring clsName
clsName
= "wsi-scaffold-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; // No hbrBackground: WM_ERASEBKGND is handled, the DIB covers every pixel. logEvent("step name=RegisterClassExW");
undefined identifier `logEvent`
if (!RegisterClassExW(&wc))
undefined identifier `RegisterClassExW`
{ logEvent("error what=RegisterClassExW code=%lu", GetLastError());
undefined identifier `logEvent`
return 1; } logEvent("step name=CreateWindowExW");
undefined identifier `logEvent`
HWND
(local variable) _error_ hwnd
hwnd
= CreateWindowExW(0, clsName.ptr, "wsi-scaffold"w.ptr,
undefined identifier `HWND`
undefined identifier `CreateWindowExW`
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 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");
undefined identifier `logEvent`
logEvent("step name=ShowWindow");
undefined identifier `logEvent`
ShowWindow(hwnd, SW_SHOW);
undefined identifier `ShowWindow`
logEvent("step name=UpdateWindow");
undefined identifier `logEvent`
UpdateWindow(hwnd); // forces the first WM_PAINT synchronously, now
undefined identifier `UpdateWindow`
logEvent("step name=SetTimer interval_ms=%d", TICK_MS);
undefined identifier `logEvent`
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; }