/* * PROJECT: ReactOS Utility Manager (Accessibility) * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: Main dialog code file * COPYRIGHT: Copyright 2019 Bișoc George (fraizeraust99 at gmail dot com) * Copyright 2019 Hermes Belusca-Maito */ /* INCLUDES *******************************************************************/ #include "precomp.h" /* GLOBALS ********************************************************************/ UTILMAN_GLOBALS Globals; /* DECLARATIONS ***************************************************************/ UTILMAN_STATE EntriesList[] = { {L"magnify.exe", IDS_MAGNIFIER, L"", FALSE}, {L"osk.exe", IDS_OSK, L"", FALSE} }; /* FUNCTIONS ******************************************************************/ /** * @InitUtilsList * * Initializes the list of accessibility utilities. * * @param[in] bInitGui * Whether we are initializing the UI list (TRUE) or the internal array (FALSE). * * @return * Nothing. */ VOID InitUtilsList(BOOL bInitGui) { UINT i; if (!bInitGui) { // TODO: Load the list dynamically from the registry key // hklm\software\microsoft\windows nt\currentversion\accessibility /* Initialize the resource utility strings only once */ for (i = 0; i < _countof(EntriesList); ++i) { LoadStringW(Globals.hInstance, EntriesList[i].uNameId, EntriesList[i].szResource, _countof(EntriesList[i].szResource)); EntriesList[i].bState = FALSE; } } else { INT iItem; BOOL bIsRunning; WCHAR szFormat[MAX_BUFFER]; /* Reset the listbox */ SendMessageW(Globals.hListDlg, LB_RESETCONTENT, 0, 0); /* Add the utilities in the listbox */ for (i = 0; i < _countof(EntriesList); ++i) { bIsRunning = IsProcessRunning(EntriesList[i].lpProgram); EntriesList[i].bState = bIsRunning; /* Load the string and append the utility's name to the format */ StringCchPrintfW(szFormat, _countof(szFormat), (bIsRunning ? Globals.szRunning : Globals.szNotRunning), EntriesList[i].szResource); /* Add the item in the listbox */ iItem = (INT)SendMessageW(Globals.hListDlg, LB_ADDSTRING, 0, (LPARAM)szFormat); if (iItem != LB_ERR) SendMessageW(Globals.hListDlg, LB_SETITEMDATA, iItem, (LPARAM)&EntriesList[i]); } } } /** * @DlgInitHandler * * Function which processes several operations for WM_INITDIALOG. * * @param[in] hDlg * The handle object of the dialog. * * @return * TRUE to inform the system that WM_INITDIALOG has been processed and * that it should set the keyboard focus to the control. * */ BOOL DlgInitHandler(IN HWND hDlg) { INT PosX, PosY; RECT rc; WCHAR szAboutDlg[MAX_BUFFER]; HMENU hSysMenu; /* Save the dialog handle */ Globals.hMainDlg = hDlg; /* Center the dialog on the screen */ GetWindowRect(hDlg, &rc); PosX = (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2; PosY = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2; SetWindowPos(hDlg, 0, PosX, PosY, 0, 0, SWP_NOZORDER | SWP_NOSIZE); /* Load the icon resource */ Globals.hIcon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_ICON_UTILMAN), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE); /* Set the icon within the dialog's title bar */ if (Globals.hIcon) { SendMessageW(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)Globals.hIcon); } /* Retrieve the system menu and append the "About" menu item onto it */ hSysMenu = GetSystemMenu(hDlg, FALSE); if (hSysMenu != NULL) { if (LoadStringW(Globals.hInstance, IDM_ABOUT, szAboutDlg, _countof(szAboutDlg))) { AppendMenuW(hSysMenu, MF_SEPARATOR, 0, NULL); AppendMenuW(hSysMenu, MF_STRING, IDM_ABOUT, szAboutDlg); } } /* Get the dialog items, specifically the dialog list box, the Start and Stop buttons */ Globals.hListDlg = GetDlgItem(hDlg, IDC_LISTBOX); Globals.hDlgCtlStart = GetDlgItem(hDlg, IDC_START); Globals.hDlgCtlStop = GetDlgItem(hDlg, IDC_STOP); /* Initialize the GUI listbox */ InitUtilsList(TRUE); /* Set the selection to the first item */ Globals.iSelectedIndex = 0; /* Refresh the list */ ListBoxRefreshContents(); /* Create a timer, we'll use it to control the state of our items in the listbox */ Globals.iTimer = SetTimer(hDlg, 0, 400, NULL); return TRUE; } /** * @GroupBoxUpdateTitle * * Updates the title of the groupbox. * * @return * Nothing. * */ VOID GroupBoxUpdateTitle(VOID) { WCHAR szFormat[MAX_BUFFER]; /* Format the string with the utility's name and set it to the listbox's title */ StringCchPrintfW(szFormat, _countof(szFormat), Globals.szGrpBoxTitle, EntriesList[Globals.iSelectedIndex].szResource); SetWindowTextW(GetDlgItem(Globals.hMainDlg, IDC_GROUPBOX), szFormat); } /** * @UpdateUtilityState * * Checks the state of the given accessibility tool. * * @param[in] bUtilState * State condition (boolean TRUE: started / FALSE: stopped). * * @return * Nothing. * */ VOID UpdateUtilityState(IN BOOL bUtilState) { Button_Enable(Globals.hDlgCtlStart, !bUtilState); Button_Enable(Globals.hDlgCtlStop, bUtilState); /* Update the groupbox's title based on the selected utility item */ GroupBoxUpdateTitle(); } /** * @ListBoxRefreshContents * * Handle the tasks on a periodic cycle. This function handles WM_TIMER message. * * @return * Returns 0 to inform the system that WM_TIMER has been processed. * */ INT ListBoxRefreshContents(VOID) { UINT i; INT iItem; BOOL bIsRunning; WCHAR szFormat[MAX_BUFFER]; /* Disable listbox redraw */ SendMessageW(Globals.hListDlg, WM_SETREDRAW, FALSE, 0); for (i = 0; i < _countof(EntriesList); ++i) { /* Check the utility's state */ bIsRunning = IsProcessRunning(EntriesList[i].lpProgram); if (bIsRunning != EntriesList[i].bState) { /* The utility's state has changed, save it */ EntriesList[i].bState = bIsRunning; /* Update the corresponding item in the listbox */ StringCchPrintfW(szFormat, _countof(szFormat), (bIsRunning ? Globals.szRunning : Globals.szNotRunning), EntriesList[i].szResource); SendMessageW(Globals.hListDlg, LB_DELETESTRING, (LPARAM)i, 0); iItem = SendMessageW(Globals.hListDlg, LB_INSERTSTRING, (LPARAM)i, (LPARAM)szFormat); if (iItem != LB_ERR) SendMessageW(Globals.hListDlg, LB_SETITEMDATA, iItem, (LPARAM)&EntriesList[i]); } } /* Re-enable listbox redraw */ SendMessageW(Globals.hListDlg, WM_SETREDRAW, TRUE, 0); /* * Check the previously selected item. This will help us determine what * item has been selected and set its focus selection back. Furthermore, check * the state of each accessibility tool and enable/disable the buttons. */ SendMessageW(Globals.hListDlg, LB_SETCURSEL, (WPARAM)Globals.iSelectedIndex, 0); UpdateUtilityState(EntriesList[Globals.iSelectedIndex].bState); return 0; } /** * @DlgProc * * Main dialog application procedure function. * * @param[in] hDlg * The handle object of the dialog. * * @param[in] Msg * Message events (in unsigned int). * * @param[in] wParam * Message parameter (in UINT_PTR). * * @param[in] lParam * Message paramater (in LONG_PTR). * * @return * Returns 0 to inform the system that the procedure has been handled. * */ INT_PTR APIENTRY DlgProc( IN HWND hDlg, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam) { switch (Msg) { case WM_INITDIALOG: DlgInitHandler(hDlg); return TRUE; case WM_CLOSE: KillTimer(hDlg, Globals.iTimer); DestroyIcon(Globals.hIcon); EndDialog(hDlg, FALSE); break; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_OK: case IDC_CANCEL: EndDialog(hDlg, FALSE); break; case IDC_LISTBOX: { switch (HIWORD(wParam)) { case LBN_SELCHANGE: { /* Retrieve the index of the current selected item */ INT iIndex = SendMessageW(Globals.hListDlg, LB_GETCURSEL, 0, 0); if ((iIndex == LB_ERR) || (iIndex >= _countof(EntriesList))) break; /* Assign the selected index and check the utility's state */ Globals.iSelectedIndex = iIndex; UpdateUtilityState(EntriesList[Globals.iSelectedIndex].bState); break; } break; } break; } case IDC_START: LaunchProcess(EntriesList[Globals.iSelectedIndex].lpProgram); break; case IDC_STOP: CloseProcess(EntriesList[Globals.iSelectedIndex].lpProgram); break; default: break; } break; } case WM_TIMER: ListBoxRefreshContents(); return 0; case WM_SYSCOMMAND: { switch (LOWORD(wParam)) { case IDM_ABOUT: ShowAboutDlg(hDlg); break; } break; } } return 0; } /** * @wWinMain * * Application entry point. * * @param[in] hInstance * Application instance. * * @param[in] hPrevInstance * The previous instance of the application (not used). * * @param[in] pCmdLine * Pointer to a command line argument (in wide string -- not used). * * @param[in] nCmdShow * An integer served as a flag to note how the application will be shown (not used). * * @return * Returns 0 to let the function terminating before it enters in the message loop. * */ INT WINAPI wWinMain( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPWSTR pCmdLine, IN INT nCmdShow) { HANDLE hMutex; DWORD dwError; INITCOMMONCONTROLSEX iccex; UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(pCmdLine); UNREFERENCED_PARAMETER(nCmdShow); /* Create a mutant object for the program. */ hMutex = CreateMutexW(NULL, FALSE, L"Utilman"); if (hMutex) { /* Check if there's already a mutex for the program */ dwError = GetLastError(); if (dwError == ERROR_ALREADY_EXISTS) { /* The program's instance is already here. That means the program is running and we should not set a new instance and mutex object. */ CloseHandle(hMutex); return 0; } } /* Load the common controls for the program */ iccex.dwSize = sizeof(INITCOMMONCONTROLSEX); iccex.dwICC = ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES; InitCommonControlsEx(&iccex); /* Initialize the globals */ ZeroMemory(&Globals, sizeof(Globals)); Globals.hInstance = hInstance; LoadStringW(Globals.hInstance, IDS_RUNNING, Globals.szRunning, _countof(Globals.szRunning)); LoadStringW(Globals.hInstance, IDS_NOTRUNNING, Globals.szNotRunning, _countof(Globals.szNotRunning)); LoadStringW(Globals.hInstance, IDS_GROUPBOX_OPTIONS_TITLE, Globals.szGrpBoxTitle, _countof(Globals.szGrpBoxTitle)); /* Initialize the list of accessibility utilities */ InitUtilsList(FALSE); /* Create the dialog box of the program */ DialogBoxW(hInstance, MAKEINTRESOURCEW(IDD_MAIN_DIALOG), GetDesktopWindow(), DlgProc); /* Delete the mutex */ if (hMutex) { CloseHandle(hMutex); } return 0; }