set svn:eol-style to native
[reactos.git] / reactos / lib / comctl32 / progress.c
1 /*
2 * Progress control
3 *
4 * Copyright 1997, 2002 Dimitrie O. Paun
5 * Copyright 1998, 1999 Eric Kohl
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * NOTE
22 *
23 * This code was audited for completeness against the documented features
24 * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun.
25 *
26 * Unless otherwise noted, we believe this code to be complete, as per
27 * the specification mentioned above.
28 * If you discover missing features, or bugs, please note them below.
29 *
30 */
31
32 #include <stdarg.h>
33 #include <string.h>
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "winuser.h"
38 #include "winnls.h"
39 #include "commctrl.h"
40 #include "comctl32.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(progress);
44
45 typedef struct
46 {
47 HWND Self; /* The window handle for this control */
48 INT CurVal; /* Current progress value */
49 INT MinVal; /* Minimum progress value */
50 INT MaxVal; /* Maximum progress value */
51 INT Step; /* Step to use on PMB_STEPIT */
52 INT MarqueePos; /* Marquee animation position */
53 BOOL Marquee; /* Whether the marquee animation is enabled */
54 COLORREF ColorBar; /* Bar color */
55 COLORREF ColorBk; /* Background color */
56 HFONT Font; /* Handle to font (not unused) */
57 } PROGRESS_INFO;
58
59 /* Control configuration constants */
60
61 #define LED_GAP 2
62 #define MARQUEE_LEDS 5
63 #define ID_MARQUEE_TIMER 1
64
65 /***********************************************************************
66 * PROGRESS_Invalidate
67 *
68 * Invalide the range between old and new pos.
69 */
70 static void PROGRESS_Invalidate( PROGRESS_INFO *infoPtr, INT old, INT new )
71 {
72 LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE);
73 RECT rect;
74 int oldPos, newPos, ledWidth;
75
76 GetClientRect (infoPtr->Self, &rect);
77 InflateRect(&rect, -1, -1);
78
79 if (style & PBS_VERTICAL)
80 {
81 oldPos = rect.bottom - MulDiv (old - infoPtr->MinVal, rect.bottom - rect.top,
82 infoPtr->MaxVal - infoPtr->MinVal);
83 newPos = rect.bottom - MulDiv (new - infoPtr->MinVal, rect.bottom - rect.top,
84 infoPtr->MaxVal - infoPtr->MinVal);
85 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
86 rect.top = min( oldPos, newPos );
87 rect.bottom = max( oldPos, newPos );
88 if (!(style & PBS_SMOOTH)) rect.top -= ledWidth;
89 InvalidateRect( infoPtr->Self, &rect, oldPos < newPos );
90 }
91 else
92 {
93 oldPos = rect.left + MulDiv (old - infoPtr->MinVal, rect.right - rect.left,
94 infoPtr->MaxVal - infoPtr->MinVal);
95 newPos = rect.left + MulDiv (new - infoPtr->MinVal, rect.right - rect.left,
96 infoPtr->MaxVal - infoPtr->MinVal);
97 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
98 rect.left = min( oldPos, newPos );
99 rect.right = max( oldPos, newPos );
100 if (!(style & PBS_SMOOTH)) rect.right += ledWidth;
101 InvalidateRect( infoPtr->Self, &rect, oldPos > newPos );
102 }
103 }
104
105
106 /***********************************************************************
107 * PROGRESS_Draw
108 * Draws the progress bar.
109 */
110 static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc)
111 {
112 HBRUSH hbrBar, hbrBk;
113 int rightBar, rightMost, ledWidth;
114 RECT rect;
115 DWORD dwStyle;
116
117 TRACE("(infoPtr=%p, hdc=%p)\n", infoPtr, hdc);
118
119 /* get the required bar brush */
120 if (infoPtr->ColorBar == CLR_DEFAULT)
121 hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
122 else
123 hbrBar = CreateSolidBrush (infoPtr->ColorBar);
124
125 if (infoPtr->ColorBk == CLR_DEFAULT)
126 hbrBk = GetSysColorBrush(COLOR_3DFACE);
127 else
128 hbrBk = CreateSolidBrush(infoPtr->ColorBk);
129
130 /* get client rectangle */
131 GetClientRect (infoPtr->Self, &rect);
132 FrameRect( hdc, &rect, hbrBk );
133 InflateRect(&rect, -1, -1);
134
135 /* get the window style */
136 dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE);
137
138 /* compute extent of progress bar */
139 if (dwStyle & PBS_VERTICAL) {
140 rightBar = rect.bottom -
141 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
142 rect.bottom - rect.top,
143 infoPtr->MaxVal - infoPtr->MinVal);
144 ledWidth = MulDiv (rect.right - rect.left, 2, 3);
145 rightMost = rect.top;
146 } else {
147 rightBar = rect.left +
148 MulDiv (infoPtr->CurVal - infoPtr->MinVal,
149 rect.right - rect.left,
150 infoPtr->MaxVal - infoPtr->MinVal);
151 ledWidth = MulDiv (rect.bottom - rect.top, 2, 3);
152 rightMost = rect.right;
153 }
154
155 /* now draw the bar */
156 if (dwStyle & PBS_SMOOTH)
157 {
158 if (dwStyle & PBS_VERTICAL)
159 {
160 if (dwStyle & PBS_MARQUEE)
161 {
162 INT old_top, old_bottom, ledMStart, leds;
163 old_top = rect.top;
164 old_bottom = rect.bottom;
165
166 leds = rect.bottom - rect.top;
167 ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds;
168
169 if(ledMStart > 0)
170 {
171 rect.top = max(rect.bottom - ledMStart, old_top);
172 FillRect(hdc, &rect, hbrBar);
173 rect.bottom = rect.top;
174 }
175 if(infoPtr->MarqueePos > 0)
176 {
177 rect.top = max(old_bottom - infoPtr->MarqueePos, old_top);
178 FillRect(hdc, &rect, hbrBk);
179 rect.bottom = rect.top;
180 }
181 if(rect.top >= old_top)
182 {
183 rect.top = max(rect.bottom - MARQUEE_LEDS, old_top);
184 FillRect(hdc, &rect, hbrBar);
185 rect.bottom = rect.top;
186 }
187 if(rect.top >= old_top)
188 {
189 rect.top = old_top;
190 FillRect(hdc, &rect, hbrBk);
191 }
192 }
193 else
194 {
195 INT old_top = rect.top;
196 rect.top = rightBar;
197 FillRect(hdc, &rect, hbrBar);
198 rect.bottom = rect.top;
199 rect.top = old_top;
200 FillRect(hdc, &rect, hbrBk);
201 }
202 }
203 else
204 {
205 if (dwStyle & PBS_MARQUEE)
206 {
207 INT old_left, old_right, ledMStart, leds;
208 old_left = rect.left;
209 old_right = rect.right;
210
211 leds = rect.right - rect.left;
212 ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds;
213 rect.right = rect.left;
214
215 if(ledMStart > 0)
216 {
217 rect.right = min(rect.left + ledMStart, old_right);
218 FillRect(hdc, &rect, hbrBar);
219 rect.left = rect.right;
220 }
221 if(infoPtr->MarqueePos > 0)
222 {
223 rect.right = min(old_left + infoPtr->MarqueePos, old_right);
224 FillRect(hdc, &rect, hbrBk);
225 rect.left = rect.right;
226 }
227 if(rect.right < old_right)
228 {
229 rect.right = min(rect.left + MARQUEE_LEDS, old_right);
230 FillRect(hdc, &rect, hbrBar);
231 rect.left = rect.right;
232 }
233 if(rect.right < old_right)
234 {
235 rect.right = old_right;
236 FillRect(hdc, &rect, hbrBk);
237 }
238 }
239 else
240 {
241 INT old_right = rect.right;
242 rect.right = rightBar;
243 FillRect(hdc, &rect, hbrBar);
244 rect.left = rect.right;
245 rect.right = old_right;
246 FillRect(hdc, &rect, hbrBk);
247 }
248 }
249 } else {
250 if (dwStyle & PBS_VERTICAL) {
251 if (dwStyle & PBS_MARQUEE)
252 {
253 INT i, old_top, old_bottom, ledMStart, leds;
254 old_top = rect.top;
255 old_bottom = rect.bottom;
256
257 leds = ((rect.bottom - rect.top) + (ledWidth + LED_GAP) - 1) / (ledWidth + LED_GAP);
258 ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds;
259
260 while(ledMStart > 0)
261 {
262 rect.top = max(rect.bottom - ledWidth, old_top);
263 FillRect(hdc, &rect, hbrBar);
264 rect.bottom = rect.top;
265 rect.top -= LED_GAP;
266 if (rect.top <= old_top) break;
267 FillRect(hdc, &rect, hbrBk);
268 rect.bottom = rect.top;
269 ledMStart--;
270 }
271 if(infoPtr->MarqueePos > 0)
272 {
273 rect.top = max(old_bottom - (infoPtr->MarqueePos * (ledWidth + LED_GAP)), old_top);
274 FillRect(hdc, &rect, hbrBk);
275 rect.bottom = rect.top;
276 }
277 for(i = 0; i < MARQUEE_LEDS && rect.top >= old_top; i++)
278 {
279 rect.top = max(rect.bottom - ledWidth, old_top);
280 FillRect(hdc, &rect, hbrBar);
281 rect.bottom = rect.top;
282 rect.top -= LED_GAP;
283 if (rect.top <= old_top) break;
284 FillRect(hdc, &rect, hbrBk);
285 rect.bottom = rect.top;
286 }
287 if(rect.top >= old_top)
288 {
289 rect.top = old_top;
290 FillRect(hdc, &rect, hbrBk);
291 }
292 }
293 else
294 {
295 while(rect.bottom > rightBar) {
296 rect.top = rect.bottom - ledWidth;
297 if (rect.top < rightMost)
298 rect.top = rightMost;
299 FillRect(hdc, &rect, hbrBar);
300 rect.bottom = rect.top;
301 rect.top -= LED_GAP;
302 if (rect.top <= rightBar) break;
303 FillRect(hdc, &rect, hbrBk);
304 rect.bottom = rect.top;
305 }
306 }
307 rect.top = rightMost;
308 FillRect(hdc, &rect, hbrBk);
309 } else {
310 if (dwStyle & PBS_MARQUEE)
311 {
312 INT i, old_right, old_left, ledMStart, leds;
313 old_left = rect.left;
314 old_right = rect.right;
315
316 leds = ((rect.right - rect.left) + ledWidth - 1) / (ledWidth + LED_GAP);
317 ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds;
318 rect.right = rect.left;
319
320 while(ledMStart > 0)
321 {
322 rect.right = min(rect.left + ledWidth, old_right);
323 FillRect(hdc, &rect, hbrBar);
324 rect.left = rect.right;
325 rect.right += LED_GAP;
326 if (rect.right > old_right) break;
327 FillRect(hdc, &rect, hbrBk);
328 rect.left = rect.right;
329 ledMStart--;
330 }
331 if(infoPtr->MarqueePos > 0)
332 {
333 rect.right = min(old_left + (infoPtr->MarqueePos * (ledWidth + LED_GAP)), old_right);
334 FillRect(hdc, &rect, hbrBk);
335 rect.left = rect.right;
336 }
337 for(i = 0; i < MARQUEE_LEDS && rect.right < old_right; i++)
338 {
339 rect.right = min(rect.left + ledWidth, old_right);
340 FillRect(hdc, &rect, hbrBar);
341 rect.left = rect.right;
342 rect.right += LED_GAP;
343 if (rect.right > old_right) break;
344 FillRect(hdc, &rect, hbrBk);
345 rect.left = rect.right;
346 }
347 if(rect.right < old_right)
348 {
349 rect.right = old_right;
350 FillRect(hdc, &rect, hbrBk);
351 }
352 }
353 else
354 {
355 while(rect.left < rightBar) {
356 rect.right = rect.left + ledWidth;
357 if (rect.right > rightMost)
358 rect.right = rightMost;
359 FillRect(hdc, &rect, hbrBar);
360 rect.left = rect.right;
361 rect.right += LED_GAP;
362 if (rect.right >= rightBar) break;
363 FillRect(hdc, &rect, hbrBk);
364 rect.left = rect.right;
365 }
366 rect.right = rightMost;
367 FillRect(hdc, &rect, hbrBk);
368 }
369 }
370 }
371
372 /* delete bar brush */
373 if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (hbrBar);
374 if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (hbrBk);
375
376 return 0;
377 }
378
379
380 /***********************************************************************
381 * PROGRESS_Paint
382 * Draw the progress bar. The background need not be erased.
383 * If dc!=0, it draws on it
384 */
385 static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc)
386 {
387 PAINTSTRUCT ps;
388 if (hdc) return PROGRESS_Draw (infoPtr, hdc);
389 hdc = BeginPaint (infoPtr->Self, &ps);
390 PROGRESS_Draw (infoPtr, hdc);
391 EndPaint (infoPtr->Self, &ps);
392 return 0;
393 }
394
395
396 /***********************************************************************
397 * PROGRESS_Timer
398 * Handle the marquee timer messages
399 */
400 static LRESULT PROGRESS_Timer (PROGRESS_INFO *infoPtr, INT idTimer)
401 {
402 if(idTimer == ID_MARQUEE_TIMER)
403 {
404 LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE);
405 RECT rect;
406 int ledWidth, leds;
407
408 GetClientRect (infoPtr->Self, &rect);
409 InflateRect(&rect, -1, -1);
410
411 if(!(style & PBS_SMOOTH))
412 {
413 int width, height;
414
415 if(style & PBS_VERTICAL)
416 {
417 width = rect.bottom - rect.top;
418 height = rect.right - rect.left;
419 }
420 else
421 {
422 height = rect.bottom - rect.top;
423 width = rect.right - rect.left;
424 }
425 ledWidth = MulDiv (height, 2, 3);
426 leds = (width + ledWidth - 1) / (ledWidth + LED_GAP);
427 }
428 else
429 {
430 ledWidth = 1;
431 if(style & PBS_VERTICAL)
432 {
433 leds = rect.bottom - rect.top;
434 }
435 else
436 {
437 leds = rect.right - rect.left;
438 }
439 }
440
441 /* increment the marquee progress */
442 if(++infoPtr->MarqueePos >= leds)
443 {
444 infoPtr->MarqueePos = 0;
445 }
446
447 InvalidateRect(infoPtr->Self, &rect, TRUE);
448 }
449 return 0;
450 }
451
452
453 /***********************************************************************
454 * PROGRESS_CoercePos
455 * Makes sure the current position (CurVal) is within bounds.
456 */
457 static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr)
458 {
459 if(infoPtr->CurVal < infoPtr->MinVal)
460 infoPtr->CurVal = infoPtr->MinVal;
461 if(infoPtr->CurVal > infoPtr->MaxVal)
462 infoPtr->CurVal = infoPtr->MaxVal;
463 }
464
465
466 /***********************************************************************
467 * PROGRESS_SetFont
468 * Set new Font for progress bar
469 */
470 static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw)
471 {
472 HFONT hOldFont = infoPtr->Font;
473 infoPtr->Font = hFont;
474 /* Since infoPtr->Font is not used, there is no need for repaint */
475 return hOldFont;
476 }
477
478 static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high)
479 {
480 DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal));
481
482 /* if nothing changes, simply return */
483 if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res;
484
485 infoPtr->MinVal = low;
486 infoPtr->MaxVal = high;
487 PROGRESS_CoercePos(infoPtr);
488 InvalidateRect(infoPtr->Self, NULL, TRUE);
489 return res;
490 }
491
492 /***********************************************************************
493 * ProgressWindowProc
494 */
495 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message,
496 WPARAM wParam, LPARAM lParam)
497 {
498 PROGRESS_INFO *infoPtr;
499
500 TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam);
501
502 infoPtr = (PROGRESS_INFO *)GetWindowLongPtrW(hwnd, 0);
503
504 if (!infoPtr && message != WM_CREATE)
505 return DefWindowProcW( hwnd, message, wParam, lParam );
506
507 switch(message) {
508 case WM_CREATE:
509 {
510 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE);
511 dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE);
512 dwExStyle |= WS_EX_STATICEDGE;
513 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle);
514 /* Force recalculation of a non-client area */
515 SetWindowPos(hwnd, 0, 0, 0, 0, 0,
516 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
517
518 /* allocate memory for info struct */
519 infoPtr = (PROGRESS_INFO *)Alloc (sizeof(PROGRESS_INFO));
520 if (!infoPtr) return -1;
521 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
522
523 /* initialize the info struct */
524 infoPtr->Self = hwnd;
525 infoPtr->MinVal = 0;
526 infoPtr->MaxVal = 100;
527 infoPtr->CurVal = 0;
528 infoPtr->Step = 10;
529 infoPtr->MarqueePos = 0;
530 infoPtr->Marquee = FALSE;
531 infoPtr->ColorBar = CLR_DEFAULT;
532 infoPtr->ColorBk = CLR_DEFAULT;
533 infoPtr->Font = 0;
534 TRACE("Progress Ctrl creation, hwnd=%p\n", hwnd);
535 return 0;
536 }
537
538 case WM_DESTROY:
539 TRACE("Progress Ctrl destruction, hwnd=%p\n", hwnd);
540 Free (infoPtr);
541 SetWindowLongPtrW(hwnd, 0, 0);
542 return 0;
543
544 case WM_GETFONT:
545 return (LRESULT)infoPtr->Font;
546
547 case WM_SETFONT:
548 return (LRESULT)PROGRESS_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam);
549
550 case WM_PAINT:
551 return PROGRESS_Paint (infoPtr, (HDC)wParam);
552
553 case WM_TIMER:
554 return PROGRESS_Timer (infoPtr, (INT)wParam);
555
556 case PBM_DELTAPOS:
557 {
558 INT oldVal;
559 oldVal = infoPtr->CurVal;
560 if(wParam != 0) {
561 infoPtr->CurVal += (INT)wParam;
562 PROGRESS_CoercePos (infoPtr);
563 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
564 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
565 }
566 return oldVal;
567 }
568
569 case PBM_SETPOS:
570 {
571 UINT oldVal;
572 oldVal = infoPtr->CurVal;
573 if(oldVal != wParam) {
574 infoPtr->CurVal = (INT)wParam;
575 PROGRESS_CoercePos(infoPtr);
576 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
577 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
578 }
579 return oldVal;
580 }
581
582 case PBM_SETRANGE:
583 return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam));
584
585 case PBM_SETSTEP:
586 {
587 INT oldStep;
588 oldStep = infoPtr->Step;
589 infoPtr->Step = (INT)wParam;
590 return oldStep;
591 }
592
593 case PBM_STEPIT:
594 {
595 INT oldVal;
596 oldVal = infoPtr->CurVal;
597 infoPtr->CurVal += infoPtr->Step;
598 if(infoPtr->CurVal > infoPtr->MaxVal)
599 infoPtr->CurVal = infoPtr->MinVal;
600 if(oldVal != infoPtr->CurVal)
601 {
602 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal);
603 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal );
604 }
605 return oldVal;
606 }
607
608 case PBM_SETRANGE32:
609 return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam);
610
611 case PBM_GETRANGE:
612 if (lParam) {
613 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal;
614 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal;
615 }
616 return wParam ? infoPtr->MinVal : infoPtr->MaxVal;
617
618 case PBM_GETPOS:
619 return infoPtr->CurVal;
620
621 case PBM_SETBARCOLOR:
622 infoPtr->ColorBar = (COLORREF)lParam;
623 InvalidateRect(hwnd, NULL, TRUE);
624 return 0;
625
626 case PBM_SETBKCOLOR:
627 infoPtr->ColorBk = (COLORREF)lParam;
628 InvalidateRect(hwnd, NULL, TRUE);
629 return 0;
630
631 case PBM_SETMARQUEE:
632 if(wParam != 0)
633 {
634 infoPtr->Marquee = TRUE;
635 SetTimer(infoPtr->Self, ID_MARQUEE_TIMER, (UINT)lParam, NULL);
636 }
637 else
638 {
639 infoPtr->Marquee = FALSE;
640 KillTimer(infoPtr->Self, ID_MARQUEE_TIMER);
641 }
642 return infoPtr->Marquee;
643
644 default:
645 if ((message >= WM_USER) && (message < WM_APP))
646 ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam );
647 return DefWindowProcW( hwnd, message, wParam, lParam );
648 }
649 }
650
651
652 /***********************************************************************
653 * PROGRESS_Register [Internal]
654 *
655 * Registers the progress bar window class.
656 */
657 void PROGRESS_Register (void)
658 {
659 WNDCLASSW wndClass;
660
661 ZeroMemory (&wndClass, sizeof(wndClass));
662 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
663 wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc;
664 wndClass.cbClsExtra = 0;
665 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *);
666 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW);
667 wndClass.lpszClassName = PROGRESS_CLASSW;
668
669 RegisterClassW (&wndClass);
670 }
671
672
673 /***********************************************************************
674 * PROGRESS_Unregister [Internal]
675 *
676 * Unregisters the progress bar window class.
677 */
678 void PROGRESS_Unregister (void)
679 {
680 UnregisterClassW (PROGRESS_CLASSW, NULL);
681 }