Source code for Windows Progress Bar Control and test program; documentation at http://www.alumni.caltech.edu/~pje/progress.html Philip J. Erdelsky =============================== PROGRESS.CPP =============================== // Windows Progress Bar Control #include #include "progress.h" LRESULT CALLBACK ProgressBarProc(HWND, UINT, WPARAM, LPARAM); /*----------------------------------------------------------------------------- This function registers the PROGRESSBAR class. It is called automatically when the program starts up. The external variables _hPrev and _hInstance duplicate the arguments hPrevInstance and hInstance, which are passed to WinMain(). If the startup code does not supply these external variables, you must pass the arguments to this function and call it explicitly before invoking any PROGRESSBAR control. -----------------------------------------------------------------------------*/ extern HINSTANCE _hInstance; #ifndef WIN32 extern HINSTANCE _hPrev; #endif static void register_progress_bar(void) { #ifndef WIN32 if (!_hPrev) #endif { WNDCLASS w; w.cbClsExtra = 0; w.cbWndExtra = 4*sizeof(WORD); #ifdef WIN32 w.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); #else w.hbrBackground = (HBRUSH) COLOR_WINDOW + 1; #endif w.hCursor = LoadCursor(NULL, IDC_ARROW); w.hIcon = NULL; w.hInstance = _hInstance; w.lpfnWndProc = ProgressBarProc; w.lpszClassName = "PROGRESSBAR"; w.lpszMenuName = NULL; w.style = 0; RegisterClass(&w); } } #pragma startup register_progress_bar #ifdef WIN32 inline void MoveTo(HDC dc, int x, int y) { MoveToEx(dc, x, y, NULL); } #define GetWindowHandle GetWindowLong #define SetWindowHandle SetWindowLong #define GWH_HINSTANCE GWL_HINSTANCE #define HANDLE_WORD DWORD inline void PostClickedMessage(HWND handle) { PostMessage(GetParent(handle), WM_COMMAND, MAKELONG((WORD) GetMenu(handle), BN_CLICKED), (LPARAM) handle); } #else #define GetWindowHandle GetWindowWord #define SetWindowHandle SetWindowWord #define GWH_HINSTANCE GWW_HINSTANCE #define HANDLE_WORD WORD inline void PostClickedMessage(HWND handle) { PostMessage(GetParent(handle), WM_COMMAND, GetMenu(handle), MAKELONG(handle, BN_CLICKED)); } #endif /*----------------------------------------------------------------------------- This function receives all messages directed to the control. -----------------------------------------------------------------------------*/ long far pascal _export ProgressBarProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam) { WORD height = GetWindowWord(handle, 0); WORD width = GetWindowWord(handle, 2); WORD completed = GetWindowWord(handle, 4); WORD total = GetWindowWord(handle, 6); switch (message) { case WM_CREATE: { SetWindowWord(handle, 0, ((CREATESTRUCT far *) lParam)->cy); // height SetWindowWord(handle, 2, ((CREATESTRUCT far *) lParam)->cx); // width SetWindowWord(handle, 6, 100); // default value of total return 0; } case WM_PAINT: { PAINTSTRUCT paint; HDC dc = BeginPaint(handle, &paint); HPEN pen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWTEXT)); HPEN old_pen = SelectObject(dc, pen); HBRUSH brush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)); HBRUSH old_brush = SelectObject(dc, brush); RECT r; char text[5]; // draw border Rectangle(dc, 0, 0, width-1, height-1); // display completion percentage SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor(dc, GetSysColor(COLOR_WINDOW)); r.left = r.top = 1; r.bottom = height - 2; r.right = width - 2; wsprintf(text, "%d%%", (100L * (DWORD) completed) / (DWORD) total); DrawText(dc, text, lstrlen(text), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE); // invert progress portion r.right = 1 + ((DWORD) (width - 3) * (DWORD) completed) / (DWORD) total; if (r.right > r.left) InvertRect(dc, &r); SelectObject(dc, old_pen); DeleteObject(pen); SelectObject(dc, old_brush); DeleteObject(brush); EndPaint(handle, &paint); return 0; } case PB_SETCOMPLETED: { RECT r; r.top = 1; r.bottom = height - 2; SetWindowWord(handle, 4, wParam); // completed if ((100L * (DWORD) wParam) / (DWORD) total != (100L * (DWORD) completed) / (DWORD) total) { HDC dc = GetDC(handle); #ifdef WIN32 SIZE size; GetTextExtentPoint32(dc, "100%", 4, &size); unsigned text_width = size.cx; #else unsigned text_width = (WORD) GetTextExtent(dc, "100%", 4); #endif r.left = 1 + (width - 2) / 2 - (text_width + 1) / 2; r.right = 1 + (width - 2) / 2 + (text_width + 1) / 2; InvalidateRect(handle, &r, TRUE); ReleaseDC(handle, dc); } r.left = 1 + ((DWORD) (width - 3) * (DWORD) completed) / (DWORD) total; r.right = 1 + ((DWORD) (width - 3) * (DWORD) wParam) / (DWORD) total; if (r.left != r.right) { if (r.left > r.right) { int x = r.left; r.left = r.right; r.right = x; } InvalidateRect(handle, &r, TRUE); } return 0; } case PB_GETCOMPLETED: return completed; case PB_SETTOTAL: SetWindowWord(handle, 6, wParam); // total SetWindowWord(handle, 4, 0); // completed InvalidateRect(handle, NULL, TRUE); return 0; case PB_GETTOTAL: return total; } return DefWindowProc(handle, message, wParam, lParam); } =============================== PROGRESS.H =============================== #define PB_GETCOMPLETED (WM_USER+0) #define PB_SETCOMPLETED (WM_USER+1) #define PB_GETTOTAL (WM_USER+2) #define PB_SETTOTAL (WM_USER+3) =============================== PROGTEST.CPP =============================== // Windows Progress Bar Control Test Program #include #include "progress.h" #include "progtest.h" extern "C" { long far pascal _export WndProc(HWND, UINT, WORD, LONG); int pascal WinMain(HINSTANCE, HINSTANCE, LPSTR, int); } const TOTAL = 500; long far pascal _export WndProc(HWND hwnd, UINT message, WORD wParam, LONG lParam) { switch (message) { case WM_CREATE: return 0; case WM_COMMAND: switch (wParam) { case LOWER: { int n = SendDlgItemMessage(hwnd, PROGRESSBAR, PB_GETCOMPLETED, 0, 0L); n = n - 1; if (n < 0) n = TOTAL; SendDlgItemMessage(hwnd, PROGRESSBAR, PB_SETCOMPLETED, n, 0L); return 0; } case HIGHER: { int n = SendDlgItemMessage(hwnd, PROGRESSBAR, PB_GETCOMPLETED, 0, 0L); n = n + 1; if (n > TOTAL) n = 0; SendDlgItemMessage(hwnd, PROGRESSBAR, PB_SETCOMPLETED, n, 0L); return 0; } } break; case WM_CLOSE: DestroyWindow(hwnd); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefDlgProc (hwnd, message, wParam, lParam); } #pragma argsused int pascal WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { HWND hwnd; MSG msg; if (!hPrevInstance) { WNDCLASS wndclass; wndclass.style = 0; wndclass.lpfnWndProc = (WNDPROC) WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = DLGWINDOWEXTRA; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "PROGRESSTEST"; RegisterClass (&wndclass); } hwnd = CreateDialog(hInstance, "PROGRESSTEST", 0, NULL); SendDlgItemMessage(hwnd, PROGRESSBAR, PB_SETTOTAL, TOTAL, 0L); ShowWindow(hwnd, nCmdShow == SW_SHOWMAXIMIZED ? SW_SHOW : nCmdShow); UpdateWindow(hwnd); while (GetMessage(&msg, NULL, 0, 0)) if (!IsDialogMessage (hwnd, &msg)) DispatchMessage (&msg); return msg.wParam; } =============================== PROGTEST.H =============================== #define PROGRESSBAR 101 #define LOWER 102 #define HIGHER 103 =============================== PROGTEST.RC =============================== #include "progtest.h" PROGRESSTEST DIALOG 6, 15, 161, 127 STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CLASS "PROGRESSTEST" CAPTION "Progress Bar Test" FONT 8, "MS Sans Serif" { PUSHBUTTON "lower", LOWER, 12, 84, 50, 14 CONTROL "", PROGRESSBAR, "PROGRESSBAR", 0 | WS_CHILD | WS_VISIBLE, 9, 18, 144, 14 PUSHBUTTON "higher", HIGHER, 96, 84, 50, 14 }