/* * PROJECT: ReactOS Services * LICENSE: GPL - See COPYING in the top level directory * FILE: base/applications/mscutils/servman/progress.c * PURPOSE: Progress dialog box message handler * COPYRIGHT: Copyright 2006-2015 Ged Murphy * */ #include "precomp.h" #include #define PROGRESS_RANGE 20 #define PROGRESS_STEP_MAX 15 typedef struct _PROGRESS_DATA { HWND hDlg; HWND hProgress; LPWSTR ServiceName; ULONG Action; BOOL StopDepends; LPWSTR ServiceList; PVOID Param; } PROGRESS_DATA, *PPROGRESS_DATA; VOID ShowError(DWORD dwLastError) { LPWSTR lpMsg; if (!FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwLastError, LANG_USER_DEFAULT, (LPWSTR)&lpMsg, 0, NULL)) { return; } MessageBoxW(NULL, lpMsg, NULL, MB_OK | MB_ICONERROR); LocalFree(lpMsg); } static VOID ResetProgressDialog(HWND hDlg, LPWSTR ServiceName, ULONG LabelId) { LPWSTR lpProgStr; /* Load the label Id */ if (AllocAndLoadString(&lpProgStr, hInstance, LabelId)) { /* Write it to the dialog */ SendDlgItemMessageW(hDlg, IDC_SERVCON_INFO, WM_SETTEXT, 0, (LPARAM)lpProgStr); LocalFree(lpProgStr); } /* Write the service name to the dialog */ SendDlgItemMessageW(hDlg, IDC_SERVCON_NAME, WM_SETTEXT, 0, (LPARAM)ServiceName); /* Set the progress bar to the start */ SendDlgItemMessageW(hDlg, IDC_SERVCON_PROGRESS, PBM_SETPOS, 0, 0); } unsigned int __stdcall ActionThread(void* Param) { PPROGRESS_DATA ProgressData = (PPROGRESS_DATA)Param; DWORD dwResult; if (ProgressData->Action == ACTION_START) { /* Setup the progress dialog for this action */ ResetProgressDialog(ProgressData->hDlg, ProgressData->ServiceName, IDS_PROGRESS_INFO_START); /* Start the service */ dwResult = DoStartService(ProgressData->ServiceName, ProgressData->hProgress, ProgressData->Param); if (dwResult == ERROR_SUCCESS) { /* We're done, slide the progress bar up to the top */ CompleteProgressBar(ProgressData->hProgress); } else { ShowError(dwResult); } } else if (ProgressData->Action == ACTION_STOP || ProgressData->Action == ACTION_RESTART) { /* Check if there are and dependants to stop */ if (ProgressData->StopDepends && ProgressData->ServiceList) { LPWSTR lpStr = ProgressData->ServiceList; /* Loop through all the services in the list */ for (;;) { /* Break when we hit the double null */ if (*lpStr == L'\0' && *(lpStr + 1) == L'\0') break; /* If this isn't our first time in the loop we'll have been left on a null char */ if (*lpStr == L'\0') lpStr++; ResetProgressDialog(ProgressData->hDlg, lpStr, IDS_PROGRESS_INFO_STOP); /* Stop the requested service */ dwResult = DoStopService(ProgressData->ServiceName, ProgressData->hProgress); if (dwResult == ERROR_SUCCESS) { CompleteProgressBar(ProgressData->hProgress); } else { ShowError(dwResult); } /* Move onto the next string */ while (*lpStr != L'\0') lpStr++; } } ResetProgressDialog(ProgressData->hDlg, ProgressData->ServiceName, IDS_PROGRESS_INFO_STOP); dwResult = DoStopService(ProgressData->ServiceName, ProgressData->hProgress); if (dwResult == ERROR_SUCCESS) { CompleteProgressBar(ProgressData->hProgress); } else { ShowError(dwResult); } /* If this was a restart, we'll need to start the service back up */ if (ProgressData->Action == ACTION_RESTART) { /* Setup the progress dialog for this action */ ResetProgressDialog(ProgressData->hDlg, ProgressData->ServiceName, IDS_PROGRESS_INFO_START); /* Start the service */ dwResult = DoStartService(ProgressData->ServiceName, ProgressData->hProgress, NULL); if (dwResult == ERROR_SUCCESS) { /* We're done, slide the progress bar up to the top */ CompleteProgressBar(ProgressData->hProgress); } else { ShowError(dwResult); } } } else if (ProgressData->Action == ACTION_PAUSE) { /* Setup the progress dialog for this action */ ResetProgressDialog(ProgressData->hDlg, ProgressData->ServiceName, IDS_PROGRESS_INFO_PAUSE); /* Pause the service */ dwResult = DoControlService(ProgressData->ServiceName, ProgressData->hProgress, SERVICE_CONTROL_PAUSE); if (dwResult == ERROR_SUCCESS) { /* We're done, slide the progress bar up to the top */ CompleteProgressBar(ProgressData->hProgress); } else { ShowError(dwResult); } } else if (ProgressData->Action == ACTION_RESUME) { /* Setup the progress dialog for this action */ ResetProgressDialog(ProgressData->hDlg, ProgressData->ServiceName, IDS_PROGRESS_INFO_RESUME); /* resume the service */ dwResult = DoControlService(ProgressData->ServiceName, ProgressData->hProgress, SERVICE_CONTROL_CONTINUE); if (dwResult == ERROR_SUCCESS) { /* We're done, slide the progress bar up to the top */ CompleteProgressBar(ProgressData->hProgress); } else { ShowError(dwResult); } } EndDialog(ProgressData->hDlg, IDOK); _endthreadex(0); return 0; } static BOOL InitProgressDialog(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam) { PPROGRESS_DATA ProgressData = (PPROGRESS_DATA)lParam; HANDLE hThread; ProgressData->hDlg = hDlg; /* Get a handle to the progress bar */ ProgressData->hProgress = GetDlgItem(hDlg, IDC_SERVCON_PROGRESS); if (!ProgressData->hProgress) return FALSE; /* Set the progress bar range */ SendMessageW(ProgressData->hProgress, PBM_SETRANGE, 0, MAKELPARAM(0, PROGRESS_RANGE)); /* Set the progress bar step */ SendMessageW(ProgressData->hProgress, PBM_SETSTEP, (WPARAM)1, 0); /* Create a thread to handle the service control */ hThread = (HANDLE)_beginthreadex(NULL, 0, &ActionThread, ProgressData, 0, NULL); if (!hThread) return FALSE; CloseHandle(hThread); return TRUE; } INT_PTR CALLBACK ProgressDialogProc(HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam) { switch(Message) { case WM_INITDIALOG: { return InitProgressDialog(hDlg, Message, wParam, lParam); } case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: EndDialog(hDlg, wParam); break; } break; default: return FALSE; } return TRUE; } VOID CompleteProgressBar(HANDLE hProgress) { HWND hProgBar = (HWND)hProgress; UINT Pos = 0; /* Get the current position */ Pos = SendMessageW(hProgBar, PBM_GETPOS, 0, 0); /* Loop until we hit the max */ while (Pos <= PROGRESS_RANGE) { /* Increment the progress bar */ SendMessageW(hProgBar, PBM_DELTAPOS, Pos, 0); /* Wait for 15ms to give it a smooth feel */ Sleep(15); Pos++; } } VOID IncrementProgressBar(HANDLE hProgress, UINT Step) { HWND hProgBar = (HWND)hProgress; UINT Position; /* Don't allow the progress to reach to complete*/ Position = SendMessageW(hProgBar, PBM_GETPOS, 0, 0); if (Position < PROGRESS_STEP_MAX) { /* Do we want to increment the default amount? */ if (Step == DEFAULT_STEP) { /* Use the step value we set on create */ SendMessageW(hProgBar, PBM_STEPIT, 0, 0); } else { /* Use the value passed */ SendMessageW(hProgBar, PBM_SETPOS, Step, 0); } } } BOOL RunActionWithProgress(HWND hParent, LPWSTR ServiceName, LPWSTR DisplayName, UINT Action, PVOID Param) { PROGRESS_DATA ProgressData; LPWSTR ServiceList; BOOL StopDepends; INT_PTR Result; StopDepends = FALSE; ServiceList = NULL; /* Check if we'll be stopping the service */ if (Action == ACTION_STOP || Action == ACTION_RESTART) { /* Does the service have any dependent services which need stopping first */ ServiceList = GetListOfServicesToStop(ServiceName); if (ServiceList) { /* Ask the user if they want to stop the dependants */ StopDepends = CreateStopDependsDialog(hParent, ServiceName, DisplayName, ServiceList); /* Exit early if the user decided not to stop the dependants */ if (StopDepends == FALSE) { HeapFree(GetProcessHeap(), 0, ServiceList); return FALSE; } } } ProgressData.hDlg = NULL; ProgressData.ServiceName = ServiceName; ProgressData.Action = Action; ProgressData.StopDepends = StopDepends; ProgressData.ServiceList = ServiceList; ProgressData.Param = Param; Result = DialogBoxParamW(hInstance, MAKEINTRESOURCEW(IDD_DLG_PROGRESS), hParent, ProgressDialogProc, (LPARAM)&ProgressData); if (ServiceList) HeapFree(GetProcessHeap(), 0, ServiceList); return (Result == IDOK); }