[MSPORTS] When the LPT port number gets changed, update the PortName and FriendlyName...
[reactos.git] / dll / win32 / msports / parallel.c
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 */