2 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
32 #include "ddk/ntddser.h"
34 #include "wine/server.h"
35 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
41 /***********************************************************************
42 * COMM_Parse* (Internal)
44 * The following COMM_Parse* functions are used by the BuildCommDCB
45 * functions to help parse the various parts of the device control string.
47 static LPCWSTR
COMM_ParseStart(LPCWSTR ptr
)
49 static const WCHAR comW
[] = {'C','O','M',0};
51 /* The device control string may optionally start with "COMx" followed
52 by an optional ':' and spaces. */
53 if(!strncmpiW(ptr
, comW
, 3))
57 /* Allow any com port above 0 as Win 9x does (NT only allows
58 values for com ports which are actually present) */
59 if(*ptr
< '1' || *ptr
> '9')
62 /* Advance pointer past port number */
63 while(*ptr
>= '0' && *ptr
<= '9') ptr
++;
65 /* The com port number must be followed by a ':' or ' ' */
66 if(*ptr
!= ':' && *ptr
!= ' ')
69 /* Advance pointer to beginning of next parameter */
70 while(*ptr
== ' ') ptr
++;
74 while(*ptr
== ' ') ptr
++;
77 /* The device control string must not start with a space. */
84 static LPCWSTR
COMM_ParseNumber(LPCWSTR ptr
, LPDWORD lpnumber
)
86 if(*ptr
< '0' || *ptr
> '9') return NULL
;
87 *lpnumber
= strtoulW(ptr
, NULL
, 10);
88 while(*ptr
>= '0' && *ptr
<= '9') ptr
++;
92 static LPCWSTR
COMM_ParseParity(LPCWSTR ptr
, LPBYTE lpparity
)
94 /* Contrary to what you might expect, Windows only sets the Parity
95 member of DCB and not fParity even when parity is specified in the
96 device control string */
102 *lpparity
= EVENPARITY
;
106 *lpparity
= MARKPARITY
;
110 *lpparity
= NOPARITY
;
114 *lpparity
= ODDPARITY
;
118 *lpparity
= SPACEPARITY
;
127 static LPCWSTR
COMM_ParseByteSize(LPCWSTR ptr
, LPBYTE lpbytesize
)
131 if(!(ptr
= COMM_ParseNumber(ptr
, &temp
)))
134 if(temp
>= 5 && temp
<= 8)
143 static LPCWSTR
COMM_ParseStopBits(LPCWSTR ptr
, LPBYTE lpstopbits
)
146 static const WCHAR stopbits15W
[] = {'1','.','5',0};
148 if(!strncmpW(stopbits15W
, ptr
, 3))
151 *lpstopbits
= ONE5STOPBITS
;
155 if(!(ptr
= COMM_ParseNumber(ptr
, &temp
)))
159 *lpstopbits
= ONESTOPBIT
;
161 *lpstopbits
= TWOSTOPBITS
;
169 static LPCWSTR
COMM_ParseOnOff(LPCWSTR ptr
, LPDWORD lponoff
)
171 static const WCHAR onW
[] = {'o','n',0};
172 static const WCHAR offW
[] = {'o','f','f',0};
174 if(!strncmpiW(onW
, ptr
, 2))
179 else if(!strncmpiW(offW
, ptr
, 3))
190 /***********************************************************************
191 * COMM_BuildOldCommDCB (Internal)
193 * Build a DCB using the old style settings string eg: "96,n,8,1"
195 static BOOL
COMM_BuildOldCommDCB(LPCWSTR device
, LPDCB lpdcb
)
199 if(!(device
= COMM_ParseNumber(device
, &lpdcb
->BaudRate
)))
202 switch(lpdcb
->BaudRate
)
207 lpdcb
->BaudRate
*= 10;
213 lpdcb
->BaudRate
*= 100;
216 lpdcb
->BaudRate
= 19200;
220 while(*device
== ' ') device
++;
221 if(*device
++ != ',') return FALSE
;
222 while(*device
== ' ') device
++;
224 if(!(device
= COMM_ParseParity(device
, &lpdcb
->Parity
)))
227 while(*device
== ' ') device
++;
228 if(*device
++ != ',') return FALSE
;
229 while(*device
== ' ') device
++;
231 if(!(device
= COMM_ParseByteSize(device
, &lpdcb
->ByteSize
)))
234 while(*device
== ' ') device
++;
235 if(*device
++ != ',') return FALSE
;
236 while(*device
== ' ') device
++;
238 if(!(device
= COMM_ParseStopBits(device
, &lpdcb
->StopBits
)))
241 /* The last parameter for flow control is optional. */
242 while(*device
== ' ') device
++;
246 while(*device
== ' ') device
++;
247 if(*device
) last
= *device
++;
248 while(*device
== ' ') device
++;
251 /* Win NT sets the flow control members based on (or lack of) the last
252 parameter. Win 9x does not set these members. */
257 lpdcb
->fOutX
= FALSE
;
258 lpdcb
->fOutxCtsFlow
= FALSE
;
259 lpdcb
->fOutxDsrFlow
= FALSE
;
260 lpdcb
->fDtrControl
= DTR_CONTROL_ENABLE
;
261 lpdcb
->fRtsControl
= RTS_CONTROL_ENABLE
;
267 lpdcb
->fOutxCtsFlow
= FALSE
;
268 lpdcb
->fOutxDsrFlow
= FALSE
;
269 lpdcb
->fDtrControl
= DTR_CONTROL_ENABLE
;
270 lpdcb
->fRtsControl
= RTS_CONTROL_ENABLE
;
275 lpdcb
->fOutX
= FALSE
;
276 lpdcb
->fOutxCtsFlow
= TRUE
;
277 lpdcb
->fOutxDsrFlow
= TRUE
;
278 lpdcb
->fDtrControl
= DTR_CONTROL_HANDSHAKE
;
279 lpdcb
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
285 /* This should be the end of the string. */
286 if(*device
) return FALSE
;
291 /***********************************************************************
292 * COMM_BuildNewCommDCB (Internal)
294 * Build a DCB using the new style settings string.
295 * eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
297 static BOOL
COMM_BuildNewCommDCB(LPCWSTR device
, LPDCB lpdcb
, LPCOMMTIMEOUTS lptimeouts
)
300 BOOL baud
= FALSE
, stop
= FALSE
;
301 static const WCHAR baudW
[] = {'b','a','u','d','=',0};
302 static const WCHAR parityW
[] = {'p','a','r','i','t','y','=',0};
303 static const WCHAR dataW
[] = {'d','a','t','a','=',0};
304 static const WCHAR stopW
[] = {'s','t','o','p','=',0};
305 static const WCHAR toW
[] = {'t','o','=',0};
306 static const WCHAR xonW
[] = {'x','o','n','=',0};
307 static const WCHAR odsrW
[] = {'o','d','s','r','=',0};
308 static const WCHAR octsW
[] = {'o','c','t','s','=',0};
309 static const WCHAR dtrW
[] = {'d','t','r','=',0};
310 static const WCHAR rtsW
[] = {'r','t','s','=',0};
311 static const WCHAR idsrW
[] = {'i','d','s','r','=',0};
315 while(*device
== ' ') device
++;
317 if(!strncmpiW(baudW
, device
, 5))
321 if(!(device
= COMM_ParseNumber(device
+ 5, &lpdcb
->BaudRate
)))
324 else if(!strncmpiW(parityW
, device
, 7))
326 if(!(device
= COMM_ParseParity(device
+ 7, &lpdcb
->Parity
)))
329 else if(!strncmpiW(dataW
, device
, 5))
331 if(!(device
= COMM_ParseByteSize(device
+ 5, &lpdcb
->ByteSize
)))
334 else if(!strncmpiW(stopW
, device
, 5))
338 if(!(device
= COMM_ParseStopBits(device
+ 5, &lpdcb
->StopBits
)))
341 else if(!strncmpiW(toW
, device
, 3))
343 if(!(device
= COMM_ParseOnOff(device
+ 3, &temp
)))
346 lptimeouts
->ReadIntervalTimeout
= 0;
347 lptimeouts
->ReadTotalTimeoutMultiplier
= 0;
348 lptimeouts
->ReadTotalTimeoutConstant
= 0;
349 lptimeouts
->WriteTotalTimeoutMultiplier
= 0;
350 lptimeouts
->WriteTotalTimeoutConstant
= temp
? 60000 : 0;
352 else if(!strncmpiW(xonW
, device
, 4))
354 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
360 else if(!strncmpiW(odsrW
, device
, 5))
362 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
365 lpdcb
->fOutxDsrFlow
= temp
;
367 else if(!strncmpiW(octsW
, device
, 5))
369 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
372 lpdcb
->fOutxCtsFlow
= temp
;
374 else if(!strncmpiW(dtrW
, device
, 4))
376 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
379 lpdcb
->fDtrControl
= temp
;
381 else if(!strncmpiW(rtsW
, device
, 4))
383 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
386 lpdcb
->fRtsControl
= temp
;
388 else if(!strncmpiW(idsrW
, device
, 5))
390 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
393 /* Win NT sets the fDsrSensitivity member based on the
394 idsr parameter. Win 9x sets fOutxDsrFlow instead. */
395 lpdcb
->fDsrSensitivity
= temp
;
400 /* After the above parsing, the next character (if not the end of
401 the string) should be a space */
402 if(*device
&& *device
!= ' ')
406 /* If stop bits were not specified, a default is always supplied. */
409 if(baud
&& lpdcb
->BaudRate
== 110)
410 lpdcb
->StopBits
= TWOSTOPBITS
;
412 lpdcb
->StopBits
= ONESTOPBIT
;
418 /**************************************************************************
419 * BuildCommDCBA (KERNEL32.@)
421 * Updates a device control block data structure with values from an
422 * ascii device control string. The device control string has two forms
423 * normal and extended, it must be exclusively in one or the other form.
427 * True on success, false on a malformed control string.
429 BOOL WINAPI
BuildCommDCBA(
430 LPCSTR device
, /* [in] The ascii device control string used to update the DCB. */
431 LPDCB lpdcb
) /* [out] The device control block to be updated. */
433 return BuildCommDCBAndTimeoutsA(device
,lpdcb
,NULL
);
436 /**************************************************************************
437 * BuildCommDCBAndTimeoutsA (KERNEL32.@)
439 * Updates a device control block data structure with values from an
440 * ascii device control string. Taking timeout values from a timeouts
441 * struct if desired by the control string.
445 * True on success, false bad handles etc.
447 BOOL WINAPI
BuildCommDCBAndTimeoutsA(
448 LPCSTR device
, /* [in] The ascii device control string. */
449 LPDCB lpdcb
, /* [out] The device control block to be updated. */
450 LPCOMMTIMEOUTS lptimeouts
) /* [in] The COMMTIMEOUTS structure to be updated. */
453 UNICODE_STRING deviceW
;
455 TRACE("(%s,%p,%p)\n",device
,lpdcb
,lptimeouts
);
456 if(device
) RtlCreateUnicodeStringFromAsciiz(&deviceW
,device
);
457 else deviceW
.Buffer
= NULL
;
459 if(deviceW
.Buffer
) ret
= BuildCommDCBAndTimeoutsW(deviceW
.Buffer
,lpdcb
,lptimeouts
);
461 RtlFreeUnicodeString(&deviceW
);
465 /**************************************************************************
466 * BuildCommDCBAndTimeoutsW (KERNEL32.@)
468 * Updates a device control block data structure with values from a
469 * unicode device control string. Taking timeout values from a timeouts
470 * struct if desired by the control string.
474 * True on success, false bad handles etc
476 BOOL WINAPI
BuildCommDCBAndTimeoutsW(
477 LPCWSTR devid
, /* [in] The unicode device control string. */
478 LPDCB lpdcb
, /* [out] The device control block to be updated. */
479 LPCOMMTIMEOUTS lptimeouts
) /* [in] The COMMTIMEOUTS structure to be updated. */
482 COMMTIMEOUTS timeouts
;
486 TRACE("(%s,%p,%p)\n",debugstr_w(devid
),lpdcb
,lptimeouts
);
488 memset(&timeouts
, 0, sizeof timeouts
);
490 /* Set DCBlength. (Windows NT does not do this, but 9x does) */
491 lpdcb
->DCBlength
= sizeof(DCB
);
493 /* Make a copy of the original data structures to work with since if
494 if there is an error in the device control string the originals
495 should not be modified (except possibly DCBlength) */
497 if(lptimeouts
) timeouts
= *lptimeouts
;
499 ptr
= COMM_ParseStart(ptr
);
503 else if(strchrW(ptr
, ','))
504 result
= COMM_BuildOldCommDCB(ptr
, &dcb
);
506 result
= COMM_BuildNewCommDCB(ptr
, &dcb
, &timeouts
);
511 if(lptimeouts
) *lptimeouts
= timeouts
;
516 WARN("Invalid device control string: %s\n", debugstr_w(devid
));
517 SetLastError(ERROR_INVALID_PARAMETER
);
522 /**************************************************************************
523 * BuildCommDCBW (KERNEL32.@)
525 * Updates a device control block structure with values from an
526 * unicode device control string. The device control string has two forms
527 * normal and extended, it must be exclusively in one or the other form.
531 * True on success, false on a malformed control string.
533 BOOL WINAPI
BuildCommDCBW(
534 LPCWSTR devid
, /* [in] The unicode device control string. */
535 LPDCB lpdcb
) /* [out] The device control block to be updated. */
537 return BuildCommDCBAndTimeoutsW(devid
,lpdcb
,NULL
);
540 /***********************************************************************
542 * The functionality of CommConfigDialogA, GetDefaultCommConfig and
543 * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
544 * This is dependent on the type of COMM port, but since it is doubtful
545 * anybody will get around to implementing support for fancy serial
546 * ports in WINE, this is hardcoded for the time being. The name of
547 * this DLL should be stored in and read from the system registry in
548 * the hive HKEY_LOCAL_MACHINE, key
549 * System\\CurrentControlSet\\Services\\Class\\Ports\\????
550 * where ???? is the port number... that is determined by PNP
551 * The DLL should be loaded when the COMM port is opened, and closed
552 * when the COMM port is closed. - MJM 20 June 2000
553 ***********************************************************************/
554 static const WCHAR lpszSerialUI
[] = {
555 's','e','r','i','a','l','u','i','.','d','l','l',0 };
558 /***********************************************************************
559 * CommConfigDialogA (KERNEL32.@)
561 * Raises a dialog that allows the user to configure a comm port.
562 * Fills the COMMCONFIG struct with information specified by the user.
563 * This function should call a similar routine in the COMM driver...
567 * TRUE on success, FALSE on failure
568 * If successful, the lpCommConfig structure will contain a new
569 * configuration for the comm port, as specified by the user.
572 * The library with the CommConfigDialog code is never unloaded.
573 * Perhaps this should be done when the comm port is closed?
575 BOOL WINAPI
CommConfigDialogA(
576 LPCSTR lpszDevice
, /* [in] name of communications device */
577 HWND hWnd
, /* [in] parent window for the dialog */
578 LPCOMMCONFIG lpCommConfig
) /* [out] pointer to struct to fill */
580 LPWSTR lpDeviceW
= NULL
;
584 TRACE("(%s, %p, %p)\n", debugstr_a(lpszDevice
), hWnd
, lpCommConfig
);
588 len
= MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, NULL
, 0 );
589 lpDeviceW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
590 MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, lpDeviceW
, len
);
592 r
= CommConfigDialogW(lpDeviceW
, hWnd
, lpCommConfig
);
593 HeapFree( GetProcessHeap(), 0, lpDeviceW
);
597 /***********************************************************************
598 * CommConfigDialogW (KERNEL32.@)
600 * See CommConfigDialogA.
602 BOOL WINAPI
CommConfigDialogW(
603 LPCWSTR lpszDevice
, /* [in] name of communications device */
604 HWND hWnd
, /* [in] parent window for the dialog */
605 LPCOMMCONFIG lpCommConfig
) /* [out] pointer to struct to fill */
607 DWORD (WINAPI
*pCommConfigDialog
)(LPCWSTR
, HWND
, LPCOMMCONFIG
);
608 HMODULE hConfigModule
;
609 DWORD res
= ERROR_INVALID_PARAMETER
;
611 TRACE("(%s, %p, %p)\n", debugstr_w(lpszDevice
), hWnd
, lpCommConfig
);
612 hConfigModule
= LoadLibraryW(lpszSerialUI
);
615 pCommConfigDialog
= (void *)GetProcAddress(hConfigModule
, "drvCommConfigDialogW");
616 if (pCommConfigDialog
) {
617 res
= pCommConfigDialog(lpszDevice
, hWnd
, lpCommConfig
);
619 FreeLibrary(hConfigModule
);
622 if (res
) SetLastError(res
);
623 return (res
== ERROR_SUCCESS
);
626 /***********************************************************************
627 * SetDefaultCommConfigW (KERNEL32.@)
629 * Initializes the default configuration for a communication device.
632 * lpszDevice [I] Name of the device targeted for configuration
633 * lpCommConfig [I] PTR to a buffer with the configuration for the device
634 * dwSize [I] Number of bytes in the buffer
638 * Success: TRUE, and default configuration saved
641 BOOL WINAPI
SetDefaultCommConfigW(LPCWSTR lpszDevice
, LPCOMMCONFIG lpCommConfig
, DWORD dwSize
)
643 BOOL (WINAPI
*lpfnSetDefaultCommConfig
)(LPCWSTR
, LPCOMMCONFIG
, DWORD
);
644 HMODULE hConfigModule
;
647 TRACE("(%s, %p, %u)\n", debugstr_w(lpszDevice
), lpCommConfig
, dwSize
);
649 hConfigModule
= LoadLibraryW(lpszSerialUI
);
653 lpfnSetDefaultCommConfig
= (void *)GetProcAddress(hConfigModule
, "drvSetDefaultCommConfigW");
654 if (lpfnSetDefaultCommConfig
)
655 r
= lpfnSetDefaultCommConfig(lpszDevice
, lpCommConfig
, dwSize
);
657 FreeLibrary(hConfigModule
);
663 /***********************************************************************
664 * SetDefaultCommConfigA (KERNEL32.@)
666 * Initializes the default configuration for a communication device.
668 * See SetDefaultCommConfigW.
671 BOOL WINAPI
SetDefaultCommConfigA(LPCSTR lpszDevice
, LPCOMMCONFIG lpCommConfig
, DWORD dwSize
)
674 LPWSTR lpDeviceW
= NULL
;
677 TRACE("(%s, %p, %u)\n", debugstr_a(lpszDevice
), lpCommConfig
, dwSize
);
681 len
= MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, NULL
, 0 );
682 lpDeviceW
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
683 MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, lpDeviceW
, len
);
685 r
= SetDefaultCommConfigW(lpDeviceW
,lpCommConfig
,dwSize
);
686 HeapFree( GetProcessHeap(), 0, lpDeviceW
);
691 /***********************************************************************
692 * GetDefaultCommConfigW (KERNEL32.@)
694 * Acquires the default configuration of the specified communication device. (unicode)
698 * True on successful reading of the default configuration,
699 * if the device is not found or the buffer is too small.
701 BOOL WINAPI
GetDefaultCommConfigW(
702 LPCWSTR lpszName
, /* [in] The unicode name of the device targeted for configuration. */
703 LPCOMMCONFIG lpCC
, /* [out] The default configuration for the device. */
704 LPDWORD lpdwSize
) /* [in/out] Initially the size of the default configuration buffer,
705 afterwards the number of bytes copied to the buffer or
706 the needed size of the buffer. */
708 DWORD (WINAPI
*pGetDefaultCommConfig
)(LPCWSTR
, LPCOMMCONFIG
, LPDWORD
);
709 HMODULE hConfigModule
;
710 DWORD res
= ERROR_INVALID_PARAMETER
;
712 TRACE("(%s, %p, %p) *lpdwSize: %u\n", debugstr_w(lpszName
), lpCC
, lpdwSize
, lpdwSize
? *lpdwSize
: 0 );
713 hConfigModule
= LoadLibraryW(lpszSerialUI
);
716 pGetDefaultCommConfig
= (void *)GetProcAddress(hConfigModule
, "drvGetDefaultCommConfigW");
717 if (pGetDefaultCommConfig
) {
718 res
= pGetDefaultCommConfig(lpszName
, lpCC
, lpdwSize
);
720 FreeLibrary(hConfigModule
);
723 if (res
) SetLastError(res
);
724 return (res
== ERROR_SUCCESS
);
727 /**************************************************************************
728 * GetDefaultCommConfigA (KERNEL32.@)
730 * Acquires the default configuration of the specified communication device. (ascii)
734 * True on successful reading of the default configuration,
735 * if the device is not found or the buffer is too small.
737 BOOL WINAPI
GetDefaultCommConfigA(
738 LPCSTR lpszName
, /* [in] The ascii name of the device targeted for configuration. */
739 LPCOMMCONFIG lpCC
, /* [out] The default configuration for the device. */
740 LPDWORD lpdwSize
) /* [in/out] Initially the size of the default configuration buffer,
741 afterwards the number of bytes copied to the buffer or
742 the needed size of the buffer. */
745 UNICODE_STRING lpszNameW
;
747 TRACE("(%s, %p, %p) *lpdwSize: %u\n", debugstr_a(lpszName
), lpCC
, lpdwSize
, lpdwSize
? *lpdwSize
: 0 );
748 if(lpszName
) RtlCreateUnicodeStringFromAsciiz(&lpszNameW
,lpszName
);
749 else lpszNameW
.Buffer
= NULL
;
751 ret
= GetDefaultCommConfigW(lpszNameW
.Buffer
,lpCC
,lpdwSize
);
753 RtlFreeUnicodeString(&lpszNameW
);