1 /*
2 * PROJECT: Ports installer library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll\win32\msports\comdb.c
5 * PURPOSE: COM port database
6 * COPYRIGHT: Copyright 2011 Eric Kohl
7 */
8
9 #include "precomp.h"
10
11 #define BITS_PER_BYTE 8
12 #define BITMAP_SIZE_INCREMENT 0x400
13 #define BITMAP_SIZE_INVALID_BITS 0x3FF
14
15 typedef struct _COMDB
16 {
17 HANDLE hMutex;
18 HKEY hKey;
19 } COMDB, *PCOMDB;
20
21
22 LONG
23 WINAPI
ComDBClaimNextFreePort(IN HCOMDB hComDB,OUT LPDWORD ComNumber)24 ComDBClaimNextFreePort(IN HCOMDB hComDB,
25 OUT LPDWORD ComNumber)
26 {
27 PCOMDB pComDB;
28 DWORD dwBitIndex;
29 DWORD dwByteIndex;
30 DWORD dwSize;
31 DWORD dwType;
32 PBYTE pBitmap = NULL;
33 BYTE cMask;
34 LONG lError;
35
36 TRACE("ComDBClaimNextFreePort(%p %p)\n", hComDB, ComNumber);
37
38 if (hComDB == INVALID_HANDLE_VALUE ||
39 hComDB == NULL ||
40 ComNumber == NULL)
41 return ERROR_INVALID_PARAMETER;
42
43 pComDB = (PCOMDB)hComDB;
44
45 /* Wait for the mutex */
46 WaitForSingleObject(pComDB->hMutex, INFINITE);
47
48 /* Get the required bitmap size */
49 lError = RegQueryValueExW(pComDB->hKey,
50 L"ComDB",
51 NULL,
52 &dwType,
53 NULL,
54 &dwSize);
55 if (lError != ERROR_SUCCESS)
56 {
57 ERR("Failed to query the bitmap size!\n");
58 goto done;
59 }
60
61 /* Allocate the bitmap */
62 pBitmap = HeapAlloc(GetProcessHeap(),
63 HEAP_ZERO_MEMORY,
64 dwSize);
65 if (pBitmap == NULL)
66 {
67 ERR("Failed to allocate the bitmap!\n");
68 lError = ERROR_NOT_ENOUGH_MEMORY;
69 goto done;
70 }
71
72 /* Read the bitmap */
73 lError = RegQueryValueExW(pComDB->hKey,
74 L"ComDB",
75 NULL,
76 &dwType,
77 pBitmap,
78 &dwSize);
79 if (lError != ERROR_SUCCESS)
80 goto done;
81
82 lError = ERROR_INVALID_PARAMETER;
83 for (dwBitIndex = 0; dwBitIndex < (dwSize * BITS_PER_BYTE); dwBitIndex++)
84 {
85 /* Calculate the byte index and a mask for the affected bit */
86 dwByteIndex = dwBitIndex / BITS_PER_BYTE;
87 cMask = 1 << (dwBitIndex % BITS_PER_BYTE);
88
89 if ((pBitmap[dwByteIndex] & cMask) == 0)
90 {
91 pBitmap[dwByteIndex] |= cMask;
92 *ComNumber = dwBitIndex + 1;
93 lError = ERROR_SUCCESS;
94 break;
95 }
96 }
97
98 /* Save the bitmap if it was modified */
99 if (lError == ERROR_SUCCESS)
100 {
101 lError = RegSetValueExW(pComDB->hKey,
102 L"ComDB",
103 0,
104 REG_BINARY,
105 pBitmap,
106 dwSize);
107 }
108
109 done:;
110 /* Release the mutex */
111 ReleaseMutex(pComDB->hMutex);
112
113 /* Release the bitmap */
114 if (pBitmap != NULL)
115 HeapFree(GetProcessHeap(), 0, pBitmap);
116
117 return lError;
118 }
119
120
121 LONG
122 WINAPI
ComDBClaimPort(IN HCOMDB hComDB,IN DWORD ComNumber,IN BOOL ForceClaim,OUT PBOOL Forced)123 ComDBClaimPort(IN HCOMDB hComDB,
124 IN DWORD ComNumber,
125 IN BOOL ForceClaim,
126 OUT PBOOL Forced)
127 {
128 PCOMDB pComDB;
129 DWORD dwBitIndex;
130 DWORD dwByteIndex;
131 DWORD dwType;
132 DWORD dwSize;
133 PBYTE pBitmap = NULL;
134 BYTE cMask;
135 LONG lError;
136
137 TRACE("ComDBClaimPort(%p %lu)\n", hComDB, ComNumber);
138
139 if (hComDB == INVALID_HANDLE_VALUE ||
140 hComDB == NULL ||
141 ComNumber == 0 ||
142 ComNumber > COMDB_MAX_PORTS_ARBITRATED)
143 return ERROR_INVALID_PARAMETER;
144
145 pComDB = (PCOMDB)hComDB;
146
147 /* Wait for the mutex */
148 WaitForSingleObject(pComDB->hMutex, INFINITE);
149
150 /* Get the required bitmap size */
151 lError = RegQueryValueExW(pComDB->hKey,
152 L"ComDB",
153 NULL,
154 &dwType,
155 NULL,
156 &dwSize);
157 if (lError != ERROR_SUCCESS)
158 {
159 ERR("Failed to query the bitmap size!\n");
160 goto done;
161 }
162
163 /* Allocate the bitmap */
164 pBitmap = HeapAlloc(GetProcessHeap(),
165 HEAP_ZERO_MEMORY,
166 dwSize);
167 if (pBitmap == NULL)
168 {
169 ERR("Failed to allocate the bitmap!\n");
170 lError = ERROR_NOT_ENOUGH_MEMORY;
171 goto done;
172 }
173
174 /* Read the bitmap */
175 lError = RegQueryValueExW(pComDB->hKey,
176 L"ComDB",
177 NULL,
178 &dwType,
179 pBitmap,
180 &dwSize);
181 if (lError != ERROR_SUCCESS)
182 goto done;
183
184 /* Get the bit index */
185 dwBitIndex = ComNumber - 1;
186
187 /* Check if the bit to set fits into the bitmap */
188 if (dwBitIndex >= (dwSize * BITS_PER_BYTE))
189 {
190 FIXME("Resize the bitmap\n");
191
192 lError = ERROR_INVALID_PARAMETER;
193 goto done;
194 }
195
196 /* Calculate the byte index and a mask for the affected bit */
197 dwByteIndex = dwBitIndex / BITS_PER_BYTE;
198 cMask = 1 << (dwBitIndex % BITS_PER_BYTE);
199
200 lError = ERROR_SHARING_VIOLATION;
201
202 /* Check if the bit is not set */
203 if ((pBitmap[dwByteIndex] & cMask) == 0)
204 {
205 /* Set the bit */
206 pBitmap[dwByteIndex] |= cMask;
207 lError = ERROR_SUCCESS;
208 }
209
210 /* Save the bitmap if it was modified */
211 if (lError == ERROR_SUCCESS)
212 {
213 lError = RegSetValueExW(pComDB->hKey,
214 L"ComDB",
215 0,
216 REG_BINARY,
217 pBitmap,
218 dwSize);
219 }
220
221 done:
222 /* Release the mutex */
223 ReleaseMutex(pComDB->hMutex);
224
225 /* Release the bitmap */
226 if (pBitmap != NULL)
227 HeapFree(GetProcessHeap(), 0, pBitmap);
228
229 return lError;
230 }
231
232
233 LONG
234 WINAPI
ComDBClose(IN HCOMDB hComDB)235 ComDBClose(IN HCOMDB hComDB)
236 {
237 PCOMDB pComDB;
238
239 TRACE("ComDBClose(%p)\n", hComDB);
240
241 if (hComDB == HCOMDB_INVALID_HANDLE_VALUE ||
242 hComDB == NULL)
243 return ERROR_INVALID_PARAMETER;
244
245 pComDB = (PCOMDB)hComDB;
246
247 /* Close the registry key */
248 if (pComDB->hKey != NULL)
249 RegCloseKey(pComDB->hKey);
250
251 /* Close the mutex */
252 if (pComDB->hMutex != NULL)
253 CloseHandle(pComDB->hMutex);
254
255 /* Release the database */
256 HeapFree(GetProcessHeap(), 0, pComDB);
257
258 return ERROR_SUCCESS;
259 }
260
261
262 LONG
263 WINAPI
ComDBGetCurrentPortUsage(IN HCOMDB hComDB,OUT PBYTE Buffer,IN DWORD BufferSize,IN DWORD ReportType,OUT LPDWORD MaxPortsReported)264 ComDBGetCurrentPortUsage(IN HCOMDB hComDB,
265 OUT PBYTE Buffer,
266 IN DWORD BufferSize,
267 IN DWORD ReportType,
268 OUT LPDWORD MaxPortsReported)
269 {
270 PCOMDB pComDB;
271 DWORD dwBitIndex;
272 DWORD dwByteIndex;
273 DWORD dwType;
274 DWORD dwSize;
275 PBYTE pBitmap = NULL;
276 BYTE cMask;
277 LONG lError = ERROR_SUCCESS;
278
279 TRACE("ComDBGetCurrentPortUsage(%p %p %lu %lu %p)\n",
280 hComDB, Buffer, BufferSize, ReportType, MaxPortsReported);
281
282 if (hComDB == INVALID_HANDLE_VALUE ||
283 hComDB == NULL ||
284 (Buffer == NULL && MaxPortsReported == NULL) ||
285 (ReportType != CDB_REPORT_BITS && ReportType != CDB_REPORT_BYTES))
286 return ERROR_INVALID_PARAMETER;
287
288 pComDB = (PCOMDB)hComDB;
289
290 /* Wait for the mutex */
291 WaitForSingleObject(pComDB->hMutex, INFINITE);
292
293 /* Get the required bitmap size */
294 lError = RegQueryValueExW(pComDB->hKey,
295 L"ComDB",
296 NULL,
297 &dwType,
298 NULL,
299 &dwSize);
300 if (lError != ERROR_SUCCESS)
301 {
302 ERR("Failed to query the bitmap size!\n");
303 goto done;
304 }
305
306 /* Allocate the bitmap */
307 pBitmap = HeapAlloc(GetProcessHeap(),
308 HEAP_ZERO_MEMORY,
309 dwSize);
310 if (pBitmap == NULL)
311 {
312 ERR("Failed to allocate the bitmap!\n");
313 lError = ERROR_NOT_ENOUGH_MEMORY;
314 goto done;
315 }
316
317 /* Read the bitmap */
318 lError = RegQueryValueExW(pComDB->hKey,
319 L"ComDB",
320 NULL,
321 &dwType,
322 pBitmap,
323 &dwSize);
324 if (lError != ERROR_SUCCESS)
325 goto done;
326
327 if (Buffer == NULL)
328 {
329 *MaxPortsReported = dwSize * BITS_PER_BYTE;
330 }
331 else
332 {
333 if (ReportType == CDB_REPORT_BITS)
334 {
335 /* Clear the buffer */
336 memset(Buffer, 0, BufferSize);
337
338 memcpy(Buffer,
339 pBitmap,
340 min(dwSize, BufferSize));
341
342 if (MaxPortsReported != NULL)
343 *MaxPortsReported = min(dwSize, BufferSize) * BITS_PER_BYTE;
344 }
345 else if (ReportType == CDB_REPORT_BYTES)
346 {
347 /* Clear the buffer */
348 memset(Buffer, 0, BufferSize);
349
350 for (dwBitIndex = 0; dwBitIndex < min(dwSize * BITS_PER_BYTE, BufferSize); dwBitIndex++)
351 {
352 /* Calculate the byte index and a mask for the affected bit */
353 dwByteIndex = dwBitIndex / BITS_PER_BYTE;
354 cMask = 1 << (dwBitIndex % BITS_PER_BYTE);
355
356 if ((pBitmap[dwByteIndex] & cMask) != 0)
357 Buffer[dwBitIndex] = 1;
358 }
359 }
360 }
361
362 done:;
363 /* Release the mutex */
364 ReleaseMutex(pComDB->hMutex);
365
366 /* Release the bitmap */
367 HeapFree(GetProcessHeap(), 0, pBitmap);
368
369 return lError;
370 }
371
372
373 LONG
374 WINAPI
ComDBOpen(OUT HCOMDB * phComDB)375 ComDBOpen(OUT HCOMDB *phComDB)
376 {
377 PCOMDB pComDB;
378 DWORD dwDisposition;
379 DWORD dwType;
380 DWORD dwSize;
381 PBYTE pBitmap;
382 LONG lError;
383
384 TRACE("ComDBOpen(%p)\n", phComDB);
385
386 /* Allocate a new database */
387 pComDB = HeapAlloc(GetProcessHeap(),
388 HEAP_ZERO_MEMORY,
389 sizeof(COMDB));
390 if (pComDB == NULL)
391 {
392 ERR("Failed to allocate the database!\n");
393 *phComDB = HCOMDB_INVALID_HANDLE_VALUE;
394 return ERROR_ACCESS_DENIED;
395 }
396
397 /* Create a mutex to protect the database */
398 pComDB->hMutex = CreateMutexW(NULL,
399 FALSE,
400 L"ComDBMutex");
401 if (pComDB->hMutex == NULL)
402 {
403 ERR("Failed to create the mutex!\n");
404 HeapFree(GetProcessHeap(), 0, pComDB);
405 *phComDB = HCOMDB_INVALID_HANDLE_VALUE;
406 return ERROR_ACCESS_DENIED;
407 }
408
409 /* Wait for the mutex */
410 WaitForSingleObject(pComDB->hMutex, INFINITE);
411
412 /* Create or open the database key */
413 lError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
414 L"System\\CurrentControlSet\\Control\\COM Name Arbiter",
415 0,
416 NULL,
417 0,
418 KEY_ALL_ACCESS,
419 NULL,
420 &pComDB->hKey,
421 &dwDisposition);
422 if (lError != ERROR_SUCCESS)
423 goto done;
424
425 /* Get the required bitmap size */
426 lError = RegQueryValueExW(pComDB->hKey,
427 L"ComDB",
428 NULL,
429 &dwType,
430 NULL,
431 &dwSize);
432 if (lError == ERROR_FILE_NOT_FOUND)
433 {
434 /* Allocate a new bitmap */
435 dwSize = COMDB_MIN_PORTS_ARBITRATED / BITS_PER_BYTE;
436 pBitmap = HeapAlloc(GetProcessHeap(),
437 HEAP_ZERO_MEMORY,
438 dwSize);
439 if (pBitmap == NULL)
440 {
441 ERR("Failed to allocate the bitmap!\n");
442 lError = ERROR_ACCESS_DENIED;
443 goto done;
444 }
445
446 /* Write the bitmap to the registry */
447 lError = RegSetValueExW(pComDB->hKey,
448 L"ComDB",
449 0,
450 REG_BINARY,
451 pBitmap,
452 dwSize);
453
454 HeapFree(GetProcessHeap(), 0, pBitmap);
455 }
456
457 done:;
458 /* Release the mutex */
459 ReleaseMutex(pComDB->hMutex);
460
461 if (lError != ERROR_SUCCESS)
462 {
463 /* Clean up in case of failure */
464 if (pComDB->hKey != NULL)
465 RegCloseKey(pComDB->hKey);
466
467 if (pComDB->hMutex != NULL)
468 CloseHandle(pComDB->hMutex);
469
470 HeapFree(GetProcessHeap(), 0, pComDB);
471
472 *phComDB = HCOMDB_INVALID_HANDLE_VALUE;
473 }
474 else
475 {
476 /* Return the database handle */
477 *phComDB = (HCOMDB)pComDB;
478 }
479
480 TRACE("done (Error %lu)\n", lError);
481
482 return lError;
483 }
484
485
486 LONG
487 WINAPI
ComDBReleasePort(IN HCOMDB hComDB,IN DWORD ComNumber)488 ComDBReleasePort(IN HCOMDB hComDB,
489 IN DWORD ComNumber)
490 {
491 PCOMDB pComDB;
492 DWORD dwByteIndex;
493 DWORD dwBitIndex;
494 DWORD dwType;
495 DWORD dwSize;
496 PBYTE pBitmap = NULL;
497 BYTE cMask;
498 LONG lError;
499
500 TRACE("ComDBReleasePort(%p %lu)\n", hComDB, ComNumber);
501
502 if (hComDB == INVALID_HANDLE_VALUE ||
503 ComNumber == 0 ||
504 ComNumber > COMDB_MAX_PORTS_ARBITRATED)
505 return ERROR_INVALID_PARAMETER;
506
507 pComDB = (PCOMDB)hComDB;
508
509 /* Wait for the mutex */
510 WaitForSingleObject(pComDB->hMutex, INFINITE);
511
512 /* Get the required bitmap size */
513 lError = RegQueryValueExW(pComDB->hKey,
514 L"ComDB",
515 NULL,
516 &dwType,
517 NULL,
518 &dwSize);
519 if (lError != ERROR_SUCCESS)
520 {
521 ERR("Failed to query the bitmap size!\n");
522 goto done;
523 }
524
525 /* Allocate the bitmap */
526 pBitmap = HeapAlloc(GetProcessHeap(),
527 HEAP_ZERO_MEMORY,
528 dwSize);
529 if (pBitmap == NULL)
530 {
531 ERR("Failed to allocate the bitmap!\n");
532 lError = ERROR_NOT_ENOUGH_MEMORY;
533 goto done;
534 }
535
536 /* Read the bitmap */
537 lError = RegQueryValueExW(pComDB->hKey,
538 L"ComDB",
539 NULL,
540 &dwType,
541 pBitmap,
542 &dwSize);
543 if (lError != ERROR_SUCCESS)
544 goto done;
545
546 /* Get the bit index */
547 dwBitIndex = ComNumber - 1;
548
549 /* Check if the bit to set fits into the bitmap */
550 if (dwBitIndex >= (dwSize * BITS_PER_BYTE))
551 {
552 lError = ERROR_INVALID_PARAMETER;
553 goto done;
554 }
555
556 /* Calculate the byte index and a mask for the affected bit */
557 dwByteIndex = dwBitIndex / BITS_PER_BYTE;
558 cMask = 1 << (dwBitIndex % BITS_PER_BYTE);
559
560 /* Release the port */
561 pBitmap[dwByteIndex] &= ~cMask;
562
563 lError = RegSetValueExW(pComDB->hKey,
564 L"ComDB",
565 0,
566 REG_BINARY,
567 pBitmap,
568 dwSize);
569
570 done:;
571 /* Release the mutex */
572 ReleaseMutex(pComDB->hMutex);
573
574 /* Release the bitmap */
575 if (pBitmap != NULL)
576 HeapFree(GetProcessHeap(), 0, pBitmap);
577
578 return lError;
579 }
580
581
582 LONG
583 WINAPI
ComDBResizeDatabase(IN HCOMDB hComDB,IN DWORD NewSize)584 ComDBResizeDatabase(IN HCOMDB hComDB,
585 IN DWORD NewSize)
586 {
587 PCOMDB pComDB;
588 PBYTE pBitmap = NULL;
589 DWORD dwSize;
590 DWORD dwNewSize;
591 DWORD dwType;
592 LONG lError;
593
594 TRACE("ComDBResizeDatabase(%p %lu)\n", hComDB, NewSize);
595
596 if (hComDB == INVALID_HANDLE_VALUE ||
597 hComDB == NULL ||
598 (NewSize & BITMAP_SIZE_INVALID_BITS))
599 return ERROR_INVALID_PARAMETER;
600
601 pComDB = (PCOMDB)hComDB;
602
603 /* Wait for the mutex */
604 WaitForSingleObject(pComDB->hMutex, INFINITE);
605
606 /* Get the required bitmap size */
607 lError = RegQueryValueExW(pComDB->hKey,
608 L"ComDB",
609 NULL,
610 &dwType,
611 NULL,
612 &dwSize);
613 if (lError != ERROR_SUCCESS)
614 goto done;
615
616 /* Check the size limits */
617 if (NewSize > COMDB_MAX_PORTS_ARBITRATED ||
618 NewSize <= dwSize * BITS_PER_BYTE)
619 {
620 lError = ERROR_BAD_LENGTH;
621 goto done;
622 }
623
624 /* Calculate the new bitmap size */
625 dwNewSize = NewSize / BITS_PER_BYTE;
626
627 /* Allocate the new bitmap */
628 pBitmap = HeapAlloc(GetProcessHeap(),
629 HEAP_ZERO_MEMORY,
630 dwSize);
631 if (pBitmap == NULL)
632 {
633 ERR("Failed to allocate the bitmap!\n");
634 lError = ERROR_ACCESS_DENIED;
635 goto done;
636 }
637
638 /* Read the current bitmap */
639 lError = RegQueryValueExW(pComDB->hKey,
640 L"ComDB",
641 NULL,
642 &dwType,
643 pBitmap,
644 &dwSize);
645 if (lError != ERROR_SUCCESS)
646 goto done;
647
648 /* Write the new bitmap */
649 lError = RegSetValueExW(pComDB->hKey,
650 L"ComDB",
651 0,
652 REG_BINARY,
653 pBitmap,
654 dwNewSize);
655
656 done:;
657 /* Release the mutex */
658 ReleaseMutex(pComDB->hMutex);
659
660 if (pBitmap != NULL)
661 HeapFree(GetProcessHeap(), 0, pBitmap);
662
663 return lError;
664 }
665
666 /* EOF */
667