reactos/base/applications/utilman/dialog.c
2019-08-19 13:05:28 +02:00

438 lines
12 KiB
C

/*
* 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;
}