//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: progress.cpp // //-------------------------------------------------------------------------- // progress.cpp : implementation file // #include #pragma hdrstop #include "clibres.h" #include "progress.h" // defines #ifdef _DEBUG //#define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif enum MYDIALOGBEHAVIORENUM { enumPERCENTCOMPLETEBEHAVIOR = 0, enumPROGRESSBARWITHTIMEOUT, }; typedef struct _PROGRESSPROC_LPARAM { HINSTANCE hInstance; HWND hwndParent; UINT iRscJobDescription; MYDIALOGBEHAVIORENUM enumWhichBehavior; DWORD dwTickerUpperRange; DBBACKUPPROGRESS* pdbp; } PROGRESSPROC_LPARAM, *PPROGRESSPROC_LPARAM; static BOOL s_fDisableProgressDialogs = 0; static BOOL s_fIKnow = 0; BOOL FICanShowDialogs() { if (s_fIKnow != TRUE) { s_fIKnow = TRUE; DWORD dwVal; if (S_OK == myGetCertRegDWValue( NULL, NULL, NULL, L"DisableProgress", &dwVal)) { s_fDisableProgressDialogs = (dwVal != 0); } } return ! s_fDisableProgressDialogs; } //////////////////////////////////////////////////////////////////////////////// // show a progress dialog int g_iTimeoutTicks = 0; BOOL g_fUseTimer; INT_PTR CALLBACK dlgProcProgress( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { PPROGRESSPROC_LPARAM pLParam = NULL; switch(uMsg) { case WM_INITDIALOG: { HWND hwndProgressBar; pLParam = (PPROGRESSPROC_LPARAM)lParam; SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (ULONG_PTR)pLParam); hwndProgressBar = GetDlgItem(hwndDlg, IDD_PROGRESS_BAR); { RECT rcParent, rcDlg, rcScreenArea; GetWindowRect(pLParam->hwndParent, &rcParent); GetWindowRect(hwndDlg, &rcDlg); SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcScreenArea, NULL); // calc centers int xLeft = (rcParent.left + rcParent.right) / 2 - (rcDlg.right - rcDlg.left) / 2; int yTop = (rcParent.top + rcParent.bottom) / 2 - (rcDlg.bottom - rcDlg.top) / 2; // careful: if the dialog is outside the screen, move it inside if (xLeft < rcScreenArea.left) xLeft = rcScreenArea.left; else if (xLeft + (rcDlg.right - rcDlg.left) > rcScreenArea.right) xLeft = rcScreenArea.right - (rcDlg.right - rcDlg.left); if (yTop < rcScreenArea.top) yTop = rcScreenArea.top; else if (yTop + (rcDlg.bottom - rcDlg.top) > rcScreenArea.bottom) yTop = rcScreenArea.bottom - (rcDlg.bottom - rcDlg.top); // map screen coordinates to child coordinates SetWindowPos(hwndDlg, HWND_TOPMOST, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } { DWORD dwStyle; dwStyle = GetWindowLong(hwndProgressBar, GWL_STYLE); SetWindowLong(hwndProgressBar, GWL_STYLE, (dwStyle | PBS_SMOOTH)); } // Set the range and increment of the progress bar. if (pLParam->enumWhichBehavior == enumPROGRESSBARWITHTIMEOUT) { SendMessage(hwndProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, pLParam->dwTickerUpperRange)); SendMessage(hwndProgressBar, PBM_SETSTEP, (WPARAM) 1, 0); } else { SendMessage(hwndProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 300)); } SendMessage(hwndProgressBar, PBM_SETPOS, (WPARAM)0, 0); // set job description if specified if (pLParam->iRscJobDescription != 0) { WCHAR szJobDesc[MAX_PATH]; if (0 != LoadString( pLParam->hInstance, pLParam->iRscJobDescription, szJobDesc, MAX_PATH)) SetDlgItemText(hwndDlg, IDC_JOB_DESCRIPTION, szJobDesc); } return 1; } case WM_DESTROY: { pLParam = (PPROGRESSPROC_LPARAM)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); if (NULL == pLParam) break; SetForegroundWindow(pLParam->hwndParent); LocalFree(pLParam); pLParam = NULL; SetWindowLongPtr(hwndDlg, GWLP_USERDATA, NULL); } case PBM_STEPIT: { pLParam = (PPROGRESSPROC_LPARAM)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); if (NULL == pLParam) break; HWND hwndProgressBar = GetDlgItem(hwndDlg, IDD_PROGRESS_BAR); if (pLParam->enumWhichBehavior == enumPROGRESSBARWITHTIMEOUT) SendMessage(hwndProgressBar, PBM_STEPIT, 0, 0); else { DWORD wProgress = pLParam->pdbp->dwDBPercentComplete + pLParam->pdbp->dwLogPercentComplete + pLParam->pdbp->dwTruncateLogPercentComplete ; DWORD wTop = (DWORD)SendMessage(hwndProgressBar, PBM_GETRANGE, FALSE, NULL); if (wProgress == wTop) { SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, S_FALSE); // we're done! return TRUE; } else SendMessage(hwndProgressBar, PBM_SETPOS, wProgress, 0); // keep incrementing } break; } case PBM_SETPOS: { HWND hwndProgressBar = GetDlgItem(hwndDlg, IDD_PROGRESS_BAR); LRESULT wTop = SendMessage(hwndProgressBar, PBM_GETRANGE, FALSE, NULL); // if we're not yet at the top make it so if (wTop != SendMessage(hwndProgressBar, PBM_GETPOS, 0, 0)) { SendMessage(hwndProgressBar, PBM_SETPOS, (WPARAM)wTop, 0); Sleep(400); } } default: break; } return 0; } #define PROGRESS_TICKS_PER_SEC 3 DWORD WINAPI StartTimerThread( LPVOID lpParameter ) { if (FICanShowDialogs()) { PPROGRESSPROC_LPARAM psParam = (PPROGRESSPROC_LPARAM)lpParameter; HWND hwndProgressDlg = CreateDialogParam( psParam->hInstance, MAKEINTRESOURCE(IDD_PROGRESS_BOX), NULL, dlgProcProgress, (LPARAM)lpParameter); if (NULL == hwndProgressDlg) return 0; ShowWindow(hwndProgressDlg, SW_SHOW); UpdateWindow(hwndProgressDlg); // if not timer based, go forever // if timer based, go while timersec is + while ((!g_fUseTimer) || (g_iTimeoutTicks-- > 0)) { SendMessage(hwndProgressDlg, PBM_STEPIT, 0, 0); UpdateWindow(hwndProgressDlg); Sleep(1000/PROGRESS_TICKS_PER_SEC); } // send "fill the indicator" SendMessage(hwndProgressDlg, PBM_SETPOS, 0, 0); DestroyWindow(hwndProgressDlg); } return 0; } // callable APIs: Start/End ProgressDlg BOOL FProgressDlgRunning() { return (!g_fUseTimer || (g_iTimeoutTicks > 0)); } HANDLE StartProgressDlg( HINSTANCE hInstance, HWND hwndParent, DWORD dwTickerSeconds, DWORD dwTimeoutSeconds, UINT iRscJobDescription) { HANDLE hProgressThread = NULL; DWORD dwThread; PPROGRESSPROC_LPARAM psParam = NULL; INITCOMMONCONTROLSEX sCommCtrl; sCommCtrl.dwSize = sizeof(sCommCtrl); sCommCtrl.dwICC = ICC_PROGRESS_CLASS; if (!InitCommonControlsEx(&sCommCtrl)) goto Ret; g_fUseTimer = dwTimeoutSeconds != 0; g_iTimeoutTicks = (dwTimeoutSeconds * PROGRESS_TICKS_PER_SEC); // dialog frees this psParam = (PPROGRESSPROC_LPARAM)LocalAlloc(LMEM_FIXED, sizeof(PROGRESSPROC_LPARAM)); if (psParam == NULL) goto Ret; psParam->hInstance = hInstance; psParam->hwndParent = hwndParent; psParam->enumWhichBehavior = enumPROGRESSBARWITHTIMEOUT; psParam->dwTickerUpperRange = dwTickerSeconds * PROGRESS_TICKS_PER_SEC; psParam->iRscJobDescription = iRscJobDescription; psParam->pdbp = NULL; hProgressThread = CreateThread( NULL, 0, StartTimerThread, (void*)psParam, 0, &dwThread); Ret: if (NULL == hProgressThread) LocalFree(psParam); return hProgressThread; } void EndProgressDlg(HANDLE hProgressThread) { // end countdown immediately g_iTimeoutTicks = 0; if (!g_fUseTimer) { // make the controlling thread suddenly aware of the timer g_fUseTimer = TRUE; } // don't return until we're certain the progress dlg is gone while(TRUE) { DWORD dwExitCode; // break on error if (!GetExitCodeThread(hProgressThread, &dwExitCode) ) break; // continue until goes away if (STILL_ACTIVE != dwExitCode) break; Sleep(100); } CloseHandle(hProgressThread); } /////////////////////////////////////////////////////// // %age complete progress indicator DWORD WINAPI StartPercentCompleteThread( LPVOID lpParameter ) { if (FICanShowDialogs()) { PPROGRESSPROC_LPARAM psParam = (PPROGRESSPROC_LPARAM)lpParameter; HWND hwndProgressDlg = CreateDialogParam( psParam->hInstance, MAKEINTRESOURCE(IDD_PROGRESS_BOX), NULL, dlgProcProgress, (LPARAM)lpParameter); if (NULL == hwndProgressDlg) {GetLastError(); return 0;} ShowWindow(hwndProgressDlg, SW_SHOW); Sleep(0); while (TRUE) { if (ERROR_SUCCESS != SendMessage(hwndProgressDlg, PBM_STEPIT, 0, 0)) break; UpdateWindow(hwndProgressDlg); Sleep(0); Sleep(1000/PROGRESS_TICKS_PER_SEC); } // send "fill the indicator" SendMessage(hwndProgressDlg, PBM_SETPOS, 0, 0); DestroyWindow(hwndProgressDlg); } return 0; } HANDLE StartPercentCompleteDlg( HINSTANCE hInstance, HWND hwndParent, UINT iRscJobDescription, DBBACKUPPROGRESS *pdbp) { HANDLE hProgressThread = NULL; DWORD dwThread; PPROGRESSPROC_LPARAM psParam = NULL; g_fUseTimer = FALSE; g_iTimeoutTicks = 0; // no timeout INITCOMMONCONTROLSEX sCommCtrl; sCommCtrl.dwSize = sizeof(sCommCtrl); sCommCtrl.dwICC = ICC_PROGRESS_CLASS; if (!InitCommonControlsEx(&sCommCtrl)) goto Ret; // dialog frees this psParam = (PPROGRESSPROC_LPARAM)LocalAlloc(LMEM_FIXED, sizeof(PROGRESSPROC_LPARAM)); if (psParam == NULL) goto Ret; psParam->hInstance = hInstance; psParam->hwndParent = hwndParent; psParam->enumWhichBehavior = enumPERCENTCOMPLETEBEHAVIOR; psParam->dwTickerUpperRange = 300; psParam->iRscJobDescription = iRscJobDescription; psParam->pdbp = pdbp; hProgressThread = CreateThread( NULL, 0, StartPercentCompleteThread, (void*)psParam, 0, &dwThread); Ret: if (NULL == hProgressThread) LocalFree(psParam); return hProgressThread; } void EndPercentCompleteDlg(HANDLE hProgressThread) { // don't return until we're certain the progress dlg is gone while(TRUE) { DWORD dwExitCode; // break on error if (!GetExitCodeThread(hProgressThread, &dwExitCode) ) break; // continue until goes away if (STILL_ACTIVE != dwExitCode) break; Sleep(100); } CloseHandle(hProgressThread); }