xref: /reactos/dll/win32/msports/parallel.c (revision d6eebaa4)
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     SP_PROPCHANGE_PARAMS PropChangeParams;
252     DWORD dwDisposition;
253     DWORD dwFilterResourceMethod;
254     DWORD dwLegacy;
255     DWORD dwPortNumber;
256     DWORD dwPortMap;
257     HKEY hKey;
258     BOOL bChanged = FALSE;
259     DWORD dwError;
260 
261     TRACE("WritePortSettings(%p)\n", pPortData);
262 
263     dwFilterResourceMethod = 1;
264     if (Button_GetCheck(GetDlgItem(hwnd, IDC_TRY_INTERRUPT)) == BST_CHECKED)
265         dwFilterResourceMethod = 0;
266     else if (Button_GetCheck(GetDlgItem(hwnd, IDC_NEVER_INTERRUPT)) == BST_CHECKED)
267         dwFilterResourceMethod = 1;
268     else if (Button_GetCheck(GetDlgItem(hwnd, IDC_ANY_INTERRUPT)) == BST_CHECKED)
269         dwFilterResourceMethod = 2;
270 
271     if (dwFilterResourceMethod != pPortData->dwFilterResourceMethod)
272     {
273         hKey = SetupDiOpenDevRegKey(pPortData->DeviceInfoSet,
274                                     pPortData->DeviceInfoData,
275                                     DICS_FLAG_GLOBAL,
276                                     0,
277                                     DIREG_DEV,
278                                     KEY_WRITE);
279         if (hKey != INVALID_HANDLE_VALUE)
280         {
281             dwError = RegSetValueExW(hKey,
282                                      L"FilterResourceMethod",
283                                      0,
284                                      REG_DWORD,
285                                      (PBYTE)&dwFilterResourceMethod,
286                                      sizeof(dwFilterResourceMethod));
287             RegCloseKey(hKey);
288             if (dwError == ERROR_SUCCESS)
289             {
290                 pPortData->dwFilterResourceMethod = dwFilterResourceMethod;
291                 bChanged = TRUE;
292             }
293         }
294     }
295 
296     dwLegacy = 0;
297     if (Button_GetCheck(GetDlgItem(hwnd, IDC_PARALLEL_LEGACY)) == BST_CHECKED)
298         dwLegacy = 1;
299 
300     if (dwLegacy != pPortData->dwLegacy)
301     {
302         dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
303                                   L"SYSTEM\\CurrentControlSet\\Services\\Parport\\Parameters",
304                                   0,
305                                   NULL,
306                                   REG_OPTION_NON_VOLATILE,
307                                   KEY_WRITE,
308                                   NULL,
309                                   &hKey,
310                                   &dwDisposition);
311         if (dwError == ERROR_SUCCESS)
312         {
313             dwError = RegSetValueExW(hKey,
314                                      L"ParEnableLegacyZip",
315                                      0,
316                                      REG_DWORD,
317                                      (LPBYTE)&dwLegacy,
318                                      sizeof(dwLegacy));
319             RegCloseKey(hKey);
320 
321             if (dwError == ERROR_SUCCESS)
322             {
323                 pPortData->dwLegacy = dwLegacy;
324                 bChanged = TRUE;
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             }
341             else
342             {
343                 ChangePortNumber(pPortData,
344                                  dwPortNumber);
345                 bChanged = TRUE;
346             }
347         }
348     }
349 
350     if (bChanged)
351     {
352         /* Notify the system */
353         PostMessageW(HWND_BROADCAST,
354                      WM_WININICHANGE,
355                      0,
356                      (LPARAM)pPortData->szPortName);
357 
358         /* Notify the installer (and device) */
359         PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
360         PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
361         PropChangeParams.Scope = DICS_FLAG_GLOBAL;
362         PropChangeParams.StateChange = DICS_PROPCHANGE;
363 
364         SetupDiSetClassInstallParams(pPortData->DeviceInfoSet,
365                                      pPortData->DeviceInfoData,
366                                      (PSP_CLASSINSTALL_HEADER)&PropChangeParams,
367                                      sizeof(SP_PROPCHANGE_PARAMS));
368 
369         SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
370                                   pPortData->DeviceInfoSet,
371                                   pPortData->DeviceInfoData);
372     }
373 }
374 
375 
376 static
377 BOOL
378 OnInitDialog(HWND hwnd,
379              WPARAM wParam,
380              LPARAM lParam)
381 {
382     WCHAR szBuffer[256];
383     WCHAR szPortInUse[64];
384     PPORT_DATA pPortData;
385     HWND hwndControl;
386     DWORD dwPortMap;
387     UINT i;
388 
389     TRACE("OnInitDialog()\n");
390 
391     pPortData = (PPORT_DATA)((LPPROPSHEETPAGEW)lParam)->lParam;
392     if (pPortData == NULL)
393     {
394         ERR("pPortData is NULL\n");
395         return FALSE;
396     }
397 
398     SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pPortData);
399 
400     /* Read and parse the port settings */
401     ReadPortSettings(pPortData);
402 
403     /* Set the 'Filter Resource Method' radiobuttons */
404     hwndControl = GetDlgItem(hwnd,
405                              IDC_TRY_INTERRUPT + pPortData->dwFilterResourceMethod);
406     if (hwndControl)
407         Button_SetCheck(hwndControl, BST_CHECKED);
408 
409     /* Disable the 'Enable legacy PNP detection' checkbox */
410     hwndControl = GetDlgItem(hwnd, IDC_PARALLEL_LEGACY);
411     if (hwndControl)
412     {
413         Button_SetCheck(GetDlgItem(hwnd, IDC_PARALLEL_LEGACY),
414                         pPortData->dwLegacy ? BST_CHECKED : BST_UNCHECKED);
415     }
416 
417     LoadStringW(hInstance, IDS_PORT_IN_USE, szPortInUse, ARRAYSIZE(szPortInUse));
418 
419     /* Fill the 'LPT Port Number' combobox */
420     hwndControl = GetDlgItem(hwnd, IDC_PARALLEL_NAME);
421     if (hwndControl)
422     {
423         GetUsedPorts(&dwPortMap);
424 
425         for (i = 1; i < 4; i++)
426         {
427             swprintf(szBuffer, L"LPT%lu", i);
428 
429             if ((dwPortMap & (1 << i)) && (pPortData->dwPortNumber != i))
430                 wcscat(szBuffer, szPortInUse);
431 
432             ComboBox_AddString(hwndControl, szBuffer);
433 
434             if (_wcsicmp(pPortData->szPortName, szBuffer) == 0)
435                 pPortData->dwPortNumber = i;
436         }
437 
438         if (pPortData->dwPortNumber != 0)
439         {
440             ComboBox_SetCurSel(hwndControl, pPortData->dwPortNumber - 1);
441         }
442     }
443 
444     return TRUE;
445 }
446 
447 
448 static
449 VOID
450 OnNotify(
451     HWND hwnd,
452     WPARAM wParam,
453     LPARAM lParam)
454 {
455     PPORT_DATA pPortData;
456 
457     TRACE("OnNotify()\n");
458 
459     pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
460     if (pPortData == NULL)
461     {
462         ERR("pPortData is NULL\n");
463         return;
464     }
465 
466     if (((LPNMHDR)lParam)->code == (UINT)PSN_APPLY)
467     {
468         TRACE("PSN_APPLY!\n");
469         WritePortSettings(hwnd, pPortData);
470     }
471 }
472 
473 
474 static
475 VOID
476 OnDestroy(
477     HWND hwnd)
478 {
479     PPORT_DATA pPortData;
480 
481     TRACE("OnDestroy()\n");
482 
483     pPortData = (PPORT_DATA)GetWindowLongPtr(hwnd, DWLP_USER);
484     if (pPortData == NULL)
485     {
486         ERR("pPortData is NULL\n");
487         return;
488     }
489 
490     HeapFree(GetProcessHeap(), 0, pPortData);
491     SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)NULL);
492 }
493 
494 
495 static
496 INT_PTR
497 CALLBACK
498 ParallelSettingsDlgProc(HWND hwnd,
499                         UINT uMsg,
500                         WPARAM wParam,
501                         LPARAM lParam)
502 {
503     TRACE("ParallelSettingsDlgProc()\n");
504 
505     switch (uMsg)
506     {
507         case WM_INITDIALOG:
508             return OnInitDialog(hwnd, wParam, lParam);
509 
510         case WM_NOTIFY:
511             OnNotify(hwnd, wParam, lParam);
512             break;
513 
514         case WM_DESTROY:
515             OnDestroy(hwnd);
516             break;
517     }
518 
519     return FALSE;
520 }
521 
522 
523 BOOL
524 WINAPI
525 ParallelPortPropPageProvider(PSP_PROPSHEETPAGE_REQUEST lpPropSheetPageRequest,
526                              LPFNADDPROPSHEETPAGE lpfnAddPropSheetPageProc,
527                              LPARAM lParam)
528 {
529     PROPSHEETPAGEW PropSheetPage;
530     HPROPSHEETPAGE hPropSheetPage;
531     PPORT_DATA pPortData;
532 
533     TRACE("ParallelPortPropPageProvider(%p %p %lx)\n",
534           lpPropSheetPageRequest, lpfnAddPropSheetPageProc, lParam);
535 
536     pPortData = HeapAlloc(GetProcessHeap(),
537                           HEAP_ZERO_MEMORY,
538                           sizeof(PORT_DATA));
539     if (pPortData == NULL)
540     {
541         ERR("Port data allocation failed!\n");
542         return FALSE;
543     }
544 
545     pPortData->DeviceInfoSet = lpPropSheetPageRequest->DeviceInfoSet;
546     pPortData->DeviceInfoData = lpPropSheetPageRequest->DeviceInfoData;
547 
548     if (lpPropSheetPageRequest->PageRequested == SPPSR_ENUM_ADV_DEVICE_PROPERTIES)
549     {
550         TRACE("SPPSR_ENUM_ADV_DEVICE_PROPERTIES\n");
551 
552         PropSheetPage.dwSize = sizeof(PROPSHEETPAGEW);
553         PropSheetPage.dwFlags = 0;
554         PropSheetPage.hInstance = hInstance;
555         PropSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_PARALLELSETTINGS);
556         PropSheetPage.pfnDlgProc = ParallelSettingsDlgProc;
557         PropSheetPage.lParam = (LPARAM)pPortData;
558         PropSheetPage.pfnCallback = NULL;
559 
560         hPropSheetPage = CreatePropertySheetPageW(&PropSheetPage);
561         if (hPropSheetPage == NULL)
562         {
563             ERR("CreatePropertySheetPageW() failed!\n");
564             return FALSE;
565         }
566 
567         if (!(*lpfnAddPropSheetPageProc)(hPropSheetPage, lParam))
568         {
569             ERR("lpfnAddPropSheetPageProc() failed!\n");
570             DestroyPropertySheetPage(hPropSheetPage);
571             return FALSE;
572         }
573     }
574 
575     TRACE("Done!\n");
576 
577     return TRUE;
578 }
579 
580 /* EOF */
581