xref: /reactos/dll/win32/msports/parallel.c (revision 7eead935)
1 /*
2  * PROJECT:     Ports installer library
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        dll\win32\msports\parallel.c
5  * PURPOSE:     Parallel Port property functions
6  * COPYRIGHT:   Copyright 2013 Eric Kohl
7  */
8 
9 #include "precomp.h"
10 
11 
12 typedef struct _PORT_DATA
13 {
14     HDEVINFO DeviceInfoSet;
15     PSP_DEVINFO_DATA DeviceInfoData;
16 
17     WCHAR szPortName[16];
18     DWORD dwPortNumber;
19     DWORD dwFilterResourceMethod;
20     DWORD dwLegacy;
21 
22 } PORT_DATA, *PPORT_DATA;
23 
24 
25 static
26 VOID
27 GetUsedPorts(
28     PDWORD pPortMap)
29 {
30     WCHAR szDeviceName[64];
31     WCHAR szDosDeviceName[64];
32     DWORD dwIndex, dwType, dwPortNumber;
33     DWORD dwDeviceNameSize, dwDosDeviceNameSize;
34     PWSTR ptr;
35     HKEY hKey;
36     DWORD dwError;
37 
38     *pPortMap = 0;
39 
40     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
41                             L"Hardware\\DeviceMap\\PARALLEL PORTS",
42                             0,
43                             KEY_READ,
44                             &hKey);
45     if (dwError == ERROR_SUCCESS)
46     {
47         for (dwIndex = 0; ; dwIndex++)
48         {
49             dwDeviceNameSize = ARRAYSIZE(szDeviceName);
50             dwDosDeviceNameSize = sizeof(szDosDeviceName);
51             dwError = RegEnumValueW(hKey,
52                                     dwIndex,
53                                     szDeviceName,
54                                     &dwDeviceNameSize,
55                                     NULL,
56                                     &dwType,
57                                     (LPBYTE)szDosDeviceName,
58                                     &dwDosDeviceNameSize);
59             if (dwError != ERROR_SUCCESS)
60                 break;
61 
62             if (dwType == REG_SZ)
63             {
64                 TRACE("%S --> %S\n", szDeviceName, szDosDeviceName);
65                 if (_wcsnicmp(szDosDeviceName, L"\\DosDevices\\LPT", wcslen(L"\\DosDevices\\LPT")) == 0)
66                 {
67                      ptr = szDosDeviceName + wcslen(L"\\DosDevices\\LPT");
68                      if (wcschr(ptr, L'.') == NULL)
69                      {
70                          TRACE("Device number %S\n", ptr);
71                          dwPortNumber = wcstoul(ptr, NULL, 10);
72                          if (dwPortNumber != 0)
73                          {
74                              *pPortMap |=(1 << dwPortNumber);
75                          }
76                      }
77                 }
78             }
79         }
80 
81         RegCloseKey(hKey);
82     }
83 
84     TRACE("Done\n");
85 }
86 
87 
88 static
89 VOID
90 ReadPortSettings(
91     PPORT_DATA pPortData)
92 {
93     DWORD dwSize;
94     HKEY hKey;
95     DWORD dwError;
96 
97     TRACE("ReadPortSettings(%p)\n", pPortData);
98 
99     pPortData->dwFilterResourceMethod = 1; /* Never use an interrupt */
100     pPortData->dwLegacy = 0;               /* Disabled */
101     pPortData->dwPortNumber = 0;           /* Unknown */
102 
103     hKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet,
104                                 pPortData->DeviceInfoData,
105                                 DICS_FLAG_GLOBAL,
106                                 0,
107                                 DIREG_DEV,
108                                 KEY_READ);
109     if (hKey != INVALID_HANDLE_VALUE)
110     {
111         dwSize = sizeof(pPortData->szPortName);
112         dwError = RegQueryValueExW(hKey,
113                                    L"PortName",
114                                    NULL,
115                                    NULL,
116                                   (PBYTE)pPortData->szPortName,
117                                   &dwSize);
118         if (dwError != ERROR_SUCCESS)
119         {
120             ERR("RegQueryValueExW failed (Error %lu)\n", dwError);
121         }
122 
123         dwSize = sizeof(pPortData->dwFilterResourceMethod);
124         dwError = RegQueryValueExW(hKey,
125                                    L"FilterResourceMethod",
126                                    NULL,
127                                    NULL,
128                                    (PBYTE)&pPortData->dwFilterResourceMethod,
129                                    &dwSize);
130         if (dwError != ERROR_SUCCESS)
131         {
132             ERR("RegQueryValueExW failed (Error %lu)\n", dwError);
133         }
134 
135         RegCloseKey(hKey);
136     }
137 
138     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
139                             L"SYSTEM\\CurrentControlSet\\Services\\Parport\\Parameters",
140                             0,
141                             KEY_READ,
142                             &hKey);
143     if (dwError == ERROR_SUCCESS)
144     {
145         dwSize = sizeof(pPortData->dwLegacy);
146         dwError = RegQueryValueExW(hKey,
147                                    L"ParEnableLegacyZip",
148                                    NULL,
149                                    NULL,
150                                    (PBYTE)&pPortData->dwLegacy,
151                                    &dwSize);
152         if (dwError != ERROR_SUCCESS)
153         {
154             ERR("RegQueryValueExW failed (Error %lu)\n", dwError);
155         }
156 
157         RegCloseKey(hKey);
158     }
159 }
160 
161 
162 static
163 DWORD
164 ChangePortNumber(
165     _In_ PPORT_DATA pPortData,
166     _In_ DWORD dwNewPortNumber)
167 {
168     WCHAR szDeviceDescription[256];
169     WCHAR szFriendlyName[256];
170     WCHAR szNewPortName[16];
171     HKEY hDeviceKey = INVALID_HANDLE_VALUE;
172     DWORD dwError;
173 
174     /* We are done if old and new port number are the same */
175     if (pPortData->dwPortNumber == dwNewPortNumber)
176         return ERROR_SUCCESS;
177 
178     /* Build the new port name */
179     swprintf(szNewPortName, L"LPT%lu", dwNewPortNumber);
180 
181     /* Open the devices hardware key */
182     hDeviceKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet,
183                                       pPortData->DeviceInfoData,
184                                       DICS_FLAG_GLOBAL,
185                                       0,
186                                       DIREG_DEV,
187                                       KEY_READ | KEY_WRITE);
188     if (hDeviceKey == INVALID_HANDLE_VALUE)
189     {
190         return GetLastError();
191     }
192 
193     /* Set the new 'PortName' value */
194     dwError = RegSetValueExW(hDeviceKey,
195                              L"PortName",
196                              0,
197                              REG_SZ,
198                              (LPBYTE)szNewPortName,
199                              (wcslen(szNewPortName) + 1) * sizeof(WCHAR));
200     if (dwError != ERROR_SUCCESS)
201         goto done;
202 
203     /* Save the new port name and number */
204     wcscpy(pPortData->szPortName, szNewPortName);
205     pPortData->dwPortNumber = dwNewPortNumber;
206 
207     /* Get the device description... */
208     if (SetupDiGetDeviceRegistryProperty(pPortData->DeviceInfoSet,
209                                          pPortData->DeviceInfoData,
210                                          SPDRP_DEVICEDESC,
211                                          NULL,
212                                          (PBYTE)szDeviceDescription,
213                                          sizeof(szDeviceDescription),
214                                          NULL))
215     {
216         /* ... and use it to build a new friendly name */
217         swprintf(szFriendlyName,
218                  L"%s (%s)",
219                  szDeviceDescription,
220                  szNewPortName);
221     }
222     else
223     {
224         /* ... or build a generic friendly name */
225         swprintf(szFriendlyName,
226                  L"Parallel Port (%s)",
227                  szNewPortName);
228     }
229 
230     /* Set the friendly name for the device */
231     SetupDiSetDeviceRegistryProperty(pPortData->DeviceInfoSet,
232                                      pPortData->DeviceInfoData,
233                                      SPDRP_FRIENDLYNAME,
234                                      (PBYTE)szFriendlyName,
235                                      (wcslen(szFriendlyName) + 1) * sizeof(WCHAR));
236 
237 done:
238     if (hDeviceKey != INVALID_HANDLE_VALUE)
239         RegCloseKey(hDeviceKey);
240 
241     return dwError;
242 }
243 
244 
245 static
246 VOID
247 WritePortSettings(
248     HWND hwnd,
249     PPORT_DATA pPortData)
250 {
251     DWORD dwDisposition;
252     DWORD dwFilterResourceMethod;
253     DWORD dwLegacy;
254     DWORD dwPortNumber;
255     DWORD dwPortMap;
256     HKEY hKey;
257     DWORD dwError;
258 
259     TRACE("WritePortSettings(%p)\n", pPortData);
260 
261     dwFilterResourceMethod = 1;
262     if (Button_GetCheck(GetDlgItem(hwnd, IDC_TRY_INTERRUPT)) == BST_CHECKED)
263         dwFilterResourceMethod = 0;
264     else if (Button_GetCheck(GetDlgItem(hwnd, IDC_NEVER_INTERRUPT)) == BST_CHECKED)
265         dwFilterResourceMethod = 1;
266     else if (Button_GetCheck(GetDlgItem(hwnd, IDC_ANY_INTERRUPT)) == BST_CHECKED)
267         dwFilterResourceMethod = 2;
268 
269     if (dwFilterResourceMethod != pPortData->dwFilterResourceMethod)
270     {
271         hKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet,
272                                     pPortData->DeviceInfoData,
273                                     DICS_FLAG_GLOBAL,
274                                     0,
275                                     DIREG_DEV,
276                                     KEY_WRITE);
277         if (hKey != INVALID_HANDLE_VALUE)
278         {
279             dwError = RegSetValueExW(hKey,
280                                      L"FilterResourceMethod",
281                                      0,
282                                      REG_DWORD,
283                                      (PBYTE)&dwFilterResourceMethod,
284                                      sizeof(dwFilterResourceMethod));
285             if (dwError != ERROR_SUCCESS)
286             {
287                 ERR("RegSetValueExW failed (Error %lu)\n", dwError);
288             }
289 
290             RegCloseKey(hKey);
291             pPortData->dwFilterResourceMethod = dwFilterResourceMethod;
292         }
293     }
294 
295     dwLegacy = 0;
296     if (Button_GetCheck(GetDlgItem(hwnd, IDC_PARALLEL_LEGACY)) == BST_CHECKED)
297         dwLegacy = 1;
298 
299     if (dwLegacy != pPortData->dwLegacy)
300     {
301         dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
302                                   L"SYSTEM\\CurrentControlSet\\Services\\Parport\\Parameters",
303                                   0,
304                                   NULL,
305                                   REG_OPTION_NON_VOLATILE,
306                                   KEY_WRITE,
307                                   NULL,
308                                   &hKey,
309                                   &dwDisposition);
310         if (dwError == ERROR_SUCCESS)
311         {
312             dwError = RegSetValueExW(hKey,
313                                      L"ParEnableLegacyZip",
314                                      0,
315                                      REG_DWORD,
316                                      (LPBYTE)&dwLegacy,
317                                      sizeof(dwLegacy));
318             RegCloseKey(hKey);
319 
320             if (dwError == ERROR_SUCCESS)
321             {
322                 FIXME("Notify the driver!\n");
323 
324                 pPortData->dwLegacy = dwLegacy;
325             }
326         }
327     }
328 
329     dwPortNumber = ComboBox_GetCurSel(GetDlgItem(hwnd, IDC_PARALLEL_NAME));
330     if (dwPortNumber != LB_ERR)
331     {
332         dwPortNumber++;
333         if (dwPortNumber != pPortData->dwPortNumber)
334         {
335             GetUsedPorts(&dwPortMap);
336 
337             if (dwPortMap & 1 << dwPortNumber)
338             {
339                 ERR("Port LPT%lu is already in use!\n", dwPortNumber);
340                 return;
341             }
342 
343             ChangePortNumber(pPortData,
344                              dwPortNumber);
345         }
346     }
347 }
348 
349 
350 static
351 BOOL
352 OnInitDialog(HWND hwnd,
353              WPARAM wParam,
354              LPARAM lParam)
355 {
356     WCHAR szBuffer[256];
357     WCHAR szPortInUse[64];
358     PPORT_DATA pPortData;
359     HWND hwndControl;
360     DWORD dwPortMap;
361     UINT i;
362 
363     TRACE("OnInitDialog()\n");
364 
365     pPortData = (PPORT_DATA)((LPPROPSHEETPAGEW)lParam)->lParam;
366     if (pPortData == NULL)
367     {
368         ERR("pPortData is NULL\n");
369         return FALSE;
370     }
371 
372     SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPortData);
373 
374     /* Read and parse the port settings */
375     ReadPortSettings(pPortData);
376 
377     /* Set the 'Filter Resource Method' radiobuttons */
378     hwndControl = GetDlgItem(hwnd,
379                              IDC_TRY_INTERRUPT + pPortData->dwFilterResourceMethod);
380     if (hwndControl)
381         Button_SetCheck(hwndControl, BST_CHECKED);
382 
383     /* Disable the 'Enable legacy PNP detection' checkbox */
384     hwndControl = GetDlgItem(hwnd, IDC_PARALLEL_LEGACY);
385     if (hwndControl)
386     {
387         Button_SetCheck(GetDlgItem(hwnd, IDC_PARALLEL_LEGACY),
388                         pPortData->dwLegacy ? BST_CHECKED : BST_UNCHECKED);
389     }
390 
391     LoadStringW(hInstance, IDS_PORT_IN_USE, szPortInUse, ARRAYSIZE(szPortInUse));
392 
393     /* Fill the 'LPT Port Number' combobox */
394     hwndControl = GetDlgItem(hwnd, IDC_PARALLEL_NAME);
395     if (hwndControl)
396     {
397         GetUsedPorts(&dwPortMap);
398 
399         for (i = 1; i < 4; i++)
400         {
401             swprintf(szBuffer, L"LPT%lu", i);
402 
403             if ((dwPortMap & (1 << i)) && (pPortData->dwPortNumber != i))
404                 wcscat(szBuffer, szPortInUse);
405 
406             ComboBox_AddString(hwndControl, szBuffer);
407 
408             if (_wcsicmp(pPortData->szPortName, szBuffer) == 0)
409                 pPortData->dwPortNumber = i;
410         }
411 
412         if (pPortData->dwPortNumber != 0)
413         {
414             ComboBox_SetCurSel(hwndControl, pPortData->dwPortNumber - 1);
415         }
416     }
417 
418     return TRUE;
419 }
420 
421 
422 static
423 VOID
424 OnNotify(
425     HWND hwnd,
426     WPARAM wParam,
427     LPARAM lParam)
428 {
429     PPORT_DATA pPortData;
430 
431     TRACE("OnNotify()\n");
432 
433     pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
434     if (pPortData == NULL)
435     {
436         ERR("pPortData is NULL\n");
437         return;
438     }
439 
440     if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
441     {
442         TRACE("PSN_APPLY!\n");
443         WritePortSettings(hwnd, pPortData);
444     }
445 }
446 
447 
448 static
449 VOID
450 OnDestroy(
451     HWND hwnd)
452 {
453     PPORT_DATA pPortData;
454 
455     TRACE("OnDestroy()\n");
456 
457     pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
458     if (pPortData == NULL)
459     {
460         ERR("pPortData is NULL\n");
461         return;
462     }
463 
464     HeapFree(GetProcessHeap(), 0, pPortData);
465     SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)NULL);
466 }
467 
468 
469 static
470 INT_PTR
471 CALLBACK
472 ParallelSettingsDlgProc(HWND hwnd,
473                         UINT uMsg,
474                         WPARAM wParam,
475                         LPARAM lParam)
476 {
477     TRACE("ParallelSettingsDlgProc()\n");
478 
479     switch (uMsg)
480     {
481         case WM_INITDIALOG:
482             return OnInitDialog(hwnd, wParam, lParam);
483 
484         case WM_NOTIFY:
485             OnNotify(hwnd, wParam, lParam);
486             break;
487 
488         case WM_DESTROY:
489             OnDestroy(hwnd);
490             break;
491     }
492 
493     return FALSE;
494 }
495 
496 
497 BOOL
498 WINAPI
499 ParallelPortPropPageProvider(PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,
500                              LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
501                              LPARAM lParam)
502 {
503     PROPSHEETPAGEW PropSheetPage;
504     HPROPSHEETPAGE hPropSheetPage;
505     PPORT_DATA pPortData;
506 
507     TRACE("ParallelPortPropPageProvider(%p %p %lx)\n",
508           lpPropSheetPageRequest, lpfnAddPropSheetPageProc, lParam);
509 
510     pPortData = HeapAlloc(GetProcessHeap(),
511                           HEAP_ZERO_MEMORY,
512                           sizeof(PORT_DATA));
513     if (pPortData == NULL)
514     {
515         ERR("Port data allocation failed!\n");
516         return FALSE;
517     }
518 
519     pPortData->DeviceInfoSet = lpPropSheetPageRequest->DeviceInfoSet;
520     pPortData->DeviceInfoData = lpPropSheetPageRequest->DeviceInfoData;
521 
522     if (lpPropSheetPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES)
523     {
524         TRACE("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n");
525 
526         PropSheetPage.dwSize = sizeof(PROPSHEETPAGEW);
527         PropSheetPage.dwFlags = 0;
528         PropSheetPage.hInstance = hInstance;
529         PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PARALLELSETTINGS);
530         PropSheetPage.pfnDlgProc = ParallelSettingsDlgProc;
531         PropSheetPage.lParam = (LPARAM)pPortData;
532         PropSheetPage.pfnCallback = NULL;
533 
534         hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage);
535         if (hPropSheetPage == NULL)
536         {
537             ERR("CreatePropertySheetPageW() failed!\n");
538             return FALSE;
539         }
540 
541         if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam))
542         {
543             ERR("lpfnAddPropSheetPageProc() failed!\n");
544             DestroyPropertySheetPage(hPropSheetPage);
545             return FALSE;
546         }
547     }
548 
549     TRACE("Done!\n");
550 
551     return TRUE;
552 }
553 
554 /* EOF */
555