reactos/dll/win32/msports/serial.c
2024-10-06 10:47:11 +03:00

670 lines
16 KiB
C

/*
* PROJECT: Ports installer library
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll\win32\msports\serial.c
* PURPOSE: Serial Port property functions
* COPYRIGHT: Copyright 2011 Eric Kohl
*/
#include "precomp.h"
typedef struct _PORT_DATA
{
HDEVINFO DeviceInfoSet;
PSP_DEVINFO_DATA DeviceInfoData;
WCHAR szPortName[16];
INT nBaudRateIndex;
INT nParityIndex;
INT nDataBitsIndex;
INT nStopBitsIndex;
INT nFlowControlIndex;
BOOL bChanged;
} PORT_DATA, *PPORT_DATA;
#define DEFAULT_BAUD_RATE_INDEX 11
#define DEFAULT_DATA_BITS_INDEX 4
#define DEFAULT_PARITY_INDEX 2
#define DEFAULT_STOP_BITS_INDEX 0
#define DEFAULT_FLOW_CONTROL_INDEX 2
DWORD BaudRates[] = {75, 110, 134, 150, 300, 600, 1200, 1800, 2400, 4800,
7200, 9600, 14400, 19200, 38400, 57600, 115200, 128000};
PWSTR Paritys[] = {L"e", L"o", L"n", L"m", L"s"};
PWSTR DataBits[] = {L"4", L"5", L"6", L"7", L"8"};
PWSTR StopBits[] = {L"1", L"1.5", L"2"};
PWSTR FlowControls[] = {L"x", L"p"};
static
VOID
FillComboBox(
HWND hwnd,
PWSTR szBuffer)
{
PWSTR pStart, pEnd;
pStart = szBuffer;
for (;;)
{
pEnd = wcschr(pStart, L',');
if (pEnd != NULL)
*pEnd = UNICODE_NULL;
ComboBox_AddString(hwnd, pStart);
if (pEnd == NULL)
break;
pStart = pEnd + 1;
}
}
static
VOID
ReadPortSettings(
PPORT_DATA pPortData)
{
WCHAR szPortData[32];
WCHAR szParity[4];
WCHAR szDataBits[4];
WCHAR szStopBits[4];
WCHAR szFlowControl[4];
DWORD dwType, dwSize;
DWORD dwBaudRate = 0;
HKEY hKey;
INT n, i;
LONG lError;
TRACE("ReadPortSettings(%p)\n", pPortData);
pPortData->nBaudRateIndex = DEFAULT_BAUD_RATE_INDEX; /* 9600 */
pPortData->nParityIndex = DEFAULT_PARITY_INDEX; /* None */
pPortData->nDataBitsIndex = DEFAULT_DATA_BITS_INDEX; /* 8 Data Bits */
pPortData->nStopBitsIndex = DEFAULT_STOP_BITS_INDEX; /* 1 Stop Bit */
pPortData->nFlowControlIndex = DEFAULT_FLOW_CONTROL_INDEX; /* None */
pPortData->bChanged = FALSE;
hKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet,
pPortData->DeviceInfoData,
DICS_FLAG_GLOBAL,
0,
DIREG_DEV,
KEY_READ);
if (hKey == INVALID_HANDLE_VALUE)
{
ERR("SetupDiOpenDevRegKey() failed\n");
return;
}
dwSize = sizeof(pPortData->szPortName);
lError = RegQueryValueExW(hKey,
L"PortName",
NULL,
NULL,
(PBYTE)pPortData->szPortName,
&dwSize);
RegCloseKey(hKey);
if (lError != ERROR_SUCCESS)
{
ERR("RegQueryValueExW failed (Error %lu)\n", lError);
return;
}
wcscat(pPortData->szPortName, L":");
TRACE("PortName: '%S'\n", pPortData->szPortName);
lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports",
0,
KEY_READ,
&hKey);
if (lError != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed (Error %lu)\n", lError);
return;
}
dwSize = sizeof(szPortData);
lError = RegQueryValueExW(hKey,
pPortData->szPortName,
NULL,
&dwType,
(LPBYTE)szPortData,
&dwSize);
RegCloseKey(hKey);
if (lError != ERROR_SUCCESS)
{
ERR("RegQueryValueExW failed (Error %lu)\n", lError);
return;
}
if ((dwType != REG_SZ) || (dwSize > sizeof(szPortData)))
{
ERR("Wrong type or size\n");
return;
}
TRACE("szPortData: '%S'\n", szPortData);
/* Replace commas by spaces */
for (i = 0; i < wcslen(szPortData); i++)
{
if (szPortData[i] == L',')
szPortData[i] = L' ';
}
TRACE("szPortData: '%S'\n", szPortData);
/* Parse the port settings */
n = swscanf(szPortData,
L"%lu %3s %3s %3s %3s",
&dwBaudRate,
&szParity,
&szDataBits,
&szStopBits,
&szFlowControl);
TRACE("dwBaudRate: %lu\n", dwBaudRate);
TRACE("szParity: '%S'\n", szParity);
TRACE("szDataBits: '%S'\n", szDataBits);
TRACE("szStopBits: '%S'\n", szStopBits);
TRACE("szFlowControl: '%S'\n", szFlowControl);
if (n > 0)
{
for (i = 0; i < ARRAYSIZE(BaudRates); i++)
{
if (dwBaudRate == BaudRates[i])
pPortData->nBaudRateIndex = i;
}
}
if (n > 1)
{
for (i = 0; i < ARRAYSIZE(Paritys); i++)
{
if (_wcsicmp(szParity, Paritys[i]) == 0)
pPortData->nParityIndex = i;
}
}
if (n > 2)
{
for (i = 0; i < ARRAYSIZE(DataBits); i++)
{
if (_wcsicmp(szDataBits, DataBits[i]) == 0)
pPortData->nDataBitsIndex = i;
}
}
if (n > 3)
{
for (i = 0; i < ARRAYSIZE(StopBits); i++)
{
if (_wcsicmp(szStopBits, StopBits[i]) == 0)
pPortData->nStopBitsIndex = i;
}
}
if (n > 4)
{
for (i = 0; i < ARRAYSIZE(FlowControls); i++)
{
if (_wcsicmp(szFlowControl, FlowControls[i]) == 0)
pPortData->nFlowControlIndex = i;
}
}
}
static
VOID
WritePortSettings(
HWND hwnd,
PPORT_DATA pPortData)
{
SP_PROPCHANGE_PARAMS PropChangeParams;
WCHAR szPortData[32];
HWND hwndControl;
INT nBaudRateIndex;
INT nDataBitsIndex;
INT nParityIndex;
INT nStopBitsIndex;
INT nFlowControlIndex;
HKEY hKey;
LONG lError;
TRACE("WritePortSettings(%p)\n", pPortData);
if (pPortData->bChanged == FALSE)
{
TRACE("Nothing changed. Done!\n");
return;
}
nBaudRateIndex = pPortData->nBaudRateIndex;
nDataBitsIndex = pPortData->nDataBitsIndex;
nParityIndex = pPortData->nParityIndex;
nStopBitsIndex = pPortData->nStopBitsIndex;
nFlowControlIndex = pPortData->nFlowControlIndex;
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
if (hwndControl)
{
nBaudRateIndex = ComboBox_GetCurSel(hwndControl);
}
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
if (hwndControl)
{
nDataBitsIndex = ComboBox_GetCurSel(hwndControl);
}
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
if (hwndControl)
{
nParityIndex = ComboBox_GetCurSel(hwndControl);
}
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
if (hwndControl)
{
nStopBitsIndex = ComboBox_GetCurSel(hwndControl);
}
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
if (hwndControl)
{
nFlowControlIndex = ComboBox_GetCurSel(hwndControl);
}
swprintf(szPortData,
L"%lu,%s,%s,%s",
BaudRates[nBaudRateIndex],
Paritys[nParityIndex],
DataBits[nDataBitsIndex],
StopBits[nStopBitsIndex]);
if (nFlowControlIndex < 2)
{
wcscat(szPortData, L",");
wcscat(szPortData, FlowControls[nFlowControlIndex]);
}
TRACE("szPortData: '%S'\n", szPortData);
lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Ports",
0,
KEY_WRITE,
&hKey);
if (lError != ERROR_SUCCESS)
{
ERR("RegOpenKeyExW failed (Error %lu)\n", lError);
return;
}
lError = RegSetValueExW(hKey,
pPortData->szPortName,
0,
REG_SZ,
(LPBYTE)szPortData,
(wcslen(szPortData) + 1) * sizeof(WCHAR));
RegCloseKey(hKey);
if (lError != ERROR_SUCCESS)
{
ERR("RegSetValueExW failed (Error %lu)\n", lError);
return;
}
/* Notify the system */
PostMessageW(HWND_BROADCAST,
WM_WININICHANGE,
0,
(LPARAM)pPortData->szPortName);
/* Notify the installer (and device) */
PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
PropChangeParams.Scope = DICS_FLAG_GLOBAL;
PropChangeParams.StateChange = DICS_PROPCHANGE;
SetupDiSetClassInstallParams(pPortData->DeviceInfoSet,
pPortData->DeviceInfoData,
(PSP_CLASSINSTALL_HEADER)&PropChangeParams,
sizeof(SP_PROPCHANGE_PARAMS));
SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
pPortData->DeviceInfoSet,
pPortData->DeviceInfoData);
TRACE("Done!\n");
}
static
BOOL
OnInitDialog(
HWND hwnd,
WPARAM wParam,
LPARAM lParam)
{
PPORT_DATA pPortData;
WCHAR szBuffer[256];
UINT i;
HWND hwndControl;
TRACE("OnInitDialog()\n");
pPortData = (PPORT_DATA)((LPPROPSHEETPAGEW)lParam)->lParam;
if (pPortData == NULL)
{
ERR("pPortData is NULL\n");
return FALSE;
}
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPortData);
/* Read and parse the port settings */
ReadPortSettings(pPortData);
/* Fill the 'Bits per second' combobox */
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
if (hwndControl)
{
for (i = 0; i < ARRAYSIZE(BaudRates); i++)
{
_ultow(BaudRates[i], szBuffer, 10);
ComboBox_AddString(hwndControl, szBuffer);
}
ComboBox_SetCurSel(hwndControl, pPortData->nBaudRateIndex);
}
/* Fill the 'Data bits' combobox */
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
if (hwndControl)
{
for (i = 0; i < ARRAYSIZE(DataBits); i++)
{
ComboBox_AddString(hwndControl, DataBits[i]);
}
ComboBox_SetCurSel(hwndControl, pPortData->nDataBitsIndex);
}
/* Fill the 'Parity' combobox */
LoadStringW(hInstance, IDS_PARITY, szBuffer, ARRAYSIZE(szBuffer));
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
if (hwndControl)
{
FillComboBox(hwndControl, szBuffer);
ComboBox_SetCurSel(hwndControl, pPortData->nParityIndex);
}
/* Fill the 'Stop bits' combobox */
LoadStringW(hInstance, IDS_STOPBITS, szBuffer, ARRAYSIZE(szBuffer));
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
if (hwndControl)
{
FillComboBox(hwndControl, szBuffer);
ComboBox_SetCurSel(hwndControl, pPortData->nStopBitsIndex);
}
/* Fill the 'Flow control' combobox */
LoadStringW(hInstance, IDS_FLOWCONTROL, szBuffer, ARRAYSIZE(szBuffer));
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
if (hwndControl)
{
FillComboBox(hwndControl, szBuffer);
ComboBox_SetCurSel(hwndControl, pPortData->nFlowControlIndex);
}
/* Disable the 'Advanced' button */
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_ADVANCED);
if (hwndControl)
EnableWindow(hwndControl, FALSE);
return TRUE;
}
static
VOID
RestoreDefaultValues(
HWND hwnd,
PPORT_DATA pPortData)
{
HWND hwndControl;
/* Reset the 'Bits per second' combobox */
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_BITSPERSECOND);
if (hwndControl)
{
ComboBox_SetCurSel(hwndControl, DEFAULT_BAUD_RATE_INDEX);
}
/* Reset the 'Data bits' combobox */
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_DATABITS);
if (hwndControl)
{
ComboBox_SetCurSel(hwndControl, DEFAULT_DATA_BITS_INDEX);
}
/* Reset the 'Parity' combobox */
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_PARITY);
if (hwndControl)
{
ComboBox_SetCurSel(hwndControl, DEFAULT_PARITY_INDEX);
}
/* Reset the 'Stop bits' combobox */
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_STOPBITS);
if (hwndControl)
{
ComboBox_SetCurSel(hwndControl, DEFAULT_STOP_BITS_INDEX);
}
/* Reset the 'Flow control' combobox */
hwndControl = GetDlgItem(hwnd, IDC_SERIAL_FLOWCONTROL);
if (hwndControl)
{
ComboBox_SetCurSel(hwndControl, DEFAULT_FLOW_CONTROL_INDEX);
}
pPortData->bChanged = TRUE;
}
static
VOID
OnCommand(
HWND hwnd,
WPARAM wParam,
LPARAM lParam)
{
PPORT_DATA pPortData;
TRACE("OnCommand()\n");
pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
if (pPortData == NULL)
{
ERR("pPortData is NULL\n");
return;
}
switch (LOWORD(wParam))
{
case IDC_SERIAL_BITSPERSECOND:
case IDC_SERIAL_DATABITS:
case IDC_SERIAL_PARITY:
case IDC_SERIAL_STOPBITS:
case IDC_SERIAL_FLOWCONTROL:
if (HIWORD(wParam) == CBN_SELCHANGE ||
HIWORD(wParam) == CBN_EDITCHANGE)
{
pPortData->bChanged = TRUE;
}
break;
// case IDC_SERIAL_ADVANCED:
case IDC_SERIAL_RESTORE:
RestoreDefaultValues(hwnd, pPortData);
break;
default:
break;
}
}
static
VOID
OnNotify(
HWND hwnd,
WPARAM wParam,
LPARAM lParam)
{
PPORT_DATA pPortData;
TRACE("OnCommand()\n");
pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
if (pPortData == NULL)
{
ERR("pPortData is NULL\n");
return;
}
if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
{
FIXME("PSN_APPLY!\n");
WritePortSettings(hwnd, pPortData);
}
}
static
VOID
OnDestroy(
HWND hwnd)
{
PPORT_DATA pPortData;
TRACE("OnDestroy()\n");
pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
if (pPortData == NULL)
{
ERR("pPortData is NULL\n");
return;
}
HeapFree(GetProcessHeap(), 0, pPortData);
SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)NULL);
}
static
INT_PTR
CALLBACK
SerialSettingsDlgProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
TRACE("SerialSettingsDlgProc()\n");
switch (uMsg)
{
case WM_INITDIALOG:
return OnInitDialog(hwnd, wParam, lParam);
case WM_COMMAND:
OnCommand(hwnd, wParam, lParam);
break;
case WM_NOTIFY:
OnNotify(hwnd, wParam, lParam);
break;
case WM_DESTROY:
OnDestroy(hwnd);
break;
}
return FALSE;
}
BOOL
WINAPI
SerialPortPropPageProvider(
PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,
LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
LPARAM lParam)
{
PROPSHEETPAGEW PropSheetPage;
HPROPSHEETPAGE hPropSheetPage;
PPORT_DATA pPortData;
TRACE("SerialPortPropPageProvider(%p %p %lx)\n",
lpPropSheetPageRequest, lpfnAddPropSheetPageProc, lParam);
pPortData = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(PORT_DATA));
if (pPortData == NULL)
{
ERR("Port data allocation failed!\n");
return FALSE;
}
pPortData->DeviceInfoSet = lpPropSheetPageRequest->DeviceInfoSet;
pPortData->DeviceInfoData = lpPropSheetPageRequest->DeviceInfoData;
if (lpPropSheetPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES)
{
TRACE("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n");
PropSheetPage.dwSize = sizeof(PROPSHEETPAGEW);
PropSheetPage.dwFlags = 0;
PropSheetPage.hInstance = hInstance;
PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SERIALSETTINGS);
PropSheetPage.pfnDlgProc = SerialSettingsDlgProc;
PropSheetPage.lParam = (LPARAM)pPortData;
PropSheetPage.pfnCallback = NULL;
hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage);
if (hPropSheetPage == NULL)
{
ERR("CreatePropertySheetPageW() failed!\n");
return FALSE;
}
if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam))
{
ERR("lpfnAddPropSheetPageProc() failed!\n");
DestroyPropertySheetPage(hPropSheetPage);
return FALSE;
}
}
TRACE("Done!\n");
return TRUE;
}
/* EOF */