Protect against use of comctl32 private control memory after it has
[wine.git] / dlls / comctl32 / progress.c
blob792bab2995cb8625ef129af4c3f156433fe79860
1 /*
2 * Progress control
4 * Copyright 1997 Dimitrie O. Paun
5 * Copyright 1998, 1999 Eric Kohl
7 */
9 #include "winbase.h"
10 #include "commctrl.h"
11 #include "progress.h"
12 #include "debugtools.h"
14 DEFAULT_DEBUG_CHANNEL(progress)
17 /* Control configuration constants */
19 #define LED_GAP 2
21 /* Work constants */
23 #define UNKNOWN_PARAM(msg, wParam, lParam) WARN(\
24 "Unknown parameter(s) for message " #msg \
25 "(%04x): wp=%04x lp=%08lx\n", msg, wParam, lParam);
27 #define PROGRESS_GetInfoPtr(hwnd) ((PROGRESS_INFO *)GetWindowLongA(hwnd, 0))
30 /***********************************************************************
31 * PROGRESS_Draw
32 * Draws the progress bar.
34 static void
35 PROGRESS_Draw (HWND hwnd, HDC hdc)
37 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
38 HBRUSH hbrBar, hbrBk;
39 int rightBar, rightMost, ledWidth;
40 RECT rect;
41 DWORD dwStyle;
43 TRACE("refresh pos=%d min=%d, max=%d\n",
44 infoPtr->CurVal, infoPtr->MinVal, infoPtr->MaxVal);
46 /* get the required bar brush */
47 if (infoPtr->ColorBar == CLR_DEFAULT)
48 hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
49 else
50 hbrBar = CreateSolidBrush (infoPtr->ColorBar);
52 /* get the required background brush */
53 if (infoPtr->ColorBk == CLR_DEFAULT)
54 hbrBk = GetSysColorBrush (COLOR_3DFACE);
55 else
56 hbrBk = CreateSolidBrush (infoPtr->ColorBk);
58 /* get client rectangle */
59 GetClientRect (hwnd, &rect);
61 /* draw the background */
62 FillRect(hdc, &rect, hbrBk);
64 rect.left++; rect.right--; rect.top++; rect.bottom--;
66 /* get the window style */
67 dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
69 /* compute extent of progress bar */
70 if (dwStyle & PBS_VERTICAL)
72 rightBar = rect.bottom -
73 MulDiv(infoPtr->CurVal-infoPtr->MinVal,
74 rect.bottom - rect.top,
75 infoPtr->MaxVal-infoPtr->MinVal);
76 ledWidth = MulDiv ((rect.right - rect.left), 2, 3);
77 rightMost = rect.top;
79 else
81 rightBar = rect.left +
82 MulDiv(infoPtr->CurVal-infoPtr->MinVal,
83 rect.right - rect.left,
84 infoPtr->MaxVal-infoPtr->MinVal);
85 ledWidth = MulDiv ((rect.bottom - rect.top), 2, 3);
86 rightMost = rect.right;
89 /* now draw the bar */
90 if (dwStyle & PBS_SMOOTH)
92 if (dwStyle & PBS_VERTICAL)
93 rect.top = rightBar;
94 else
95 rect.right = rightBar;
96 FillRect(hdc, &rect, hbrBar);
98 else
100 if (dwStyle & PBS_VERTICAL)
102 while(rect.bottom > rightBar) {
103 rect.top = rect.bottom-ledWidth;
104 if (rect.top < rightMost)
105 rect.top = rightMost;
106 FillRect(hdc, &rect, hbrBar);
107 rect.bottom = rect.top-LED_GAP;
110 else {
111 while(rect.left < rightBar) {
112 rect.right = rect.left+ledWidth;
113 if (rect.right > rightMost)
114 rect.right = rightMost;
115 FillRect(hdc, &rect, hbrBar);
116 rect.left = rect.right+LED_GAP;
121 /* delete bar brush */
122 if (infoPtr->ColorBar != CLR_DEFAULT)
123 DeleteObject (hbrBar);
125 /* delete background brush */
126 if (infoPtr->ColorBk != CLR_DEFAULT)
127 DeleteObject (hbrBk);
130 /***********************************************************************
131 * PROGRESS_Refresh
132 * Draw the progress bar. The background need not be erased.
134 static void
135 PROGRESS_Refresh (HWND hwnd)
137 HDC hdc;
139 hdc = GetDC (hwnd);
140 PROGRESS_Draw (hwnd, hdc);
141 ReleaseDC (hwnd, hdc);
144 /***********************************************************************
145 * PROGRESS_Paint
146 * Draw the progress bar. The background need not be erased.
147 * If dc!=0, it draws on it
149 static void
150 PROGRESS_Paint (HWND hwnd)
152 PAINTSTRUCT ps;
153 HDC hdc;
155 hdc = BeginPaint (hwnd, &ps);
156 PROGRESS_Draw (hwnd, hdc);
157 EndPaint (hwnd, &ps);
161 /***********************************************************************
162 * PROGRESS_CoercePos
163 * Makes sure the current position (CUrVal) is within bounds.
165 static void PROGRESS_CoercePos(HWND hwnd)
167 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
169 if(infoPtr->CurVal < infoPtr->MinVal)
170 infoPtr->CurVal = infoPtr->MinVal;
171 if(infoPtr->CurVal > infoPtr->MaxVal)
172 infoPtr->CurVal = infoPtr->MaxVal;
176 /***********************************************************************
177 * PROGRESS_SetFont
178 * Set new Font for progress bar
180 static HFONT
181 PROGRESS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
183 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
184 HFONT hOldFont = infoPtr->hFont;
186 infoPtr->hFont = (HFONT)wParam;
187 if (LOWORD(lParam))
188 PROGRESS_Refresh (hwnd);
189 return hOldFont;
193 /***********************************************************************
194 * ProgressWindowProc
196 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
197 WPARAM wParam, LPARAM lParam)
199 PROGRESS_INFO *infoPtr = PROGRESS_GetInfoPtr(hwnd);
200 UINT temp;
201 if (!infoPtr && (message != WM_CREATE))
202 return DefWindowProcA( hwnd, message, wParam, lParam );
203 switch(message)
205 case WM_NCCREATE:
207 DWORD dwExStyle;
208 dwExStyle = GetWindowLongA (hwnd, GWL_EXSTYLE);
209 SetWindowLongA (hwnd, GWL_EXSTYLE, dwExStyle | WS_EX_STATICEDGE);
211 return TRUE;
213 case WM_CREATE:
214 /* allocate memory for info struct */
215 infoPtr =
216 (PROGRESS_INFO *)COMCTL32_Alloc (sizeof(PROGRESS_INFO));
217 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
219 /* initialize the info struct */
220 infoPtr->MinVal=0;
221 infoPtr->MaxVal=100;
222 infoPtr->CurVal=0;
223 infoPtr->Step=10;
224 infoPtr->ColorBar=CLR_DEFAULT;
225 infoPtr->ColorBk=CLR_DEFAULT;
226 infoPtr->hFont=(HANDLE)NULL;
227 TRACE("Progress Ctrl creation, hwnd=%04x\n", hwnd);
228 break;
230 case WM_DESTROY:
231 TRACE("Progress Ctrl destruction, hwnd=%04x\n", hwnd);
232 COMCTL32_Free (infoPtr);
233 SetWindowLongA(hwnd, 0, 0);
234 break;
236 case WM_ERASEBKGND:
237 /* pretend to erase it here, but we will do it in the paint
238 function to avoid flicker */
239 return 1;
241 case WM_GETFONT:
242 return (LRESULT)infoPtr->hFont;
244 case WM_SETFONT:
245 return PROGRESS_SetFont (hwnd, wParam, lParam);
247 case WM_PAINT:
248 PROGRESS_Paint (hwnd);
249 break;
251 case PBM_DELTAPOS:
252 if(lParam)
253 UNKNOWN_PARAM(PBM_DELTAPOS, wParam, lParam);
254 temp = infoPtr->CurVal;
255 if(wParam != 0){
256 infoPtr->CurVal += (UINT16)wParam;
257 PROGRESS_CoercePos (hwnd);
258 PROGRESS_Refresh (hwnd);
260 return temp;
262 case PBM_SETPOS:
263 if (lParam)
264 UNKNOWN_PARAM(PBM_SETPOS, wParam, lParam);
265 temp = infoPtr->CurVal;
266 if(temp != wParam){
267 infoPtr->CurVal = (UINT16)wParam;
268 PROGRESS_CoercePos(hwnd);
269 PROGRESS_Refresh (hwnd);
271 return temp;
273 case PBM_SETRANGE:
274 if (wParam)
275 UNKNOWN_PARAM(PBM_SETRANGE, wParam, lParam);
276 temp = MAKELONG(infoPtr->MinVal, infoPtr->MaxVal);
277 if(temp != lParam){
278 infoPtr->MinVal = LOWORD(lParam);
279 infoPtr->MaxVal = HIWORD(lParam);
280 if(infoPtr->MaxVal <= infoPtr->MinVal)
281 infoPtr->MaxVal = infoPtr->MinVal+1;
282 PROGRESS_CoercePos(hwnd);
283 PROGRESS_Refresh (hwnd);
285 return temp;
287 case PBM_SETSTEP:
288 if (lParam)
289 UNKNOWN_PARAM(PBM_SETSTEP, wParam, lParam);
290 temp = infoPtr->Step;
291 infoPtr->Step = (UINT16)wParam;
292 return temp;
294 case PBM_STEPIT:
295 if (wParam || lParam)
296 UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
297 temp = infoPtr->CurVal;
298 infoPtr->CurVal += infoPtr->Step;
299 if(infoPtr->CurVal > infoPtr->MaxVal)
300 infoPtr->CurVal = infoPtr->MinVal;
301 if(temp != infoPtr->CurVal)
302 PROGRESS_Refresh (hwnd);
303 return temp;
305 case PBM_SETRANGE32:
306 temp = MAKELONG(infoPtr->MinVal, infoPtr->MaxVal);
307 if((infoPtr->MinVal != (INT)wParam) ||
308 (infoPtr->MaxVal != (INT)lParam)) {
309 infoPtr->MinVal = (INT)wParam;
310 infoPtr->MaxVal = (INT)lParam;
311 if(infoPtr->MaxVal <= infoPtr->MinVal)
312 infoPtr->MaxVal = infoPtr->MinVal+1;
313 PROGRESS_CoercePos(hwnd);
314 PROGRESS_Refresh (hwnd);
316 return temp;
318 case PBM_GETRANGE:
319 if (lParam){
320 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
321 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
323 return (wParam) ? infoPtr->MinVal : infoPtr->MaxVal;
325 case PBM_GETPOS:
326 if (wParam || lParam)
327 UNKNOWN_PARAM(PBM_STEPIT, wParam, lParam);
328 return (infoPtr->CurVal);
330 case PBM_SETBARCOLOR:
331 if (wParam)
332 UNKNOWN_PARAM(PBM_SETBARCOLOR, wParam, lParam);
333 infoPtr->ColorBar = (COLORREF)lParam;
334 PROGRESS_Refresh (hwnd);
335 break;
337 case PBM_SETBKCOLOR:
338 if (wParam)
339 UNKNOWN_PARAM(PBM_SETBKCOLOR, wParam, lParam);
340 infoPtr->ColorBk = (COLORREF)lParam;
341 PROGRESS_Refresh (hwnd);
342 break;
344 default:
345 if (message >= WM_USER)
346 ERR("unknown msg %04x wp=%04x lp=%08lx\n",
347 message, wParam, lParam );
348 return DefWindowProcA( hwnd, message, wParam, lParam );
351 return 0;
355 /***********************************************************************
356 * PROGRESS_Register [Internal]
358 * Registers the progress bar window class.
361 VOID
362 PROGRESS_Register (void)
364 WNDCLASSA wndClass;
366 ZeroMemory (&wndClass, sizeof( WNDCLASSA));
367 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
368 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
369 wndClass.cbClsExtra = 0;
370 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
371 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
372 wndClass.lpszClassName = PROGRESS_CLASSA;
374 RegisterClassA (&wndClass);
378 /***********************************************************************
379 * PROGRESS_Unregister [Internal]
381 * Unregisters the progress bar window class.
384 VOID
385 PROGRESS_Unregister (void)
387 UnregisterClassA (PROGRESS_CLASSA, (HINSTANCE)NULL);