godzilla
asked on
Strange Behavior in NT 4.0
I have a Win32 C app that works fine in W95 and NT 3.51. In NT 4.0, however, the client area of the app window (it's SDI) does not seem to get painted properly. Instead of a white background, it shows whatever was on the screen behind it when the app was launched. When the screen refreshes, the client area displays again what is on the screen, not the usual white background. (In all other respects, the app functions normally.)
I handle the WM_PAINT message by calling this function:
void RepaintScreen(HWND hWnd, PAINTSTRUCT ps, short ylen) {
int iCtr;
HDC hDc;
int begin = 0;
Y = 2;
if ( SCREEN_LINES > (ylen/Spacing) && bScreenLines )
begin = SCREEN_LINES - (ylen/Spacing);
//hDc = BeginPaint(hWnd,&ps);
hDc = ps.hdc;
for (iCtr = begin; iCtr < SCREEN_LINES; iCtr++)
{
if ( lpsScrn[iCtr][0] != '\0' )
{
TextOut(hDc, 1, Y, lpsScrn[iCtr], lstrlen(lpsScrn[iCtr]));
Y = CheckForScroll(hWnd,
Y,
Spacing,
lstrlen(lpsScrn[iCtr]) * tm.tmMaxCharWidth);
}
}
EndPaint(hWnd,&ps);
return;
}
RepaintScreen() calls CheckForScroll():
int CheckForScroll(hWnd,Curren tPosition, Spacing, Length)
HWND hWnd;
int CurrentPosition;
int Spacing;
int Length;
{
RECT rect; /* RECT structure for validation */
rect.top = CurrentPosition; /* top of last line of text */
rect.bottom = CurrentPosition+Spacing+1; /* bottom of last line */
rect.left = 1; /* left most column of line */
rect.right = Length+1; /* right most column of line */
GetClientRect(hWnd,(LPRECT )&rect); /* get rect for current client */
if(CurrentPosition + (Spacing*2) > rect.bottom) /* will line fit */
{
/* if not scroll window and */
/* update client window */
ScrollWindowEx(hWnd,0,-(Sp acing+1), (CONST RECT*) NULL,
(CONST RECT*) NULL,
(HRGN)NULL,(RECT FAR*)NULL, 0);
return(CurrentPosition);
}
return(CurrentPosition+Spa cing);
}
I handle the WM_PAINT message by calling this function:
void RepaintScreen(HWND hWnd, PAINTSTRUCT ps, short ylen) {
int iCtr;
HDC hDc;
int begin = 0;
Y = 2;
if ( SCREEN_LINES > (ylen/Spacing) && bScreenLines )
begin = SCREEN_LINES - (ylen/Spacing);
//hDc = BeginPaint(hWnd,&ps);
hDc = ps.hdc;
for (iCtr = begin; iCtr < SCREEN_LINES; iCtr++)
{
if ( lpsScrn[iCtr][0] != '\0' )
{
TextOut(hDc, 1, Y, lpsScrn[iCtr], lstrlen(lpsScrn[iCtr]));
Y = CheckForScroll(hWnd,
Y,
Spacing,
lstrlen(lpsScrn[iCtr]) * tm.tmMaxCharWidth);
}
}
EndPaint(hWnd,&ps);
return;
}
RepaintScreen() calls CheckForScroll():
int CheckForScroll(hWnd,Curren
HWND hWnd;
int CurrentPosition;
int Spacing;
int Length;
{
RECT rect; /* RECT structure for validation */
rect.top = CurrentPosition; /* top of last line of text */
rect.bottom = CurrentPosition+Spacing+1;
rect.left = 1; /* left most column of line */
rect.right = Length+1; /* right most column of line */
GetClientRect(hWnd,(LPRECT
if(CurrentPosition + (Spacing*2) > rect.bottom) /* will line fit */
{
/* if not scroll window and */
/* update client window */
ScrollWindowEx(hWnd,0,-(Sp
(CONST RECT*) NULL,
(HRGN)NULL,(RECT FAR*)NULL, 0);
return(CurrentPosition);
}
return(CurrentPosition+Spa
}
ASKER
This is how the WNDCLASS structure is filled:
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)WindowsProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, ICON) ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHI TE_BRUSH);
wc.lpszMenuName = (LPSTR)MENU_NAME ;
wc.lpszClassName = (LPSTR)CLASS_NAME ;
This is how WM_PAINT is handled (works fine for 16-bit programs):
case WM_PAINT:
RepaintScreen(hWnd,cyClien t);
break;
void RepaintScreen(HWND hWnd,short ylen) {
PAINTSTRUCT ps;
int iCtr;
HDC hDc;
int begin = 0;
Y = 2;
if ( SCREEN_LINES > (ylen/Spacing) && bScreenLines )
begin = SCREEN_LINES - (ylen/Spacing);
hDc = BeginPaint(hWndLocal,&ps);
for (iCtr = begin; iCtr < SCREEN_LINES; iCtr++)
{
if ( lpsScrn[iCtr][0] != '\0' )
{
TextOut(hDc, 1, Y, lpsScrn[iCtr], lstrlen(lpsScrn[iCtr]));
Y = CheckForScroll(hWndLocal,
Y,
Spacing,
lstrlen(lpsScrn[iCtr]) * tm.tmMaxCharWidth);
}
}
UpdateWindow(hWndLocal);
EndPaint(hWndLocal,&ps);
ReleaseDC(hWndLocal, hDc);
return;
}
WM_ERASEBKGND is not handled (could that be the problem?)
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)WindowsProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, ICON) ;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHI
wc.lpszMenuName = (LPSTR)MENU_NAME ;
wc.lpszClassName = (LPSTR)CLASS_NAME ;
This is how WM_PAINT is handled (works fine for 16-bit programs):
case WM_PAINT:
RepaintScreen(hWnd,cyClien
break;
void RepaintScreen(HWND hWnd,short ylen) {
PAINTSTRUCT ps;
int iCtr;
HDC hDc;
int begin = 0;
Y = 2;
if ( SCREEN_LINES > (ylen/Spacing) && bScreenLines )
begin = SCREEN_LINES - (ylen/Spacing);
hDc = BeginPaint(hWndLocal,&ps);
for (iCtr = begin; iCtr < SCREEN_LINES; iCtr++)
{
if ( lpsScrn[iCtr][0] != '\0' )
{
TextOut(hDc, 1, Y, lpsScrn[iCtr], lstrlen(lpsScrn[iCtr]));
Y = CheckForScroll(hWndLocal,
Y,
Spacing,
lstrlen(lpsScrn[iCtr]) * tm.tmMaxCharWidth);
}
}
UpdateWindow(hWndLocal);
EndPaint(hWndLocal,&ps);
ReleaseDC(hWndLocal, hDc);
return;
}
WM_ERASEBKGND is not handled (could that be the problem?)
1. Use hdc memeber of PAINTSTRUCT:
hDc=pc.hdc;
2. Do not use UpdateWindow() inside WM_PAINT handling function - it may cause endless loop. It is not necessary to call UpdateWindow() here.
3. Do not call ReleaseDC()
hDc=pc.hdc;
2. Do not use UpdateWindow() inside WM_PAINT handling function - it may cause endless loop. It is not necessary to call UpdateWindow() here.
3. Do not call ReleaseDC()
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Good answers, but they didn't do the trick. Here's some more information: My CheckForScroll() function. Perhaps the problem lies here?
int CheckForScroll(hWnd,Curren tPosition, Spacing, Length)
HWND hWnd;
int CurrentPosition;
int Spacing;
int Length;
{
RECT rect; /* RECT structure for validation */
rect.top = CurrentPosition; /* top of last line of text */
rect.bottom = CurrentPosition+Spacing+1; /* bottom of last line */
rect.left = 1; /* left most column of line */
rect.right = Length+1; /* right most column of line */
ValidateRect(hWnd,(LPRECT) &rect); /* validate line so that it is */
/* not blanked on next paint */
GetClientRect(hWnd,(LPRECT )&rect); /* get rect for current client */
if(CurrentPosition + (Spacing*2) > rect.bottom) /* will line fit */
{
/* if not scroll window and */
/* update client window */
ScrollWindowEx(hWnd,0,-(Sp acing+1), (RECT FAR*) NULL,
(RECT FAR*) NULL,
(HRGN)NULL,(RECT FAR*)NULL, (UINT)NULL);
return(CurrentPosition);
}
return(CurrentPosition+Spa cing);
}
int CheckForScroll(hWnd,Curren
HWND hWnd;
int CurrentPosition;
int Spacing;
int Length;
{
RECT rect; /* RECT structure for validation */
rect.top = CurrentPosition; /* top of last line of text */
rect.bottom = CurrentPosition+Spacing+1;
rect.left = 1; /* left most column of line */
rect.right = Length+1; /* right most column of line */
ValidateRect(hWnd,(LPRECT)
/* not blanked on next paint */
GetClientRect(hWnd,(LPRECT
if(CurrentPosition + (Spacing*2) > rect.bottom) /* will line fit */
{
/* if not scroll window and */
/* update client window */
ScrollWindowEx(hWnd,0,-(Sp
(RECT FAR*) NULL,
(HRGN)NULL,(RECT FAR*)NULL, (UINT)NULL);
return(CurrentPosition);
}
return(CurrentPosition+Spa
}
You should not call ValidateRect() API inside the WM_PAINT.
The BeginPaint function automatically validates the entire client area. ValidateRect() nor ValidateRgn() function should be called if a portion of the update region must be validated before the next WM_PAINT message is generated.
Win32 continues to generate WM_PAINT messages until the current update region is validated.
By the way, you should not use unnecessarry typecasting of NULL in your code, when the parameter is plain UINT. In Win32 NULL is defined differently than in Win16. Just use honest 0 instead.
My best regards
ETE
The BeginPaint function automatically validates the entire client area. ValidateRect() nor ValidateRgn() function should be called if a portion of the update region must be validated before the next WM_PAINT message is generated.
Win32 continues to generate WM_PAINT messages until the current update region is validated.
By the way, you should not use unnecessarry typecasting of NULL in your code, when the parameter is plain UINT. In Win32 NULL is defined differently than in Win16. Just use honest 0 instead.
My best regards
ETE
ASKER
Ete, I've made changes according to your latest suggestions. The client area still isn't being painted or refreshed, though.
ASKER
Edited text of question
Try to comment line with 'ScrollWindowEx' and see what happens.
Then try to use SW_ERASE or/and SW_VALIDATE as last parameter for ScrollWindowEx.
In my opinion, it's dangerous and, may be, not correctly to use ScrollWindow.. in WM_PAINT handler.
Then try to use SW_ERASE or/and SW_VALIDATE as last parameter for ScrollWindowEx.
In my opinion, it's dangerous and, may be, not correctly to use ScrollWindow.. in WM_PAINT handler.
Or, just use ScrollWindow instead of ScrollWindowEx - in any case you don't use extended features of ScrollWindowEx..
ASKER
I tried commenting out ScrollWindowEx, and it had no effect on the problem, so the cause must be elsewhere.
- how do you fill the window class structure (specially the background brush) before registering it?
- how do you handle WM_PAINT and WM_ERASEBKGND in your window procedure?
Regards ETE