Skip to content

Stop indexing an empty page array, and redo a dropped layout pass#65

Merged
xroche merged 2 commits into
masterfrom
fix-layout-baseline-and-guards
Jul 26, 2026
Merged

Stop indexing an empty page array, and redo a dropped layout pass#65
xroche merged 2 commits into
masterfrom
fix-layout-baseline-and-guards

Conversation

@xroche

@xroche xroche commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Two real defects from #61, plus a call-site move.

GetActivePage() is m_pages[GetActiveIndex()] with no bounds check outside a debug ASSERT, and GetActiveIndex() returns -1 when nothing is selected. FinalInProgress and EndInProgress both empty the array before refilling it, and RemovePage relayouts synchronously, so a WM_SIZE arriving mid-rebuild read m_pages[-1] and dereferenced whatever came back. Both call sites now go through GetActiveIndex and GetPageCount.

DeferWindowPos destroys the HDWP on failure, dropping every position already queued, and the loop then carried on with SetWindowPos for the remainder so the earlier controls silently kept their old rects. It now redoes the whole pass.

BuildLayout also moves from CWizTab::OnInitDialog to CDialogContainer::OnInitialUpdate. My first rationale for this was wrong: there is no popup-to-WS_CHILD restyle after WM_INITDIALOG, MFC injects the style into the template at PSCB_PRECREATE, and the recorded rects are identical either way. What the move actually buys is that the active page has a window at the later point, so m_pageBase is the page rect rather than the hidden tab control standing in for it.

Nothing here is visible in normal use, and VM testing confirmed no change to the startup window.

…mpty page array

Three defects in the panel resizing, all found by review rather than by use.

BuildLayout ran from CWizTab::OnInitDialog, but MFC restyles a modeless sheet
from a popup to WS_CHILD only after WM_INITDIALOG returns. Every rect was
therefore measured against the popup's client origin, baking a caption and
border into the baseline, which then offset the buttons and the page for the
rest of the run. Record it from CDialogContainer::OnInitialUpdate instead, the
first point where both sheets are their final selves and still untouched.

GetActivePage() is m_pages[GetActiveIndex()] with no bounds check outside a
debug ASSERT, and GetActiveIndex() gives -1 when nothing is selected. Both
FinalInProgress and EndInProgress empty the array before refilling it, and
RemovePage relayouts synchronously, so a WM_SIZE arriving mid-rebuild read
m_pages[-1] and dereferenced whatever it found. Go through GetActiveIndex and
GetPageCount instead.

DeferWindowPos destroys the HDWP when it fails, dropping every position already
deferred. The loop carried on with SetWindowPos for the remainder, so the
already-queued controls silently kept their old rects. Redo the whole pass
instead of continuing a half-applied one.

No functional change intended beyond the above; the layout still needs an eye on
a VM, since CI cannot see it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HXNEMWtyrkW7xoD8ewcR3
Signed-off-by: Xavier Roche <roche@httrack.com>
The popup-to-WS_CHILD restyle the first message claimed does not happen: MFC
injects the requested style into the dialog template at PSCB_PRECREATE, so the
sheet is already a child when WM_INITDIALOG arrives, and ScreenToClient would
have cancelled a caption out in any case.

What moving the call does buy is that the active page has a window by then, so
the page's own rect is measured rather than the hidden tab control standing in
for it. State that instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019HXNEMWtyrkW7xoD8ewcR3
Signed-off-by: Xavier Roche <roche@httrack.com>
@xroche xroche changed the title Record the sheet layout after MFC restyles it, and stop indexing an empty page array Stop indexing an empty page array, and redo a dropped layout pass Jul 26, 2026
@xroche
xroche merged commit f767721 into master Jul 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant