From: Scoots on
Part of me feels rather dumb for asking this, but everything seems to
work smoothly except for one scrolling action.

I have a dialog with two embedded child dialogs within it. The top
dialog has a scrolling interface. The parent dialog is roughly 640 *
540 pixels, with the top child dialog being 640*388. The ACTUAL size
of the top child is 640*2008 (strange application, but YES, that is
intentional. It has twenty "elements" which include a couple of
statics and a picture control. So you'll see a lot of "20"'s floating
around, that's why.).

Using information here:
http://support.microsoft.com/kb/262954

I found I had to tweak it a bit to get it correct, as my Windows
seemed to want to cap my window to 1030 tall, roughly the vertical
pixel count of my screen, I guess.

Parent dialog:


BOOL C4IN1RegDialog::OnInitDialog()
{
CDialog::OnInitDialog();

m_TopDlg.Create(C4IN1RegTopDialog::IDD, this);
m_BottomDlg.Create(C4IN1RegBottomDialog::IDD, this);

m_TopDlg.ShowWindow(SW_SHOW);
CRect rc;
GetWindowRect(rc);
MoveWindow(rc.left, rc.top, 648, 530,true);
m_TopDlg.MoveWindow(0,0,640, 388, true);

m_BottomDlg.ShowWindow(SW_SHOW);
m_BottomDlg.MoveWindow(0,390,640, 120, true);

return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}


Top dialog (bottom is fine, so I'll avoid code-spammage)

BOOL C4IN1RegTopDialog::OnInitDialog()
{
CDialog::OnInitDialog();

m_iScrollPos = 0;

m_rect.top = 0;
m_rect.left = 0;
m_rect.right = 617;
m_rect.bottom = iOffsetFromTop + ((iItem) * (iOffsetBetween +
iSizeOfImageY));
SetWindowPos(NULL, m_rect.left, m_rect.top, m_rect.right,
m_rect.bottom, SWP_NOZORDER);


UpdateWindow();

return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}

void C4IN1RegTopDialog::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);

m_iCurHeight = cy;

SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL; // SIF_ALL = SIF_PAGE | SIF_RANGE | SIF_POS;
si.nMin = 0;
si.nMax = m_rect.Height() - m_iCurHeight;
si.nPage = si.nMax/20;
si.nPos = 0;
SetScrollInfo(SB_VERT, &si, TRUE);
}

void C4IN1RegTopDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*
pScrollBar)
{
// TODO: Add your message handler code here and/or call default

int nDelta;
int nMaxPos = m_rect.Height() - m_iCurHeight;

switch (nSBCode)
{
case SB_LINEDOWN:
if (m_iScrollPos >= nMaxPos)
return;
nDelta = min(nMaxPos/20,nMaxPos-m_iScrollPos);
//nDelta = min(max(nMaxPos/20,5),nMaxPos-m_iScrollPos);
break;

case SB_LINEUP:
if (m_iScrollPos <= 0)
return;
nDelta = -min(nMaxPos/20,m_iScrollPos);
//nDelta = -min(max(nMaxPos/20,5),m_iScrollPos);
break;

case SB_PAGEDOWN:
if (m_iScrollPos >= nMaxPos)
return;
nDelta = min(nMaxPos/20,nMaxPos-m_iScrollPos);
//nDelta = min(max(nMaxPos/20,5),nMaxPos-m_iScrollPos);
break;

case SB_THUMBTRACK:
case SB_THUMBPOSITION:
{
nDelta = (int)nPos - m_iScrollPos;
//int iPos = GetScrollPos(SB_VERT);
//nDelta = (int)iPos - m_iScrollPos;
}
break;

case SB_PAGEUP:
if (m_iScrollPos <= 0)
return;
nDelta = -min(nMaxPos/20,m_iScrollPos);
//nDelta = -min(max(nMaxPos/20,5),m_iScrollPos);
break;

default:
return;
}
m_iScrollPos += nDelta;
SetScrollPos(SB_VERT,m_iScrollPos, TRUE);
ScrollWindow(0,-nDelta);
CDialog::OnVScroll(nSBCode, nPos, pScrollBar);

}

Obviously this is eliminating a LOT of initialization, loading, etc.
Now, this works perfectly when the user presses on the ends of the
scrollbar. The dialog scrolls smoothly and it's all wonderful. But
when the user clicks and drags the thumbtrack, the SB_THUMBTRACK event
seems to not scroll all the way. It goes almost all the way, but it
seems like the last "tick" isn't there. I get all but the last
element. Then if the user taps the button, it scrolls a little more,
showing everything. If the user clicks the thumbtrack, it snaps back
to that "tick" before the end. I've stepped throught he code, and
when the user taps the thumbtrack, I get a position of 1592, as
opposed to 1620 that is the max (remember, my windowsize is 388, so
2008-388=1620, which I do get with the buttons).

Why isn't this last "tick" there? And how can I get it? The
thumbtrack size is dependent upon my nPage count, but I've tried to
monkey with that and that doesn't change the behaviour. It always
seems to be one tick short.

Thanks for the help,
~Scoots
From: Joseph M. Newcomer on
See below...
On Mon, 23 Nov 2009 13:06:32 -0800 (PST), Scoots <linkingfire(a)msn.com> wrote:

