···11+ReactOS Accessibility Utility Manager
22+=======================================
33+44+Currently the application can manage the state of the accessibility tools however there are some things which needs to be DONE in order to consider the program as fully complete. The following are:
55+66+- The warning dialog is not implemented YET
77+- The program can only control the launch/stopping states of accessibility tools, the code which manages the options for each utility is not implemented YET
88+- Function helper which catches the Windows logo + U keys is not implemented YET
99+- Registry configuration saver/loader is not implemented YET (XP's Utility Manager creates a key on HKEY_CURRENT_USER\Software\Microsoft with the name "Utility Manager" although the rest of other configuration values for utility options are stored elsewhere and I don't know exactly where are those)
1010+- XP's and Server 2003's main Utility Manager implementation is compiled in a DLL (+ an executable which loads the DLL in question) whereas our Utility Manager is compiled as a whole executable
1111+- On Windows Vista and later, it complains for required elevation to open a process. We need to improve our process creation code and discard ShellExecuteW()
+93
base/applications/utilman/about.c
···11+/*
22+ * PROJECT: ReactOS Utility Manager (Accessibility)
33+ * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
44+ * PURPOSE: About dialog file
55+ * COPYRIGHT: Copyright 2019 Bișoc George (fraizeraust99 at gmail dot com)
66+ */
77+88+/* INCLUDES *******************************************************************/
99+1010+#include "precomp.h"
1111+1212+/* GLOBALS ********************************************************************/
1313+1414+UTILMAN_GLOBALS Globals;
1515+1616+/* FUNCTIONS ******************************************************************/
1717+1818+/**
1919+ * @AboutDlgProc
2020+ *
2121+ * "About" dialog procedure.
2222+ *
2323+ * @param hDlg
2424+ * The handle object of the dialog.
2525+ *
2626+ * @param Msg
2727+ * Message events (in unsigned int).
2828+ *
2929+ * @param wParam
3030+ * Message parameter (in UINT_PTR).
3131+ *
3232+ * @param lParam
3333+ * Message paramater (in LONG_PTR).
3434+ *
3535+ * @return
3636+ * Return TRUE if the dialog processed messages,
3737+ * FALSE otherwise.
3838+ *
3939+ */
4040+INT_PTR CALLBACK AboutDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
4141+{
4242+ switch (Msg)
4343+ {
4444+ case WM_INITDIALOG:
4545+ {
4646+ Globals.hIcon = LoadImageW(Globals.hInstance,
4747+ MAKEINTRESOURCEW(IDI_ICON_UTILMAN),
4848+ IMAGE_ICON,
4949+ 0,
5050+ 0,
5151+ LR_DEFAULTSIZE);
5252+5353+ /* Set the icon within the dialog's title bar */
5454+ if (Globals.hIcon)
5555+ {
5656+ SendMessageW(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)Globals.hIcon);
5757+ }
5858+5959+ return TRUE;
6060+ }
6161+6262+ case WM_COMMAND:
6363+ {
6464+ case IDOK:
6565+ case IDCANCEL:
6666+ DestroyIcon(Globals.hIcon);
6767+ EndDialog(hDlg, FALSE);
6868+ break;
6969+ }
7070+ }
7171+7272+ return FALSE;
7373+}
7474+7575+/**
7676+ * @ShowAboutDlg
7777+ *
7878+ * Display the "About" dialog.
7979+ *
8080+ * @param hDlgParent
8181+ * The handle object of the parent dialog.
8282+ *
8383+ * @return
8484+ * Nothing.
8585+ */
8686+VOID ShowAboutDlg(HWND hDlgParent)
8787+{
8888+ /* Display the "About" dialog when the user clicks on the "About" menu item */
8989+ DialogBoxW(Globals.hInstance,
9090+ MAKEINTRESOURCEW(IDD_ABOUT_DIALOG),
9191+ hDlgParent,
9292+ AboutDlgProc);
9393+}
+438
base/applications/utilman/dialog.c
···11+/*
22+ * PROJECT: ReactOS Utility Manager (Accessibility)
33+ * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
44+ * PURPOSE: Main dialog code file
55+ * COPYRIGHT: Copyright 2019 Bișoc George (fraizeraust99 at gmail dot com)
66+ * Copyright 2019 Hermes Belusca-Maito
77+ */
88+99+/* INCLUDES *******************************************************************/
1010+1111+#include "precomp.h"
1212+1313+/* GLOBALS ********************************************************************/
1414+1515+UTILMAN_GLOBALS Globals;
1616+1717+/* DECLARATIONS ***************************************************************/
1818+1919+UTILMAN_STATE EntriesList[] =
2020+{
2121+ {L"magnify.exe", IDS_MAGNIFIER, L"", FALSE},
2222+ {L"osk.exe", IDS_OSK, L"", FALSE}
2323+};
2424+2525+/* FUNCTIONS ******************************************************************/
2626+2727+/**
2828+ * @InitUtilsList
2929+ *
3030+ * Initializes the list of accessibility utilities.
3131+ *
3232+ * @param[in] bInitGui
3333+ * Whether we are initializing the UI list (TRUE) or the internal array (FALSE).
3434+ *
3535+ * @return
3636+ * Nothing.
3737+ */
3838+VOID InitUtilsList(BOOL bInitGui)
3939+{
4040+ UINT i;
4141+4242+ if (!bInitGui)
4343+ {
4444+ // TODO: Load the list dynamically from the registry key
4545+ // hklm\software\microsoft\windows nt\currentversion\accessibility
4646+4747+ /* Initialize the resource utility strings only once */
4848+ for (i = 0; i < _countof(EntriesList); ++i)
4949+ {
5050+ LoadStringW(Globals.hInstance, EntriesList[i].uNameId,
5151+ EntriesList[i].szResource, _countof(EntriesList[i].szResource));
5252+5353+ EntriesList[i].bState = FALSE;
5454+ }
5555+ }
5656+ else
5757+ {
5858+ INT iItem;
5959+ BOOL bIsRunning;
6060+ WCHAR szFormat[MAX_BUFFER];
6161+6262+ /* Reset the listbox */
6363+ SendMessageW(Globals.hListDlg, LB_RESETCONTENT, 0, 0);
6464+6565+ /* Add the utilities in the listbox */
6666+ for (i = 0; i < _countof(EntriesList); ++i)
6767+ {
6868+ bIsRunning = IsProcessRunning(EntriesList[i].lpProgram);
6969+ EntriesList[i].bState = bIsRunning;
7070+7171+ /* Load the string and append the utility's name to the format */
7272+ StringCchPrintfW(szFormat, _countof(szFormat),
7373+ (bIsRunning ? Globals.szRunning : Globals.szNotRunning),
7474+ EntriesList[i].szResource);
7575+7676+ /* Add the item in the listbox */
7777+ iItem = (INT)SendMessageW(Globals.hListDlg, LB_ADDSTRING, 0, (LPARAM)szFormat);
7878+ if (iItem != LB_ERR)
7979+ SendMessageW(Globals.hListDlg, LB_SETITEMDATA, iItem, (LPARAM)&EntriesList[i]);
8080+ }
8181+ }
8282+}
8383+8484+/**
8585+ * @DlgInitHandler
8686+ *
8787+ * Function which processes several operations for WM_INITDIALOG.
8888+ *
8989+ * @param[in] hDlg
9090+ * The handle object of the dialog.
9191+ *
9292+ * @return
9393+ * TRUE to inform the system that WM_INITDIALOG has been processed and
9494+ * that it should set the keyboard focus to the control.
9595+ *
9696+ */
9797+BOOL DlgInitHandler(IN HWND hDlg)
9898+{
9999+ INT PosX, PosY;
100100+ RECT rc;
101101+ WCHAR szAboutDlg[MAX_BUFFER];
102102+ HMENU hSysMenu;
103103+104104+ /* Save the dialog handle */
105105+ Globals.hMainDlg = hDlg;
106106+107107+ /* Center the dialog on the screen */
108108+ GetWindowRect(hDlg, &rc);
109109+ PosX = (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2;
110110+ PosY = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2;
111111+ SetWindowPos(hDlg, 0, PosX, PosY, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
112112+113113+ /* Load the icon resource */
114114+ Globals.hIcon = LoadImageW(Globals.hInstance,
115115+ MAKEINTRESOURCEW(IDI_ICON_UTILMAN),
116116+ IMAGE_ICON,
117117+ 0,
118118+ 0,
119119+ LR_DEFAULTSIZE);
120120+121121+ /* Set the icon within the dialog's title bar */
122122+ if (Globals.hIcon)
123123+ {
124124+ SendMessageW(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)Globals.hIcon);
125125+ }
126126+127127+ /* Retrieve the system menu and append the "About" menu item onto it */
128128+ hSysMenu = GetSystemMenu(hDlg, FALSE);
129129+ if (hSysMenu != NULL)
130130+ {
131131+ if (LoadStringW(Globals.hInstance, IDM_ABOUT, szAboutDlg, _countof(szAboutDlg)))
132132+ {
133133+ AppendMenuW(hSysMenu, MF_SEPARATOR, 0, NULL);
134134+ AppendMenuW(hSysMenu, MF_STRING, IDM_ABOUT, szAboutDlg);
135135+ }
136136+ }
137137+138138+ /* Get the dialog items, specifically the dialog list box, the Start and Stop buttons */
139139+ Globals.hListDlg = GetDlgItem(hDlg, IDC_LISTBOX);
140140+ Globals.hDlgCtlStart = GetDlgItem(hDlg, IDC_START);
141141+ Globals.hDlgCtlStop = GetDlgItem(hDlg, IDC_STOP);
142142+143143+ /* Initialize the GUI listbox */
144144+ InitUtilsList(TRUE);
145145+146146+ /* Set the selection to the first item */
147147+ Globals.iSelectedIndex = 0;
148148+149149+ /* Refresh the list */
150150+ ListBoxRefreshContents();
151151+152152+ /* Create a timer, we'll use it to control the state of our items in the listbox */
153153+ Globals.iTimer = SetTimer(hDlg, 0, 400, NULL);
154154+155155+ return TRUE;
156156+}
157157+158158+/**
159159+ * @GroupBoxUpdateTitle
160160+ *
161161+ * Updates the title of the groupbox.
162162+ *
163163+ * @return
164164+ * Nothing.
165165+ *
166166+ */
167167+VOID GroupBoxUpdateTitle(VOID)
168168+{
169169+ WCHAR szFormat[MAX_BUFFER];
170170+171171+ /* Format the string with the utility's name and set it to the listbox's title */
172172+ StringCchPrintfW(szFormat, _countof(szFormat), Globals.szGrpBoxTitle, EntriesList[Globals.iSelectedIndex].szResource);
173173+ SetWindowTextW(GetDlgItem(Globals.hMainDlg, IDC_GROUPBOX), szFormat);
174174+}
175175+176176+/**
177177+ * @UpdateUtilityState
178178+ *
179179+ * Checks the state of the given accessibility tool.
180180+ *
181181+ * @param[in] bUtilState
182182+ * State condition (boolean TRUE: started / FALSE: stopped).
183183+ *
184184+ * @return
185185+ * Nothing.
186186+ *
187187+ */
188188+VOID UpdateUtilityState(IN BOOL bUtilState)
189189+{
190190+ Button_Enable(Globals.hDlgCtlStart, !bUtilState);
191191+ Button_Enable(Globals.hDlgCtlStop, bUtilState);
192192+193193+ /* Update the groupbox's title based on the selected utility item */
194194+ GroupBoxUpdateTitle();
195195+}
196196+197197+/**
198198+ * @ListBoxRefreshContents
199199+ *
200200+ * Handle the tasks on a periodic cycle. This function handles WM_TIMER message.
201201+ *
202202+ * @return
203203+ * Returns 0 to inform the system that WM_TIMER has been processed.
204204+ *
205205+ */
206206+INT ListBoxRefreshContents(VOID)
207207+{
208208+ UINT i;
209209+ INT iItem;
210210+ BOOL bIsRunning;
211211+ WCHAR szFormat[MAX_BUFFER];
212212+213213+ /* Disable listbox redraw */
214214+ SendMessageW(Globals.hListDlg, WM_SETREDRAW, FALSE, 0);
215215+216216+ for (i = 0; i < _countof(EntriesList); ++i)
217217+ {
218218+ /* Check the utility's state */
219219+ bIsRunning = IsProcessRunning(EntriesList[i].lpProgram);
220220+ if (bIsRunning != EntriesList[i].bState)
221221+ {
222222+ /* The utility's state has changed, save it */
223223+ EntriesList[i].bState = bIsRunning;
224224+225225+ /* Update the corresponding item in the listbox */
226226+ StringCchPrintfW(szFormat, _countof(szFormat),
227227+ (bIsRunning ? Globals.szRunning : Globals.szNotRunning),
228228+ EntriesList[i].szResource);
229229+230230+ SendMessageW(Globals.hListDlg, LB_DELETESTRING, (LPARAM)i, 0);
231231+ iItem = SendMessageW(Globals.hListDlg, LB_INSERTSTRING, (LPARAM)i, (LPARAM)szFormat);
232232+ if (iItem != LB_ERR)
233233+ SendMessageW(Globals.hListDlg, LB_SETITEMDATA, iItem, (LPARAM)&EntriesList[i]);
234234+ }
235235+ }
236236+237237+ /* Re-enable listbox redraw */
238238+ SendMessageW(Globals.hListDlg, WM_SETREDRAW, TRUE, 0);
239239+240240+ /*
241241+ * Check the previously selected item. This will help us determine what
242242+ * item has been selected and set its focus selection back. Furthermore, check
243243+ * the state of each accessibility tool and enable/disable the buttons.
244244+ */
245245+ SendMessageW(Globals.hListDlg, LB_SETCURSEL, (WPARAM)Globals.iSelectedIndex, 0);
246246+ UpdateUtilityState(EntriesList[Globals.iSelectedIndex].bState);
247247+248248+ return 0;
249249+}
250250+251251+/**
252252+ * @DlgProc
253253+ *
254254+ * Main dialog application procedure function.
255255+ *
256256+ * @param[in] hDlg
257257+ * The handle object of the dialog.
258258+ *
259259+ * @param[in] Msg
260260+ * Message events (in unsigned int).
261261+ *
262262+ * @param[in] wParam
263263+ * Message parameter (in UINT_PTR).
264264+ *
265265+ * @param[in] lParam
266266+ * Message paramater (in LONG_PTR).
267267+ *
268268+ * @return
269269+ * Returns 0 to inform the system that the procedure has been handled.
270270+ *
271271+ */
272272+INT_PTR APIENTRY DlgProc(
273273+ IN HWND hDlg,
274274+ IN UINT Msg,
275275+ IN WPARAM wParam,
276276+ IN LPARAM lParam)
277277+{
278278+ switch (Msg)
279279+ {
280280+ case WM_INITDIALOG:
281281+ DlgInitHandler(hDlg);
282282+ return TRUE;
283283+284284+ case WM_CLOSE:
285285+ KillTimer(hDlg, Globals.iTimer);
286286+ DestroyIcon(Globals.hIcon);
287287+ EndDialog(hDlg, FALSE);
288288+ break;
289289+290290+ case WM_COMMAND:
291291+ {
292292+ switch (LOWORD(wParam))
293293+ {
294294+ case IDC_OK:
295295+ case IDC_CANCEL:
296296+ EndDialog(hDlg, FALSE);
297297+ break;
298298+299299+ case IDC_LISTBOX:
300300+ {
301301+ switch (HIWORD(wParam))
302302+ {
303303+ case LBN_SELCHANGE:
304304+ {
305305+ /* Retrieve the index of the current selected item */
306306+ INT iIndex = SendMessageW(Globals.hListDlg, LB_GETCURSEL, 0, 0);
307307+ if ((iIndex == LB_ERR) || (iIndex >= _countof(EntriesList)))
308308+ break;
309309+310310+ /* Assign the selected index and check the utility's state */
311311+ Globals.iSelectedIndex = iIndex;
312312+ UpdateUtilityState(EntriesList[Globals.iSelectedIndex].bState);
313313+ break;
314314+ }
315315+ break;
316316+ }
317317+ break;
318318+ }
319319+320320+ case IDC_START:
321321+ LaunchProcess(EntriesList[Globals.iSelectedIndex].lpProgram);
322322+ break;
323323+324324+ case IDC_STOP:
325325+ CloseProcess(EntriesList[Globals.iSelectedIndex].lpProgram);
326326+ break;
327327+328328+ default:
329329+ break;
330330+ }
331331+ break;
332332+ }
333333+334334+ case WM_TIMER:
335335+ ListBoxRefreshContents();
336336+ return 0;
337337+338338+ case WM_SYSCOMMAND:
339339+ {
340340+ switch (LOWORD(wParam))
341341+ {
342342+ case IDM_ABOUT:
343343+ ShowAboutDlg(hDlg);
344344+ break;
345345+ }
346346+ break;
347347+ }
348348+ }
349349+350350+ return 0;
351351+}
352352+353353+/**
354354+ * @wWinMain
355355+ *
356356+ * Application entry point.
357357+ *
358358+ * @param[in] hInstance
359359+ * Application instance.
360360+ *
361361+ * @param[in] hPrevInstance
362362+ * The previous instance of the application (not used).
363363+ *
364364+ * @param[in] pCmdLine
365365+ * Pointer to a command line argument (in wide string -- not used).
366366+ *
367367+ * @param[in] nCmdShow
368368+ * An integer served as a flag to note how the application will be shown (not used).
369369+ *
370370+ * @return
371371+ * Returns 0 to let the function terminating before it enters in the message loop.
372372+ *
373373+ */
374374+INT WINAPI wWinMain(
375375+ IN HINSTANCE hInstance,
376376+ IN HINSTANCE hPrevInstance,
377377+ IN LPWSTR pCmdLine,
378378+ IN INT nCmdShow)
379379+{
380380+ HANDLE hMutex;
381381+ DWORD dwError;
382382+ INITCOMMONCONTROLSEX iccex;
383383+384384+ UNREFERENCED_PARAMETER(hPrevInstance);
385385+ UNREFERENCED_PARAMETER(pCmdLine);
386386+ UNREFERENCED_PARAMETER(nCmdShow);
387387+388388+ /* Create a mutant object for the program. */
389389+ hMutex = CreateMutexW(NULL, FALSE, L"Utilman");
390390+ if (hMutex)
391391+ {
392392+ /* Check if there's already a mutex for the program */
393393+ dwError = GetLastError();
394394+ if (dwError == ERROR_ALREADY_EXISTS)
395395+ {
396396+ /*
397397+ The program's instance is already here. That means
398398+ the program is running and we should not set a new instance
399399+ and mutex object.
400400+ */
401401+ CloseHandle(hMutex);
402402+ return 0;
403403+ }
404404+ }
405405+406406+ /* Load the common controls for the program */
407407+ iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
408408+ iccex.dwICC = ICC_STANDARD_CLASSES | ICC_WIN95_CLASSES;
409409+ InitCommonControlsEx(&iccex);
410410+411411+ /* Initialize the globals */
412412+ ZeroMemory(&Globals, sizeof(Globals));
413413+ Globals.hInstance = hInstance;
414414+415415+ LoadStringW(Globals.hInstance, IDS_RUNNING,
416416+ Globals.szRunning, _countof(Globals.szRunning));
417417+ LoadStringW(Globals.hInstance, IDS_NOTRUNNING,
418418+ Globals.szNotRunning, _countof(Globals.szNotRunning));
419419+ LoadStringW(Globals.hInstance, IDS_GROUPBOX_OPTIONS_TITLE,
420420+ Globals.szGrpBoxTitle, _countof(Globals.szGrpBoxTitle));
421421+422422+ /* Initialize the list of accessibility utilities */
423423+ InitUtilsList(FALSE);
424424+425425+ /* Create the dialog box of the program */
426426+ DialogBoxW(hInstance,
427427+ MAKEINTRESOURCEW(IDD_MAIN_DIALOG),
428428+ GetDesktopWindow(),
429429+ DlgProc);
430430+431431+ /* Delete the mutex */
432432+ if (hMutex)
433433+ {
434434+ CloseHandle(hMutex);
435435+ }
436436+437437+ return 0;
438438+}