|
|
@@ -496,6 +496,13 @@ void CShadowUI::MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent)
|
|
|
int nAnchors = max(szParent.cy, szShadow.cy); // # of anchor points pares
|
|
|
int (*ptAnchors)[2] = new int[nAnchors + 2][2];
|
|
|
int (*ptAnchorsOri)[2] = new int[szParent.cy][2]; // anchor points, will not modify during erosion
|
|
|
+ // [2026-10-09] R55: zero both arrays. The scan loop below only writes the rows it
|
|
|
+ // can resolve; a row with no pixel inside hParentRgn leaves its [1] / [0] pair
|
|
|
+ // untouched (see the "Start point not found" branch further down). Memory from
|
|
|
+ // new[] is not zeroed, so those slots used to carry arbitrary values which then
|
|
|
+ // leaked into the fill loops below as loop bounds.
|
|
|
+ ::ZeroMemory(ptAnchors, sizeof(int) * 2 * (nAnchors + 2));
|
|
|
+ ::ZeroMemory(ptAnchorsOri, sizeof(int) * 2 * szParent.cy);
|
|
|
ptAnchors[0][0] = szParent.cx;
|
|
|
ptAnchors[0][1] = 0;
|
|
|
ptAnchors[nAnchors + 1][0] = szParent.cx;
|
|
|
@@ -522,9 +529,16 @@ void CShadowUI::MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent)
|
|
|
}
|
|
|
// Start point not found
|
|
|
if(j >= szParent.cx) {
|
|
|
+ // [2026-10-09] R55: the 2nd and 3rd line used to duplicate the 1st and 2nd,
|
|
|
+ // so ptAnchors[i + 1][1] and ptAnchorsOri[i][0] were never written at all.
|
|
|
+ // Empty rows are not theoretical here: a rounded window region built by
|
|
|
+ // CreateRoundRectRgn has NO pixel on its very last row, so this branch runs
|
|
|
+ // on every shadow repaint of a roundcorner window. The uninitialised pair
|
|
|
+ // then acted as the bound of the clCenter fill below, which ran past the
|
|
|
+ // end of the DIB section (crash: access violation on write).
|
|
|
ptAnchors[i + 1][0] = szParent.cx;
|
|
|
- ptAnchorsOri[i][1] = 0;
|
|
|
- ptAnchors[i + 1][0] = szParent.cx;
|
|
|
+ ptAnchorsOri[i][0] = szParent.cx;
|
|
|
+ ptAnchors[i + 1][1] = 0;
|
|
|
ptAnchorsOri[i][1] = 0;
|
|
|
}
|
|
|
else {
|
|
|
@@ -567,6 +581,26 @@ void CShadowUI::MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent)
|
|
|
|
|
|
// morphologic dilation
|
|
|
ptAnchors += (m_nSize < 0 ? -m_nSize : 0) + 1; // now coordinates in ptAnchors are same as in shadow window
|
|
|
+ // [2026-10-09] R55: last line of defence. Both anchor arrays are consumed directly
|
|
|
+ // as x bounds of the clCenter / kernel loops below, so clamp every span into the
|
|
|
+ // DIB row before it is used. Healthy values already live in [0, szShadow.cx], so
|
|
|
+ // this is a no-op on every correct path; it only bites when something still slips
|
|
|
+ // through, and it turns "write past the end of a 620x544 DIB" into "write nothing".
|
|
|
+ // The +1 shift above maps index 0..nAnchorCnt onto the original 1..nAnchorCnt+1
|
|
|
+ // slots, which is exactly the index range both loops touch.
|
|
|
+ const int nAnchorCnt = nAnchors - (m_nSize < 0 ? -m_nSize : 0);
|
|
|
+ for(int i = 0; i <= nAnchorCnt; i++) {
|
|
|
+ if(ptAnchors[i][0] < 0) ptAnchors[i][0] = 0;
|
|
|
+ else if(ptAnchors[i][0] > szShadow.cx) ptAnchors[i][0] = szShadow.cx;
|
|
|
+ if(ptAnchors[i][1] < 0) ptAnchors[i][1] = 0;
|
|
|
+ else if(ptAnchors[i][1] > szShadow.cx) ptAnchors[i][1] = szShadow.cx;
|
|
|
+ }
|
|
|
+ for(int i = 0; i < szParent.cy; i++) {
|
|
|
+ if(ptAnchorsOri[i][0] < 0) ptAnchorsOri[i][0] = 0;
|
|
|
+ else if(ptAnchorsOri[i][0] > szShadow.cx) ptAnchorsOri[i][0] = szShadow.cx;
|
|
|
+ if(ptAnchorsOri[i][1] < 0) ptAnchorsOri[i][1] = 0;
|
|
|
+ else if(ptAnchorsOri[i][1] > szShadow.cx) ptAnchorsOri[i][1] = szShadow.cx;
|
|
|
+ }
|
|
|
// Generate the kernel
|
|
|
int nKernelSize = m_nSize > m_nSharpness ? m_nSize : m_nSharpness;
|
|
|
int nCenterSize = m_nSize > m_nSharpness ? (m_nSize - m_nSharpness) : 0;
|