>Part of me feels rather dumb for asking this, but everything seems to
>work smoothly except for one scrolling action.
>
>I have a dialog with two embedded child dialogs within it. The top
>dialog has a scrolling interface. The parent dialog is roughly 640 *
>540 pixels, with the top child dialog being 640*388. The ACTUAL size
>of the top child is 640*2008 (strange application, but YES, that is
>intentional. It has twenty "elements" which include a couple of
>statics and a picture control. So you'll see a lot of "20"'s floating
>around, that's why.).
>
>Using information here:
>http://support.microsoft.com/kb/262954
>
>I found I had to tweak it a bit to get it correct, as my Windows
>seemed to want to cap my window to 1030 tall, roughly the vertical
>pixel count of my screen, I guess.
>
>Parent dialog:
>
>
>BOOL C4IN1RegDialog::OnInitDialog()
>{
> CDialog::OnInitDialog();
>
> m_TopDlg.Create(C4IN1RegTopDialog::IDD, this);
> m_BottomDlg.Create(C4IN1RegBottomDialog::IDD, this);
>
> m_TopDlg.ShowWindow(SW_SHOW);
> CRect rc;
> GetWindowRect(rc);
> MoveWindow(rc.left, rc.top, 648, 530,true);
> m_TopDlg.MoveWindow(0,0,640, 388, true);
>
****
These hardwired numbers are a bit scary. I suppose if you never, ever change the machine
you are on, or your monitor, or your display card, or the resolution you use, they might
make sense, but overall, any code like this is so amazingly fragile that it cannot be
expected to run on any other machine in the known universe. Why do you think these
numbers, which can run on only your machine, with your current display, your current
display card, your current display resolution, your current default font, your current
display driver, with the current version of the OS with the current set of hotfixes, is
going to work even *next week*?

You have to replace these values by meaningful computations.

It is not very practical to create a window that is larger than the current screen
resolution. Since this can change at any time (for example, you buy a new monitor, move
it to your laptop, etc.), all hardwired constants are suspect.
****
> m_BottomDlg.ShowWindow(SW_SHOW);
> m_BottomDlg.MoveWindow(0,390,640, 120, true);
>
> return TRUE; // return TRUE unless you set the focus to a control
> // EXCEPTION: OCX Property Pages should return FALSE
>}
>
>
>Top dialog (bottom is fine, so I'll avoid code-spammage)
>
>BOOL C4IN1RegTopDialog::OnInitDialog()
>{
> CDialog::OnInitDialog();
>
> m_iScrollPos = 0;
>
> m_rect.top = 0;
> m_rect.left = 0;
> m_rect.right = 617;
****
See previous comments about hardwired integers
****
> m_rect.bottom = iOffsetFromTop + ((iItem) * (iOffsetBetween +
>iSizeOfImageY));
> SetWindowPos(NULL, m_rect.left, m_rect.top, m_rect.right,
>m_rect.bottom, SWP_NOZORDER);
****
If you aren't changing the top or left, why do you bother using them? Just put 0,0 there
and use SWP_NOMOVE
****
>
>
> UpdateWindow();
>
> return TRUE; // return TRUE unless you set the focus to a control
> // EXCEPTION: OCX Property Pages should return FALSE
>}
>
>void C4IN1RegTopDialog::OnSize(UINT nType, int cx, int cy)
>{
> CDialog::OnSize(nType, cx, cy);
>
> m_iCurHeight = cy;
>
> SCROLLINFO si;
> si.cbSize = sizeof(SCROLLINFO);
> si.fMask = SIF_ALL; // SIF_ALL = SIF_PAGE | SIF_RANGE | SIF_POS;
> si.nMin = 0;
> si.nMax = m_rect.Height() - m_iCurHeight;
****
It is not clear why you have a class variable for the rectangle. Note also that OnSize is
called many, many times during the creation of a window, and the m_rect, which is not set
until OnInitDialog, will not have a valid value at those times.

Either you have to have a boolean that says if the rectangle is valid, or compute the
value at this point from basic properties of the window. Do not store it as you have
done, and assume that the sequence is
OnInitDialog -> OnSize
when the actual sequence is

(OnSize)* -> OnInitDialog -> (OnSize)*
where OnSize* means "zero or more times" but in fact there will be several calls on
OnSize, many of which occur before OnInitDialog. As a regular expression, it might be
better expressed as
(OnSize)+ -> OnInitDialog -> (OnSize)+
where Onsize+ means "One or more calls"
*****
> si.nPage = si.nMax/20;
> si.nPos = 0;
> SetScrollInfo(SB_VERT, &si, TRUE);
>}
>
>void C4IN1RegTopDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*
>pScrollBar)
>{
> // TODO: Add your message handler code here and/or call default
>
> int nDelta;
> int nMaxPos = m_rect.Height() - m_iCurHeight;
>
> switch (nSBCode)
> {
> case SB_LINEDOWN:
> if (m_iScrollPos >= nMaxPos)
> return;
> nDelta = min(nMaxPos/20,nMaxPos-m_iScrollPos);
> //nDelta = min(max(nMaxPos/20,5),nMaxPos-m_iScrollPos);
> break;
>
> case SB_LINEUP:
> if (m_iScrollPos <= 0)
> return;
> nDelta = -min(nMaxPos/20,m_iScrollPos);
> //nDelta = -min(max(nMaxPos/20,5),m_iScrollPos);
> break;
>
> case SB_PAGEDOWN:
> if (m_iScrollPos >= nMaxPos)
> return;
> nDelta = min(nMaxPos/20,nMaxPos-m_iScrollPos);
> //nDelta = min(max(nMaxPos/20,5),nMaxPos-m_iScrollPos);
> break;
>
> case SB_THUMBTRACK:
> case SB_THUMBPOSITION:
> {
> nDelta = (int)nPos - m_iScrollPos;
> //int iPos = GetScrollPos(SB_VERT);
> //nDelta = (int)iPos - m_iScrollPos;
> }
****
But what is this computing? The correct value is to use nPos. The nPos value is an
absolute scroll position. I don't understand why you are using a global m_iScrollPos
value anyway. You can get the scroll position directly from the control.
****
> break;
>
> case SB_PAGEUP:
> if (m_iScrollPos <= 0)
> return;
> nDelta = -min(nMaxPos/20,m_iScrollPos);
> //nDelta = -min(max(nMaxPos/20,5),m_iScrollPos);
> break;
>
> default:
> return;
> }
> m_iScrollPos += nDelta;
****
I now see why you are using a delta. But this is not a natural way to express this.
Instead, normal scrollbar control code stores the new position, so instead of computing
the delta in the thumbtrack/thumbposition, you would just set the new position to be nPos;
in other cases you would not compute the value, but compute the new position.

As such, this code is hard to read and to understand.
****
> SetScrollPos(SB_VERT,m_iScrollPos, TRUE);
> ScrollWindow(0,-nDelta);
> CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
>
>}
>
>Obviously this is eliminating a LOT of initialization, loading, etc.
>Now, this works perfectly when the user presses on the ends of the
>scrollbar. The dialog scrolls smoothly and it's all wonderful. But
>when the user clicks and drags the thumbtrack, the SB_THUMBTRACK event
>seems to not scroll all the way. It goes almost all the way, but it
>seems like the last "tick" isn't there. I get all but the last
>element. Then if the user taps the button, it scrolls a little more,
>showing everything. If the user clicks the thumbtrack, it snaps back
>to that "tick" before the end. I've stepped throught he code, and
>when the user taps the thumbtrack, I get a position of 1592, as
>opposed to 1620 that is the max (remember, my windowsize is 388, so
>2008-388=1620, which I do get with the buttons).
****
I haven't looked at the code in detail, but it looks like a classic off-by-one-unit error
somewhere.

I'd simplify this code and get rid of nearly all those member variables. Compute values
as you need them, where you need them, from first principles.
joe

****
>
>Why isn't this last "tick" there? And how can I get it? The
>thumbtrack size is dependent upon my nPage count, but I've tried to
>monkey with that and that doesn't change the behaviour. It always
>seems to be one tick short.
>
>Thanks for the help,
>~Scoots
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Scoots on
My apologies that this will sound harsh. Rather, you have helped me
numerous times, and I do value your input. But there's no way to
answer your comments without sounding harsh.

1. This is code that is not complete. It has problems, it has
issues. Hence why I'm posting here about problems. I haven't gone
over it and cleaned it up.
2. It uses things I don't know very well, so my first and primary
goal is to learn how it operates, then I can clean it. 80% of the
code here is, in fact, from a Microsoft KB post. Given that there is
a problem in it, my time and focus has been on fixing the code and in
understanding the interactions, not in immediately rewriting the
code. For instance, the difference between MoveWindow and
SetWindowPos in regards to an embedded child window. You should have
seen the code before I figured that out...
3. You assume a lot about this application. In truth this is an
emulation (legal, business emulation for simulation.). I emulate the
application I am emulating. All of these hardcoded values are taken
from this. This should never be in DLU's, percentages, or anything
else. It is precise because it is meant to be. I didn't state this,
and while it is true that this code is rough, it was posted here so
that anyone else could duplicate my problem, no matter how junky or
ugly my code is. You've yelled at me before for cleaning up code and
the critical piece not being posted.

(oh, and I DO set the font. That was in the initialization that has
nothing to do with window sizes and scrolling)

"If you aren't changing the top or left, why do you bother using
them? Just put 0,0 there
and use SWP_NOMOVE"
--Alright. That is my code, written while I was trying to get the
scrollbar to work at ALL. I'll fix that.

"It is not clear why you have a class variable for the rectangle.
Note also that OnSize is
called many, many times during the creation of a window, and the
m_rect, which is not set
until OnInitDialog, will not have a valid value at those times."
--Well, the KB post the code was obtained from did, but that is not
the reason it is still around. Rather, I noticed in the OnSize() that
windows was forcing the window to 1030 pixels tall, presumably due to
the size of the monitor. Or something. I couldn't find any
documentation on it. The rectangle is retained because my window is
nearly twice this size (though obviously not to the user), and I need
the real size for the calculations.

"(OnSize)* -> OnInitDialog -> (OnSize)*"
--That's a perfectly fine regular expression. I don't understand why
you need to correct it. Indeed, I've noticed this behavior, but aside
from mentally noting it, I have not messed with it, as the end result
of the KB code is still the same. The final size is what the user
sees. The size of the scroll bar in between is largely irrelevant to
the user (and me, at this stage in development, when I am still taking
a virtual hacksaw to my code), as the window is shown AFTER it is
initialized -- at which point the final size is already set.

"But what is this computing? The correct value is to use nPos. The
nPos value is an
absolute scroll position. I don't understand why you are using a
global m_iScrollPos
value anyway. You can get the scroll position directly from the
control."
--Actually I ran into difficulties when doing this. GetScrollPos was
returning the position from before the tracking took place, which was
incorrect for the scroll operation done at the bottom of the routine.
(If I was to switch the logic to what you suggested later, then yes,
the nPos would be fine. For a Delta operation though, GetScrollPos
and nPos fail miserably) Also, I haven't posted header files, but
m_iScrollPos isn't a global, it's a member variable, if that helps (m_
stands for member variable, in this notation).


I appreciate your input, but the majority of your comments are
directed at analyzing the Microsoft KB posting. This will undoubtedly
help me to clean the code up, once the issue is resolved. However,
I'm not that far along, as the issue is still there. I have been
temporarily able to "resolve" the issue by adding an extra page
(logically) to what Windows sees on the scrollbar.

In the OnSize Handler

SCROLLINFO si;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_ALL; // SIF_ALL = SIF_PAGE | SIF_RANGE
| SIF_POS;
si.nMin = 0;
si.nMax = m_rect.Height() - m_iCurHeight + 81;
si.nPage = si.nMax/20;
si.nPos = 0;
SetScrollInfo(SB_VERT, &si, TRUE);


Because of the backwards-ness of my code in the OnVScroll, this
actually works, because the scrolling from the linedown and other
events are based on the REAL size of the window, not the expanded.
This is a hack of a workaround, and I'm no closer to solving the
issue.

Thanks for the response, and I am sorry if it comes out sounding
harsh. It's not meant to be.
~Scoots

On Nov 23, 5:16 pm, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
> See below...
>
>
>
>
>
> On Mon, 23 Nov 2009 13:06:32 -0800 (PST), Scoots <linkingf...(a)msn.com> wrote:
> >Part of me feels rather dumb for asking this, but everything seems to
> >work smoothly except for one scrolling action.
>
> >I have a dialog with two embedded child dialogs within it. The top
> >dialog has a scrolling interface. The parent dialog is roughly 640 *
> >540 pixels, with the top child dialog being 640*388. The ACTUAL size
> >of the top child is 640*2008 (strange application, but YES, that is
> >intentional. It has twenty "elements" which include a couple of
> >statics and a picture control. So you'll see a lot of "20"'s floating
> >around, that's why.).
>
> >Using information here:
> >http://support.microsoft.com/kb/262954
>
> >I found I had to tweak it a bit to get it correct, as my Windows
> >seemed to want to cap my window to 1030 tall, roughly the vertical
> >pixel count of my screen, I guess.
>
> >Parent dialog:
>
> >BOOL C4IN1RegDialog::OnInitDialog()
> >{
> > CDialog::OnInitDialog();
>
> > m_TopDlg.Create(C4IN1RegTopDialog::IDD, this);
> > m_BottomDlg.Create(C4IN1RegBottomDialog::IDD, this);
>
> > m_TopDlg.ShowWindow(SW_SHOW);
> > CRect rc;
> > GetWindowRect(rc);
> > MoveWindow(rc.left, rc.top, 648, 530,true);
> > m_TopDlg.MoveWindow(0,0,640, 388, true);
>
> ****
> These hardwired numbers are a bit scary. I suppose if you never, ever change the machine
> you are on, or your monitor, or your display card, or the resolution you use, they might
> make sense, but overall, any code like this is so amazingly fragile that it cannot be
> expected to run on any other machine in the known universe. Why do you think these
> numbers, which can run on only your machine, with your current display, your current
> display card, your current display resolution, your current default font, your current
> display driver, with the current version of the OS with the current set of hotfixes, is
> going to work even *next week*?
>
> You have to replace these values by meaningful computations.
>
> It is not very practical to create a window that is larger than the current screen
> resolution. Since this can change at any time (for example, you buy a new monitor, move
> it to your laptop, etc.), all hardwired constants are suspect.
> ****
>
>
>
> > m_BottomDlg.ShowWindow(SW_SHOW);
> > m_BottomDlg.MoveWindow(0,390,640, 120, true);
>
> > return TRUE; // return TRUE unless you set the focus to a control
> > // EXCEPTION: OCX Property Pages should return FALSE
> >}
>
> >Top dialog (bottom is fine, so I'll avoid code-spammage)
>
> >BOOL C4IN1RegTopDialog::OnInitDialog()
> >{
> > CDialog::OnInitDialog();
>
> > m_iScrollPos = 0;
>
> > m_rect.top = 0;
> > m_rect.left = 0;
> > m_rect.right = 617;
>
> ****
> See previous comments about hardwired integers
> ****> m_rect.bottom = iOffsetFromTop + ((iItem) * (iOffsetBetween +
> >iSizeOfImageY));
> > SetWindowPos(NULL, m_rect.left, m_rect.top, m_rect.right,
> >m_rect.bottom, SWP_NOZORDER);
>
> ****
> If you aren't changing the top or left, why do you bother using them? Just put 0,0 there
> and use SWP_NOMOVE
> ****
>
>
>
>
>
> > UpdateWindow();
>
> > return TRUE; // return TRUE unless you set the focus to a control
> > // EXCEPTION: OCX Property Pages should return FALSE
> >}
>
> >void C4IN1RegTopDialog::OnSize(UINT nType, int cx, int cy)
> >{
> > CDialog::OnSize(nType, cx, cy);
>
> > m_iCurHeight = cy;
>
> > SCROLLINFO si;
> > si.cbSize = sizeof(SCROLLINFO);
> > si.fMask = SIF_ALL; // SIF_ALL = SIF_PAGE | SIF_RANGE | SIF_POS;
> > si.nMin = 0;
> > si.nMax = m_rect.Height() - m_iCurHeight;
>
> ****
> It is not clear why you have a class variable for the rectangle. Note also that OnSize is
> called many, many times during the creation of a window, and the m_rect, which is not set
> until OnInitDialog, will not have a valid value at those times.
>
> Either you have to have a boolean that says if the rectangle is valid, or compute the
> value at this point from basic properties of the window. Do not store it as you have
> done, and assume that the sequence is
> OnInitDialog -> OnSize
> when the actual sequence is
>
> (OnSize)* -> OnInitDialog -> (OnSize)*
> where OnSize* means "zero or more times" but in fact there will be several calls on
> OnSize, many of which occur before OnInitDialog. As a regular expression, it might be
> better expressed as
> (OnSize)+ -> OnInitDialog -> (OnSize)+
> where Onsize+ means "One or more calls"
> *****
>
>
>
> > si.nPage = si.nMax/20;
> > si.nPos = 0;
> > SetScrollInfo(SB_VERT, &si, TRUE);
> >}
>
> >void C4IN1RegTopDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*
> >pScrollBar)
> >{
> > // TODO: Add your message handler code here and/or call default
>
> > int nDelta;
> > int nMaxPos = m_rect.Height() - m_iCurHeight;
>
> > switch (nSBCode)
> > {
> > case SB_LINEDOWN:
> > if (m_iScrollPos >= nMaxPos)
> > return;
> > nDelta = min(nMaxPos/20,nMaxPos-m_iScrollPos);
> > //nDelta = min(max(nMaxPos/20,5),nMaxPos-m_iScrollPos);
> > break;
>
> > case SB_LINEUP:
> > if (m_iScrollPos <= 0)
> > return;
> > nDelta = -min(nMaxPos/20,m_iScrollPos);
> > //nDelta = -min(max(nMaxPos/20,5),m_iScrollPos);
> > break;
>
> > case SB_PAGEDOWN:
> > if (m_iScrollPos >= nMaxPos)
> > return;
> > nDelta = min(nMaxPos/20,nMaxPos-m_iScrollPos);
> > //nDelta = min(max(nMaxPos/20,5),nMaxPos-m_iScrollPos);
> > break;
>
> > case SB_THUMBTRACK:
> > case SB_THUMBPOSITION:
> > {
> > nDelta = (int)nPos - m_iScrollPos;
> > //int iPos = GetScrollPos(SB_VERT);
> > //nDelta = (int)iPos - m_iScrollPos;
> > }
>
> ****
> But what is this computing? The correct value is to use nPos. The nPos value is an
> absolute scroll position. I don't understand why you are using a global m_iScrollPos
> value anyway. You can get the scroll position directly from the control.
> ****> break;
>
> > case SB_PAGEUP:
> > if (m_iScrollPos <= 0)
> > return;
> > nDelta = -min(nMaxPos/20,m_iScrollPos);
> > //nDelta = -min(max(nMaxPos/20,5),m_iScrollPos);
> > break;
>
> > default:
> > return;
> > }
> > m_iScrollPos += nDelta;
>
> ****
> I now see why you are using a delta. But this is not a natural way to express this.
> Instead, normal scrollbar control code stores the new position, so instead of computing
> the delta in the thumbtrack/thumbposition, you would just set the new position to be nPos;
> in other cases you would not compute the value, but compute the new position.
>
> As such, this code is hard to read and to understand.
> ****
>
>
>
> > SetScrollPos(SB_VERT,m_iScrollPos, TRUE);
> > ScrollWindow(0,-nDelta);
> > CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
>
> >}
>
> >Obviously this is eliminating a LOT of initialization, loading, etc.
> >Now, this works perfectly when the user presses on the ends of the
> >scrollbar. The dialog scrolls smoothly and it's all wonderful. But
> >when the user clicks and drags the thumbtrack, the SB_THUMBTRACK event
> >seems to not scroll all the way. It goes almost all the way, but it
> >seems like the last "tick" isn't there. I get all but the last
> >element. Then if the user taps the button, it scrolls a little more,
> >showing everything. If the user clicks the thumbtrack, it snaps back
> >to that "tick" before the end. I've stepped throught he code, and
> >when the user taps the thumbtrack, I get a position of 1592, as
> >opposed to 1620 that is the max (remember, my windowsize is 388, so
> >2008-388=1620, which I do get with the buttons).
>
> ****
> I haven't looked at the code in detail, but it looks like a classic off-by-one-unit error
> somewhere.
>
> I'd simplify this code and get rid of nearly all those member variables. Compute values
> as you need them, where you need them, from first principles.
> joe
>
> ****
>
> >Why isn't this last "tick" there? And how can I get it? The
> >thumbtrack size is dependent upon my nPage count, but I've tried to
> >monkey with that and that doesn't change the behaviour. It always
> >seems to be one tick short.
>
> >Thanks for the help,
> >~Scoots
>
> Joseph M. Newcomer [MVP]
> email: newco...(a)flounder.com
> Web:http://www.flounder.com
> MVP Tips:http://www.flounder.com/mvp_tips.htm- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -

From: Joseph M. Newcomer on
See below...
On Mon, 23 Nov 2009 15:06:43 -0800 (PST), Scoots <linkingfire(a)msn.com> wrote:

>My apologies that this will sound harsh. Rather, you have helped me
>numerous times, and I do value your input. But there's no way to
>answer your comments without sounding harsh.
>
>1. This is code that is not complete. It has problems, it has
>issues. Hence why I'm posting here about problems. I haven't gone
>over it and cleaned it up.
>2. It uses things I don't know very well, so my first and primary
>goal is to learn how it operates, then I can clean it. 80% of the
>code here is, in fact, from a Microsoft KB post. Given that there is
>a problem in it, my time and focus has been on fixing the code and in
>understanding the interactions, not in immediately rewriting the
>code. For instance, the difference between MoveWindow and
>SetWindowPos in regards to an embedded child window. You should have
>seen the code before I figured that out...
>3. You assume a lot about this application. In truth this is an
>emulation (legal, business emulation for simulation.). I emulate the
>application I am emulating. All of these hardcoded values are taken
>from this. This should never be in DLU's, percentages, or anything
>else. It is precise because it is meant to be. I didn't state this,
>and while it is true that this code is rough, it was posted here so
>that anyone else could duplicate my problem, no matter how junky or
>ugly my code is. You've yelled at me before for cleaning up code and
>the critical piece not being posted.
****
Still, doing anything with hardwired limits, for whatever reason, is dangerous.
****
>
>(oh, and I DO set the font. That was in the initialization that has
>nothing to do with window sizes and scrolling)
>
>"If you aren't changing the top or left, why do you bother using
>them? Just put 0,0 there
>and use SWP_NOMOVE"
>--Alright. That is my code, written while I was trying to get the
>scrollbar to work at ALL. I'll fix that.
>
>"It is not clear why you have a class variable for the rectangle.
>Note also that OnSize is
>called many, many times during the creation of a window, and the
>m_rect, which is not set
>until OnInitDialog, will not have a valid value at those times."
>--Well, the KB post the code was obtained from did, but that is not
>the reason it is still around. Rather, I noticed in the OnSize() that
>windows was forcing the window to 1030 pixels tall, presumably due to
>the size of the monitor. Or something. I couldn't find any
>documentation on it. The rectangle is retained because my window is
>nearly twice this size (though obviously not to the user), and I need
>the real size for the calculations.
****
Still, you are setting sizes in OnSize using an uninitialized variable.
****
>
>"(OnSize)* -> OnInitDialog -> (OnSize)*"
>--That's a perfectly fine regular expression. I don't understand why
>you need to correct it. Indeed, I've noticed this behavior, but aside
>from mentally noting it, I have not messed with it, as the end result
>of the KB code is still the same. The final size is what the user
>sees. The size of the scroll bar in between is largely irrelevant to
>the user (and me, at this stage in development, when I am still taking
>a virtual hacksaw to my code), as the window is shown AFTER it is
>initialized -- at which point the final size is already set.
****
Well, it gets messy if you start resizing to sizes like 0xCDCDCDCD or 0xCCCCCCCC or the
like. You get odd failures that propagate in odd ways. I've seen at least one case where
a child window got arranged modulo 65536 pixels (on WIn32!), and then when the next call
came in, the window was incorrectly placed and then got moved to the wrong place. Took me
hours to figure that one out (I didn't write the code, so was also in the fix of figuring
out what was going on).
****
>
>"But what is this computing? The correct value is to use nPos. The
>nPos value is an
>absolute scroll position. I don't understand why you are using a
>global m_iScrollPos
>value anyway. You can get the scroll position directly from the
>control."
>--Actually I ran into difficulties when doing this. GetScrollPos was
>returning the position from before the tracking took place, which was
>incorrect for the scroll operation done at the bottom of the routine.
>(If I was to switch the logic to what you suggested later, then yes,
>the nPos would be fine. For a Delta operation though, GetScrollPos
>and nPos fail miserably) Also, I haven't posted header files, but
>m_iScrollPos isn't a global, it's a member variable, if that helps (m_
>stands for member variable, in this notation).
****
I've not seen this; normally, GetScrollInfo (I don't know about GetScrollPos) is supposed
to give the absolute thumb position, so you can use displacements > 16K. Although it is
not obvious from the prototype, the nPos value is derived from a 16-bit value in the
message, and if your scrollbar can move more than 64K absolute distance, you can't use the
nPos value that comes in; it is used for backward compatibility with older code and any
code that has a limit < 64K scroll units. Otherwise, the documentation says you are
supposed to call GetScrollInfo to find the *actual* position value under these conditions.

By "global" (and I thought I corrected this but must have missed one) I really mean
"member variable global to the function", my error. I tend to keep these computations
local to the functions only because it is that much less state to manage.
****
>
>
>I appreciate your input, but the majority of your comments are
>directed at analyzing the Microsoft KB posting. This will undoubtedly
>help me to clean the code up, once the issue is resolved. However,
>I'm not that far along, as the issue is still there. I have been
>temporarily able to "resolve" the issue by adding an extra page
>(logically) to what Windows sees on the scrollbar.
****
When code is presented, I have to analyze the code I see; I can't infer that it is
directly from some KB article.
****
>
>In the OnSize Handler
>
> SCROLLINFO si;
> si.cbSize = sizeof(SCROLLINFO);
> si.fMask = SIF_ALL; // SIF_ALL = SIF_PAGE | SIF_RANGE
>| SIF_POS;
> si.nMin = 0;
> si.nMax = m_rect.Height() - m_iCurHeight + 81;
> si.nPage = si.nMax/20;
> si.nPos = 0;
> SetScrollInfo(SB_VERT, &si, TRUE);
>
>
>Because of the backwards-ness of my code in the OnVScroll, this
>actually works, because the scrolling from the linedown and other
>events are based on the REAL size of the window, not the expanded.
>This is a hack of a workaround, and I'm no closer to solving the
>issue.
>
>Thanks for the response, and I am sorry if it comes out sounding
>harsh. It's not meant to be.
****
It doesn't sound harsh, so I'm not sure what you are apologizing for.

I can't see how I can help more than I tried. I could only look at the code that was
there and try to figure out what could be wrong. The off-by-one problem is a common one,
and it usually means some kind of round-down truncation error; I usually solve it, when I
see it, by first figuring out how I'm off-by-one and then adding 1 in to the appropriate
place to cover it. /20 types of operations will truncate low, and that is a potential
source of the problem. So if you had a number of objects that worked out to 199 pixels,
and call a line "20", then you will have 19 units if you divide by 20, when you really
want 20. That's the first place I'd look for a problem.
joe
****
>~Scoots
>
>On Nov 23, 5:16 pm, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
>> See below...
>>
>>
>>
>>
>>
>> On Mon, 23 Nov 2009 13:06:32 -0800 (PST), Scoots <linkingf...(a)msn.com> wrote:
>> >Part of me feels rather dumb for asking this, but everything seems to
>> >work smoothly except for one scrolling action.
>>
>> >I have a dialog with two embedded child dialogs within it. The top
>> >dialog has a scrolling interface. The parent dialog is roughly 640 *
>> >540 pixels, with the top child dialog being 640*388. The ACTUAL size
>> >of the top child is 640*2008 (strange application, but YES, that is
>> >intentional. It has twenty "elements" which include a couple of
>> >statics and a picture control. So you'll see a lot of "20"'s floating
>> >around, that's why.).
>>
>> >Using information here:
>> >http://support.microsoft.com/kb/262954
>>
>> >I found I had to tweak it a bit to get it correct, as my Windows
>> >seemed to want to cap my window to 1030 tall, roughly the vertical
>> >pixel count of my screen, I guess.
>>
>> >Parent dialog:
>>
>> >BOOL C4IN1RegDialog::OnInitDialog()
>> >{
>> > CDialog::OnInitDialog();
>>
>> > m_TopDlg.Create(C4IN1RegTopDialog::IDD, this);
>> > m_BottomDlg.Create(C4IN1RegBottomDialog::IDD, this);
>>
>> > m_TopDlg.ShowWindow(SW_SHOW);
>> > CRect rc;
>> > GetWindowRect(rc);
>> > MoveWindow(rc.left, rc.top, 648, 530,true);
>> > m_TopDlg.MoveWindow(0,0,640, 388, true);
>>
>> ****
>> These hardwired numbers are a bit scary. I suppose if you never, ever change the machine
>> you are on, or your monitor, or your display card, or the resolution you use, they might
>> make sense, but overall, any code like this is so amazingly fragile that it cannot be
>> expected to run on any other machine in the known universe. Why do you think these
>> numbers, which can run on only your machine, with your current display, your current
>> display card, your current display resolution, your current default font, your current
>> display driver, with the current version of the OS with the current set of hotfixes, is
>> going to work even *next week*?
>>
>> You have to replace these values by meaningful computations.
>>
>> It is not very practical to create a window that is larger than the current screen
>> resolution. Since this can change at any time (for example, you buy a new monitor, move
>> it to your laptop, etc.), all hardwired constants are suspect.
>> ****
>>
>>
>>
>> > m_BottomDlg.ShowWindow(SW_SHOW);
>> > m_BottomDlg.MoveWindow(0,390,640, 120, true);
>>
>> > return TRUE; // return TRUE unless you set the focus to a control
>> > // EXCEPTION: OCX Property Pages should return FALSE
>> >}
>>
>> >Top dialog (bottom is fine, so I'll avoid code-spammage)
>>
>> >BOOL C4IN1RegTopDialog::OnInitDialog()
>> >{
>> > CDialog::OnInitDialog();
>>
>> > m_iScrollPos = 0;
>>
>> > m_rect.top = 0;
>> > m_rect.left = 0;
>> > m_rect.right = 617;
>>
>> ****
>> See previous comments about hardwired integers
>> ****> m_rect.bottom = iOffsetFromTop + ((iItem) * (iOffsetBetween +
>> >iSizeOfImageY));
>> > SetWindowPos(NULL, m_rect.left, m_rect.top, m_rect.right,
>> >m_rect.bottom, SWP_NOZORDER);
>>
>> ****
>> If you aren't changing the top or left, why do you bother using them? Just put 0,0 there
>> and use SWP_NOMOVE
>> ****
>>
>>
>>
>>
>>
>> > UpdateWindow();
>>
>> > return TRUE; // return TRUE unless you set the focus to a control
>> > // EXCEPTION: OCX Property Pages should return FALSE
>> >}
>>
>> >void C4IN1RegTopDialog::OnSize(UINT nType, int cx, int cy)
>> >{
>> > CDialog::OnSize(nType, cx, cy);
>>
>> > m_iCurHeight = cy;
>>
>> > SCROLLINFO si;
>> > si.cbSize = sizeof(SCROLLINFO);
>> > si.fMask = SIF_ALL; // SIF_ALL = SIF_PAGE | SIF_RANGE | SIF_POS;
>> > si.nMin = 0;
>> > si.nMax = m_rect.Height() - m_iCurHeight;
>>
>> ****
>> It is not clear why you have a class variable for the rectangle. Note also that OnSize is
>> called many, many times during the creation of a window, and the m_rect, which is not set
>> until OnInitDialog, will not have a valid value at those times.
>>
>> Either you have to have a boolean that says if the rectangle is valid, or compute the
>> value at this point from basic properties of the window. Do not store it as you have
>> done, and assume that the sequence is
>> OnInitDialog -> OnSize
>> when the actual sequence is
>>
>> (OnSize)* -> OnInitDialog -> (OnSize)*
>> where OnSize* means "zero or more times" but in fact there will be several calls on
>> OnSize, many of which occur before OnInitDialog. As a regular expression, it might be
>> better expressed as
>> (OnSize)+ -> OnInitDialog -> (OnSize)+
>> where Onsize+ means "One or more calls"
>> *****
>>
>>
>>
>> > si.nPage = si.nMax/20;
>> > si.nPos = 0;
>> > SetScrollInfo(SB_VERT, &si, TRUE);
>> >}
>>
>> >void C4IN1RegTopDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar*
>> >pScrollBar)
>> >{
>> > // TODO: Add your message handler code here and/or call default
>>
>> > int nDelta;
>> > int nMaxPos = m_rect.Height() - m_iCurHeight;
>>
>> > switch (nSBCode)
>> > {
>> > case SB_LINEDOWN:
>> > if (m_iScrollPos >= nMaxPos)
>> > return;
>> > nDelta = min(nMaxPos/20,nMaxPos-m_iScrollPos);
>> > //nDelta = min(max(nMaxPos/20,5),nMaxPos-m_iScrollPos);
>> > break;
>>
>> > case SB_LINEUP:
>> > if (m_iScrollPos <= 0)
>> > return;
>> > nDelta = -min(nMaxPos/20,m_iScrollPos);
>> > //nDelta = -min(max(nMaxPos/20,5),m_iScrollPos);
>> > break;
>>
>> > case SB_PAGEDOWN:
>> > if (m_iScrollPos >= nMaxPos)
>> > return;
>> > nDelta = min(nMaxPos/20,nMaxPos-m_iScrollPos);
>> > //nDelta = min(max(nMaxPos/20,5),nMaxPos-m_iScrollPos);
>> > break;
>>
>> > case SB_THUMBTRACK:
>> > case SB_THUMBPOSITION:
>> > {
>> > nDelta = (int)nPos - m_iScrollPos;
>> > //int iPos = GetScrollPos(SB_VERT);
>> > //nDelta = (int)iPos - m_iScrollPos;
>> > }
>>
>> ****
>> But what is this computing? The correct value is to use nPos. The nPos value is an
>> absolute scroll position. I don't understand why you are using a global m_iScrollPos
>> value anyway. You can get the scroll position directly from the control.
>> ****> break;
>>
>> > case SB_PAGEUP:
>> > if (m_iScrollPos <= 0)
>> > return;
>> > nDelta = -min(nMaxPos/20,m_iScrollPos);
>> > //nDelta = -min(max(nMaxPos/20,5),m_iScrollPos);
>> > break;
>>
>> > default:
>> > return;
>> > }
>> > m_iScrollPos += nDelta;
>>
>> ****
>> I now see why you are using a delta. But this is not a natural way to express this.
>> Instead, normal scrollbar control code stores the new position, so instead of computing
>> the delta in the thumbtrack/thumbposition, you would just set the new position to be nPos;
>> in other cases you would not compute the value, but compute the new position.
>>
>> As such, this code is hard to read and to understand.
>> ****
>>
>>
>>
>> > SetScrollPos(SB_VERT,m_iScrollPos, TRUE);
>> > ScrollWindow(0,-nDelta);
>> > CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
>>
>> >}
>>
>> >Obviously this is eliminating a LOT of initialization, loading, etc.
>> >Now, this works perfectly when the user presses on the ends of the
>> >scrollbar. The dialog scrolls smoothly and it's all wonderful. But
>> >when the user clicks and drags the thumbtrack, the SB_THUMBTRACK event
>> >seems to not scroll all the way. It goes almost all the way, but it
>> >seems like the last "tick" isn't there. I get all but the last
>> >element. Then if the user taps the button, it scrolls a little more,
>> >showing everything. If the user clicks the thumbtrack, it snaps back
>> >to that "tick" before the end. I've stepped throught he code, and
>> >when the user taps the thumbtrack, I get a position of 1592, as
>> >opposed to 1620 that is the max (remember, my windowsize is 388, so
>> >2008-388=1620, which I do get with the buttons).
>>
>> ****
>> I haven't looked at the code in detail, but it looks like a classic off-by-one-unit error
>> somewhere.
>>
>> I'd simplify this code and get rid of nearly all those member variables. Compute values
>> as you need them, where you need them, from first principles.
>> joe
>>
>> ****
>>
>> >Why isn't this last "tick" there? And how can I get it? The
>> >thumbtrack size is dependent upon my nPage count, but I've tried to
>> >monkey with that and that doesn't change the behaviour. It always
>> >seems to be one tick short.
>>
>> >Thanks for the help,
>> >~Scoots
>>
>> Joseph M. Newcomer [MVP]
>> email: newco...(a)flounder.com
>> Web:http://www.flounder.com
>> MVP Tips:http://www.flounder.com/mvp_tips.htm- Hide quoted text -
>>
>> - Show quoted text -- Hide quoted text -
>>
>> - Show quoted text -- Hide quoted text -
>>
>> - Show quoted text -- Hide quoted text -
>>
>> - Show quoted text -- Hide quoted text -
>>
>> - Show quoted text -
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Scoots on
I'm pretty sure you've hit it right on the head. If I add the
equivalent of a "page worth of data" I get the correct behavior.
Perhaps I'm not quite sure that my understanding of the SCROLLINFO
members is correct. My understanding is the nMin and nMax are the
maximum limits of the scrolling. From the MSDN documentation, the
nPage is the size of a "page." And you're right, a truncation was
occuring there. But while I would expect that the number of pages
would change the size of the slider, I would NOT expect it to change
the amount displayed. I could easily see that the incorrect number of
pages would yield an incorrect sliding amount, but I would expect the
code to use the size to determine how many pages there were. For
instance.

Say my window is 1626 and I tell it a page is /20. So...
1626/20 = 81
81*20 = 1620

Note that we have 6 extra lines worth of information.

If the code was doing this, I'd expect the MFC code to (personified
here) "AHAH! My page size is 81, and I need 21 pages to display
everything." But that's not the behavior I'm seeing. I'm seeing more
of a "eh, there's a partial page there, but I can't display that".

The trouble is, I've now forced it to be an even number of pages and I
still see this behavior. I'll definately keep working on it tomorrow,
I have the same hunch you have about where the error occurs (and I
know telling MFC I have an extra page makes it behave the way I want).

Thanks,
~Scoots




On Nov 23, 6:29 pm, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
> See below...
>
>
>
>
>
> On Mon, 23 Nov 2009 15:06:43 -0800 (PST), Scoots <linkingf...(a)msn.com> wrote:
> >My apologies that this will sound harsh.  Rather, you have helped me
> >numerous times, and I do value your input.  But there's no way to
> >answer your comments without sounding harsh.
>
> >1.  This is code that is not complete.  It has problems, it has
> >issues.  Hence why I'm posting here about problems.  I haven't gone
> >over it and cleaned it up.
> >2.  It uses things I don't know very well, so my first and primary
> >goal is to learn how it operates, then I can clean it.  80% of the
> >code here is, in fact, from a Microsoft KB post.  Given that there is
> >a problem in it, my time and focus has been on fixing the code and in
> >understanding the interactions, not in immediately rewriting the
> >code.  For instance, the difference between MoveWindow and
> >SetWindowPos in regards to an embedded child window.  You should have
> >seen the code before I figured that out...
> >3.  You assume a lot about this application.  In truth this is an
> >emulation (legal, business emulation for simulation.).  I emulate the
> >application I am emulating.  All of these hardcoded values are taken
> >from this.  This should never be in DLU's, percentages, or anything
> >else.  It is precise because it is meant to be.  I didn't state this,
> >and while it is true that this code is rough, it was posted here so
> >that anyone else could duplicate my problem, no matter how junky or
> >ugly my code is.  You've yelled at me before for cleaning up code and
> >the critical piece not being posted.
>
> ****
> Still, doing anything with hardwired limits, for whatever reason, is dangerous.
> ****
>
>
>
>
>
> >(oh, and I DO set the font.  That was in the initialization that has
> >nothing to do with window sizes and scrolling)
>
> >"If you aren't changing the top or left, why do you bother using
> >them?  Just put 0,0 there
> >and use SWP_NOMOVE"
> >--Alright.  That is my code, written while I was trying to get the
> >scrollbar to work at ALL.  I'll fix that.
>
> >"It is not clear why you have a class variable for the rectangle.
> >Note also that OnSize is
> >called many, many times during the creation of a window, and the
> >m_rect, which is not set
> >until OnInitDialog, will not have a valid value at those times."
> >--Well, the KB post the code was obtained from did, but that is not
> >the reason it is still around.  Rather, I noticed in the OnSize() that
> >windows was forcing the window to 1030 pixels tall, presumably due to
> >the size of the monitor.  Or something.  I couldn't find any
> >documentation on it.  The rectangle is retained because my window is
> >nearly twice this size (though obviously not to the user), and I need
> >the real size for the calculations.
>
> ****
> Still, you are setting sizes in OnSize using an uninitialized variable.
> ****
>
> >"(OnSize)* -> OnInitDialog -> (OnSize)*"
> >--That's a perfectly fine regular expression.  I don't understand why
> >you need to correct it.  Indeed, I've noticed this behavior, but aside
> >from mentally noting it, I have not messed with it, as the end result
> >of the KB code is still the same.  The final size is what the user
> >sees.  The size of the scroll bar in between is largely irrelevant to
> >the user (and me, at this stage in development, when I am still taking
> >a virtual hacksaw to my code), as the window is shown AFTER it is
> >initialized -- at which point the final size is already set.
>
> ****
> Well, it gets messy if you start resizing to sizes like 0xCDCDCDCD or 0xCCCCCCCC or the
> like.  You get odd failures that propagate in odd ways.  I've seen at least one case where
> a child window got arranged modulo 65536 pixels (on WIn32!), and then when the next call
> came in, the window was incorrectly placed and then got moved to the wrong place.  Took me
> hours to figure that one out (I didn't write the code, so was also in the fix of figuring
> out what was going on).
> ****
>
> >"But what is this computing?  The correct value is to use nPos.  The
> >nPos value is an
> >absolute scroll position.  I don't understand why you are using a
> >global m_iScrollPos
> >value anyway.  You can get the scroll position directly from the
> >control."
> >--Actually I ran into difficulties when doing this.  GetScrollPos was
> >returning the position from before the tracking took place, which was
> >incorrect for the scroll operation done at the bottom of the routine.
> >(If I was to switch the logic to what you suggested later, then yes,
> >the nPos would be fine.  For a Delta operation though, GetScrollPos
> >and nPos fail miserably)  Also, I haven't posted header files, but
> >m_iScrollPos isn't a global, it's a member variable, if that helps (m_
> >stands for member variable, in this notation).
>
> ****
> I've not seen this; normally, GetScrollInfo (I don't know about GetScrollPos) is supposed
> to give the absolute thumb position, so you can use displacements > 16K.  Although it is
> not obvious from the prototype, the nPos value is derived from a 16-bit value in the
> message, and if your scrollbar can move more than 64K absolute distance, you can't use the
> nPos value that comes in; it is used for backward compatibility with older code and any
> code that has a limit < 64K scroll units.  Otherwise, the documentation says you are
> supposed to call GetScrollInfo to find the *actual* position value under these conditions.
>
> By "global" (and I thought I corrected this but must have missed one) I really mean
> "member variable global to the function", my error.  I tend to keep these computations
> local to the functions only because it is that much less state to manage.
> ****
>
> >I appreciate your input, but the majority of your comments are
> >directed at analyzing the Microsoft KB posting.  This will undoubtedly
> >help me to clean the code up, once the issue is resolved.  However,
> >I'm not that far along, as the issue is still there.  I have been
> >temporarily able to "resolve" the issue by adding an extra page
> >(logically) to what Windows sees on the scrollbar.
>
> ****
> When code is presented, I have to analyze the code I see; I can't infer that it is
> directly from some KB article.
> ****
>
>
>
>
>
> >In the OnSize Handler
>
> >                SCROLLINFO si;
> >                si.cbSize = sizeof(SCROLLINFO);
> >                si.fMask = SIF_ALL; // SIF_ALL = SIF_PAGE | SIF_RANGE
> >| SIF_POS;
> >                si.nMin = 0;
> >                si.nMax = m_rect.Height() - m_iCurHeight + 81;
> >                si.nPage = si.nMax/20;
> >                si.nPos = 0;
> >                SetScrollInfo(SB_VERT, &si, TRUE);
>
> >Because of the backwards-ness of my code in the OnVScroll, this
> >actually works, because the scrolling from the linedown and other
> >events are based on the REAL size of the window, not the expanded.
> >This is a hack of a workaround, and I'm no closer to solving the
> >issue.
>
> >Thanks for the response, and I am sorry if it comes out sounding
> >harsh.  It's not meant to be.
>
> ****
> It doesn't sound harsh, so I'm not sure what you are apologizing for.
>
> I can't see how I can help more than I tried.  I could only look at the code that was
> there and try to figure out what could be wrong.  The off-by-one problem is a common one,
> and it usually means some kind of round-down truncation error; I usually solve it, when I
> see it, by first figuring out how I'm off-by-one and then adding 1 in to the appropriate
> place to cover it.  /20 types of operations will truncate low, and that is a potential
> source of the problem.  So if you had a number of objects that worked out to 199 pixels,
> and call a line "20", then you will have 19 units if you divide by 20, when you really
> want 20.  That's the first place I'd look for a problem.
>                                 joe
> ****
>
>
>
> >~Scoots
>
> >On Nov 23, 5:16 pm, Joseph M. Newcomer <newco...(a)flounder.com> wrote:
> >> See below...
>
> >> On Mon, 23 Nov 2009 13:06:32 -0800 (PST), Scoots <linkingf...(a)msn.com> wrote:
> >> >Part of me feels rather dumb for asking this, but everything seems to
> >> >work smoothly except for one scrolling action.
>
> >> >I have a dialog with two embedded child dialogs within it.  The top
> >> >dialog has a scrolling interface.  The parent dialog is roughly 640 *
> >> >540 pixels, with the top child dialog being 640*388.  The ACTUAL size
> >> >of the top child is 640*2008 (strange application, but YES, that is
> >> >intentional.   It has twenty "elements" which include a couple of
> >> >statics and a picture control.  So you'll see a lot of "20"'s floating
> >> >around, that's why.).
>
> >> >Using information here:
> >> >http://support.microsoft.com/kb/262954
>
> >> >I found I had to tweak it a bit to get it correct, as my Windows
> >> >seemed to want to cap my window to 1030 tall, roughly the vertical
> >> >pixel count of my screen, I guess.
>
> >> >Parent dialog:
>
> >> >BOOL C4IN1RegDialog::OnInitDialog()
> >> >{
> >> >    CDialog::OnInitDialog();
>
> >> >    m_TopDlg.Create(C4IN1RegTopDialog::IDD, this);
> >> >    m_BottomDlg.Create(C4IN1RegBottomDialog::IDD, this);
>
> >> >    m_TopDlg.ShowWindow(SW_SHOW);
> >> >    CRect rc;
> >> >    GetWindowRect(rc);
> >> >    MoveWindow(rc.left, rc.top, 648, 530,true);
> >> >    m_TopDlg.MoveWindow(0,0,640, 388, true);
>
> >> ****
> >> These hardwired numbers are a bit scary.  I suppose if you never, ever change the machine
> >> you are on, or your monitor, or your display card, or the resolution you use, they might
> >> make sense, but overall, any code like this is so amazingly fragile that it cannot be
> >> expected to run on any other machine in the known universe.  Why do you think these
> >> numbers, which can run on only your machine, with your current display, your current
> >> display card, your current display resolution, your current default font, your current
> >> display driver, with the current version of the OS with the current set of hotfixes, is
> >> going to work even *next week*?
>
> >> You have to replace these values by meaningful computations.
>
> >> It is not very practical to create a window that is larger than the current screen
> >> resolution.  Since this can change at any time (for example, you buy a new monitor, move
> >> it to your laptop, etc.), all
>
> ...
>
> read more »- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -