Code:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ HDC hdc;
PAINTSTRUCT ps;
SCROLLINFO si; // scroll info
static int cxChar, cxCaps, cyChar;
static int cxClient, cyClient, iMaxWidth; // current size of the window
int iVertPos,iHorzPos, iPaintBeg, iPaintEnd, y,x,i;
static int NUMLINES=1000;
TCHAR szBuffer[10];
TEXTMETRIC tm;
switch (message)
{
case WM_CREATE: // when window is created
hdc=GetDC(hwnd); // gets handle for paint functions
GetTextMetrics (hdc,&tm); // gets info for text, like font size
cxChar=tm.tmAveCharWidth;
cxCaps=(tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar/2;
cyChar = tm.tmHeight+tm.tmExternalLeading;
ReleaseDC(hwnd, hdc);
iMaxWidth=1000;
return 0;
case WM_SIZE: // for when the window is resized
cxClient=LOWORD(lParam);
cyClient=HIWORD(lParam);
// Set vertical scroll bar range and page size
si.cbSize=sizeof(si); // always done. this way in future updates the size updates auto
si.fMask=SIF_RANGE | SIF_PAGE;
si.nMin=0;
si.nMax=NUMLINES-1;
si.nPage=cyClient/cyChar;
SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
// Set horizontal scroll bar range and page size
si.cbSize=sizeof(si); // always done. this way in future updates the size updates auto
si.fMask=SIF_RANGE | SIF_PAGE;
si.nMin=0;
si.nMax=2+iMaxWidth/cxChar;
si.nPage=cxClient/cxChar;
SetScrollInfo(hwnd,SB_HORZ,&si,TRUE);
return 0;
case WM_PAINT: // when it needs to be painted/repainted
hdc=BeginPaint(hwnd, &ps);
si.cbSize=sizeof(si);
si.fMask=SIF_POS;
GetScrollInfo(hwnd,SB_VERT,&si);
iVertPos=si.nPos;
GetScrollInfo(hwnd,SB_HORZ,&si);
iHorzPos=si.nPos;
iPaintBeg=max(0,iVertPos+ps.rcPaint.top/cyChar);
iPaintEnd=min(NUMLINES-1,iVertPos+ps.rcPaint.bottom/cyChar);
for (i=iPaintBeg; i<=iPaintEnd; i++)
{
x=0;
y=cyChar*(i-iVertPos);
TextOut(hdc,x,y,szBuffer,wsprintf(szBuffer,TEXT("%i. This Works!"),y));
}
EndPaint(hwnd, &ps);
return 0;
case WM_VSCROLL: // vertical scroll
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_VERT,&si);
iVertPos=si.nPos;
switch (LOWORD(wParam))
{
case SB_TOP:
si.nPos=si.nMin;
break;
case SB_BOTTOM:
si.nPos=si.nMax;
break;
case SB_LINEUP: // click arrow pointing up
si.nPos--;
break;
case SB_LINEDOWN: // click arrow pointing down
si.nPos++;
break;
case SB_PAGEUP: // click empty spot above thumbtab
si.nPos-=si.nPage;
break;
case SB_PAGEDOWN: // click empty spot below thumbtab
si.nPos+=si.nPage;
break;
case SB_THUMBPOSITION: // click thumbtab
si.nPos=si.nTrackPos;
break;
default:
break;
}
// set position and then retrieve it.
si.fMask=SIF_POS;
SetScrollInfo(hwnd,SB_VERT,&si,TRUE);
GetScrollInfo(hwnd,SB_VERT,&si);
// if position has changed, scroll window and update it
if (si.nPos!=iVertPos)
{
ScrollWindow(hwnd,0,cyChar*(iVertPos-si.nPos),NULL,NULL);
UpdateWindow(hwnd);
}
return 0;
case WM_HSCROLL: // side-to-side scroll
si.cbSize=sizeof(si);
si.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_HORZ,&si);
iHorzPos=si.nPos;
switch (LOWORD(wParam))
{
case SB_LINELEFT: // click arrow pointing left
si.nPos--;
break;
case SB_LINERIGHT: // click arrow pointing right
si.nPos++;
break;
case SB_PAGELEFT: // click empty spot next to thumbtab
si.nPos-=si.nPage;
break;
case SB_PAGERIGHT: // click empty spot next to thumbtab
si.nPos+=si.nPage;
break;
case SB_THUMBPOSITION: // click thumbtab
si.nPos=si.nTrackPos;
break;
default:
break;
}
// set position and then retrieve it.
si.fMask=SIF_POS;
SetScrollInfo(hwnd,SB_HORZ,&si,TRUE);
GetScrollInfo(hwnd,SB_HORZ,&si);
// if position has changed, scroll window and update it
if (si.nPos!=iHorzPos)
{
ScrollWindow(hwnd,cxChar*(iHorzPos-si.nPos),0,NULL,NULL);
UpdateWindow(hwnd);
}
return 0;
case WM_DESTROY: // when it is destroyed
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}