[msports] Notify the system of changes to the serial port settings.
[reactos.git] / dll / win32 / msports / serial.c
index b4d3d6c..768fedf 100644 (file)
 
 #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)
+{
+    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);
+
+    TRACE("Done!\n");
+}
+
+
 static
 BOOL
-OnInitDialog(HWND hwnd,
-             WPARAM wParam,
-             LPARAM lParam)
+OnInitDialog(
+    HWND hwnd,
+    WPARAM wParam,
+    LPARAM lParam)
 {
-    FIXME("Port_OnInit()\n");
+    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
@@ -27,12 +569,24 @@ SerialSettingsDlgProc(HWND hwnd,
                       WPARAM wParam,
                       LPARAM lParam)
 {
-    FIXME("SerialSettingsDlgProc()\n");
+    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;
@@ -41,44 +595,58 @@ SerialSettingsDlgProc(HWND hwnd,
 
 BOOL
 WINAPI
-SerialPortPropPageProvider(PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,
-                           LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
-                           LPARAM lParam)
+SerialPortPropPageProvider(
+    PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,
+    LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
+    LPARAM lParam)
 {
     PROPSHEETPAGEW PropSheetPage;
     HPROPSHEETPAGE hPropSheetPage;
+    PPORT_DATA pPortData;
 
-    FIXME("SerialPortPropPageProvider(%p %p %lx)\n",
+    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)
     {
-        FIXME("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n");
+        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 = 0;
+        PropSheetPage.lParam = (LPARAM)pPortData;
         PropSheetPage.pfnCallback = NULL;
 
         hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage);
         if (hPropSheetPage == NULL)
         {
-            FIXME("CreatePropertySheetPageW() failed!\n");
+            ERR("CreatePropertySheetPageW() failed!\n");
             return FALSE;
         }
 
         if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam))
         {
-            FIXME("lpfnAddPropSheetPageProc() failed!\n");
+            ERR("lpfnAddPropSheetPageProc() failed!\n");
             DestroyPropertySheetPage(hPropSheetPage);
             return FALSE;
         }
     }
 
-    FIXME("Done!\n");
+    TRACE("Done!\n");
 
     return TRUE;
 }