BuildCommDCBAndTimeouts patch

Kevin Groeneveld kgroeneveld at mcmaster.ca
Mon Sep 8 20:21:16 CDT 2003


Ok, here is my first attempt at a real patch for wine (i.e. more than 3 
lines).

This started off as a simple fix.  I have a Windows program which makes
use of the serial communications routines.  I found that this Windows
program would only ever open the com port once, then I had to close the
application and start it again.  I tracked this problem down to the fact
that the first parameter to BuildCommDCBAndTimeouts is supposed to be a
constants string, but wine was modifying it.

As I was trying to fix the above problem, I found several other bugs in
BuildCommDCBAndTimeouts.  For example, COMM_BuildOldCommDCB contained a
possible buffer overflow.

To try and verify the correct operation of BuildCommDCBAndTimeouts I
wrote a small Windows program.  This program takes input from stdin,
passes it to BuildCommDCBAndTimeouts and then shows the results.  I have
attached this program for if anyone wants to try and verify my
patch.  I ran this program many times under Win 95, Win 2000 and wine to
try and make sure the results were consistent.

Changelog:
   Kevin Groeneveld <kgroeneveld at mcmaster.ca>
   Add missing wReserved1 member to DCB structure definition
   Fix several bugs in BuildCommDCBAndTimeouts:
   - make sure LPCSTR parameter is really treated as constant
   - fix possible buffer overflow if passed in string is too long
   - if the device control string is invalid, do not modify DCB
   - do not clear entire DCB, only modify appropriate members
   - fix parsing of stop bits parameter so it works for 1 and 1.5
   - populate COMMTIMEOUTS when to=xxx parameter is specified
   - added support for xon, odsr, octs, dtr, rts, and idsr parameters
   - fix several other parsing errors

-------------- next part --------------
diff -ur wine-20030813/dlls/kernel/comm.c wine-20030813.patched/dlls/kernel/comm.c
--- wine-20030813/dlls/kernel/comm.c	2003-08-23 23:12:42.000000000 -0400
+++ wine-20030813.patched/dlls/kernel/comm.c	2003-09-08 20:43:08.000000000 -0400
@@ -153,134 +153,349 @@
 }
 
 /***********************************************************************
- *           COMM_BuildOldCommDCB   (Internal)
+ *           COMM_Parse*   (Internal)
  *
- *  Build a DCB using the old style settings string eg: "COMx:96,n,8,1"
- *  We ignore the COM port index, since we can support more than 4 ports.
+ *  The following COMM_Parse* functions are used by the BuildCommDCB
+ *  functions to help parse the various parts of the device control string.
  */
-BOOL WINAPI COMM_BuildOldCommDCB(LPCSTR device, LPDCB lpdcb)
+static LPCSTR COMM_ParseStart(LPCSTR ptr)
 {
-	/* "COM1:96,n,8,1"	*/
-	/*  012345		*/
-	char *ptr, temp[256], last;
-	int rate;
+	/* The device control string may optionally start with "COMx" followed
+	   by an optional ':' and spaces. */
+	if(!strncasecmp(ptr, "COM", 3))
+	{
+		ptr += 3;
 
-	TRACE("(%s), ptr %p\n", device, lpdcb);
+		/* Allow any com port above 0 as Win 9x does (NT only allows
+		   values for com ports which are actually present) */
+		if(*ptr < '1' || *ptr > '9')
+			return NULL;
+		
+		/* Advance pointer past port number */
+		while(*ptr >= '0' && *ptr <= '9') ptr++;
+		
+		/* The com port number must be followed by a ':' or ' ' */
+		if(*ptr != ':' && *ptr != ' ')
+			return NULL;
+
+		/* Advance pointer to beginning of next parameter */
+		while(*ptr == ' ') ptr++;
+		if(*ptr == ':')
+		{
+			ptr++;
+			while(*ptr == ' ') ptr++;
+		}
+	}
+	/* The device control string must not start with a space. */
+	else if(*ptr == ' ')
+		return NULL;
+	
+	return ptr;
+}
+ 
+static LPCSTR COMM_ParseNumber(LPCSTR ptr, LPDWORD lpnumber)
+{
+	if(*ptr < '0' || *ptr > '9') return NULL;
+	if(!sscanf(ptr, "%ld", lpnumber)) return NULL;
+	while(*ptr >= '0' && *ptr <= '9') ptr++;
+	return ptr;
+}
 
-        /* Some applications call this function with "9600,n,8,1"
-         * not sending the "COM1:" parameter at left of string */
-        if (!strncasecmp(device,"COM",3))
-        {
-            if (!device[3]) return FALSE;
-            if (device[4] != ':' && device[4] != ' ') return FALSE;
-            strcpy(temp,device+5);
-        }
-        else strcpy(temp,device);
+static LPCSTR COMM_ParseParity(LPCSTR ptr, LPBYTE lpparity)
+{
+	/* Contrary to what you might expect, Windows only sets the Parity
+	   member of DCB and not fParity even when parity is specified in the
+	   device control string */
+
+	switch(toupper(*ptr++))
+	{
+	case 'E':
+		*lpparity = EVENPARITY;
+		break;
+	case 'M':
+		*lpparity = MARKPARITY;
+		break;
+	case 'N':
+		*lpparity = NOPARITY;
+		break;
+	case 'O':
+		*lpparity = ODDPARITY;
+		break;
+	case 'S':
+		*lpparity = SPACEPARITY;
+		break;
+	default:
+		return NULL;
+	}
+
+	return ptr;
+}
+
+static LPCSTR COMM_ParseByteSize(LPCSTR ptr, LPBYTE lpbytesize)
+{
+	DWORD temp;
+
+	if(!(ptr = COMM_ParseNumber(ptr, &temp)))
+		return NULL;
+
+	if(temp >= 5 && temp <= 8)
+	{
+		*lpbytesize = temp;
+		return ptr;
+	}
+	else
+		return NULL;
+}
+
+static LPCSTR COMM_ParseStopBits(LPCSTR ptr, LPBYTE lpstopbits)
+{
+	DWORD temp;
+
+	if(!strncmp("1.5", ptr, 3))
+	{
+		ptr += 3;
+		*lpstopbits = ONE5STOPBITS;
+	}
+	else
+	{
+		if(!(ptr = COMM_ParseNumber(ptr, &temp)))
+			return NULL;
 
-	last=temp[strlen(temp)-1];
-	ptr = strtok(temp, ", ");
+		if(temp == 1)
+			*lpstopbits = ONESTOPBIT;
+		else if(temp == 2)
+			*lpstopbits = TWOSTOPBITS;
+		else
+			return NULL;
+	}
+	
+	return ptr;
+}
 
-        /* DOS/Windows only compares the first two numbers
-	 * and assigns an appropriate baud rate.
-	 * You can supply 961324245, it still returns 9600 ! */
-	if (strlen(ptr) < 2)
+static LPCSTR COMM_ParseOnOff(LPCSTR ptr, LPDWORD lponoff)
+{
+	if(!strncasecmp("on", ptr, 2))
 	{
-		WARN("Unknown baudrate string '%s' !\n", ptr);
-		return FALSE; /* error: less than 2 chars */
+		ptr += 2;
+		*lponoff = 1;
 	}
-	ptr[2] = '\0';
-	rate = atoi(ptr);
+	else if(!strncasecmp("off", ptr, 3))
+	{
+		ptr += 3;
+		*lponoff = 0;
+	}
+	else
+		return NULL;
 
-	switch (rate) {
+	return ptr;
+}
+
+/***********************************************************************
+ *           COMM_BuildOldCommDCB   (Internal)
+ *
+ *  Build a DCB using the old style settings string eg: "96,n,8,1"
+ */
+static BOOL COMM_BuildOldCommDCB(LPCSTR device, LPDCB lpdcb)
+{
+	char last = 0;
+
+	if(!(device = COMM_ParseNumber(device, &lpdcb->BaudRate)))
+		return FALSE;
+	
+	switch(lpdcb->BaudRate)
+	{
 	case 11:
 	case 30:
 	case 60:
-		rate *= 10;
+		lpdcb->BaudRate *= 10;
 		break;
 	case 12:
 	case 24:
 	case 48:
 	case 96:
-		rate *= 100;
+		lpdcb->BaudRate *= 100;
 		break;
 	case 19:
-		rate = 19200;
+		lpdcb->BaudRate = 19200;
 		break;
-	default:
-		WARN("Unknown baudrate indicator %d !\n", rate);
-		return FALSE;
 	}
 
-        lpdcb->BaudRate = rate;
-	TRACE("baudrate (%ld)\n", lpdcb->BaudRate);
+	while(*device == ' ') device++;
+	if(*device++ != ',') return FALSE;
+	while(*device == ' ') device++;
 
-	ptr = strtok(NULL, ", ");
-	if (islower(*ptr))
-		*ptr = toupper(*ptr);
-
-       	TRACE("parity (%c)\n", *ptr);
-	lpdcb->fParity = TRUE;
-	switch (*ptr) {
-	case 'N':
-		lpdcb->Parity = NOPARITY;
-		lpdcb->fParity = FALSE;
-		break;
-	case 'E':
-		lpdcb->Parity = EVENPARITY;
+	if(!(device = COMM_ParseParity(device, &lpdcb->Parity)))
+		return FALSE;
+
+	while(*device == ' ') device++;
+	if(*device++ != ',') return FALSE;
+	while(*device == ' ') device++;
+		
+	if(!(device = COMM_ParseByteSize(device, &lpdcb->ByteSize)))
+		return FALSE;
+
+	while(*device == ' ') device++;
+	if(*device++ != ',') return FALSE;
+	while(*device == ' ') device++;
+
+	if(!(device = COMM_ParseStopBits(device, &lpdcb->StopBits)))
+		return FALSE;
+
+	/* The last parameter for flow control is optional. */
+	while(*device == ' ') device++;
+	if(*device == ',')
+	{
+		device++;
+		while(*device == ' ') device++;
+		if(*device) last = toupper(*device++);
+		while(*device == ' ') device++;
+	}
+		
+	switch(last)
+	{
+	case 0:
+		lpdcb->fInX = FALSE;
+		lpdcb->fOutX = FALSE;
+		lpdcb->fOutxCtsFlow = FALSE;
+		lpdcb->fOutxDsrFlow = FALSE;
+		lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
+		lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
 		break;
-	case 'M':
-		lpdcb->Parity = MARKPARITY;
+	case 'X':
+		lpdcb->fInX = TRUE;
+		lpdcb->fOutX = TRUE;
+		lpdcb->fOutxCtsFlow = FALSE;
+		lpdcb->fOutxDsrFlow = FALSE;
+		lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
+		lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
 		break;
-	case 'O':
-		lpdcb->Parity = ODDPARITY;
+	case 'P':
+		lpdcb->fInX = FALSE;
+		lpdcb->fOutX = FALSE;
+		lpdcb->fOutxCtsFlow = TRUE;
+		lpdcb->fOutxDsrFlow = TRUE;
+		lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
+		lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
 		break;
-        case 'S':
-                lpdcb->Parity = SPACEPARITY;
-                break;
 	default:
-		WARN("Unknown parity `%c'!\n", *ptr);
 		return FALSE;
 	}
 
-	ptr = strtok(NULL, ", ");
-       	TRACE("charsize (%c)\n", *ptr);
-	lpdcb->ByteSize = *ptr - '0';
-
-	ptr = strtok(NULL, ", ");
-       	TRACE("stopbits (%c)\n", *ptr);
-	switch (*ptr) {
-	case '1':
-		lpdcb->StopBits = ONESTOPBIT;
-		break;
-	case '2':
-		lpdcb->StopBits = TWOSTOPBITS;
-		break;
-	default:
-		WARN("Unknown # of stopbits `%c'!\n", *ptr);
-		return FALSE;
+	/* This should be the end of the string. */
+	if(*device) return FALSE;
+	
+	return TRUE;
+}
+
+/***********************************************************************
+ *           COMM_BuildNewCommDCB   (Internal)
+ *
+ *  Build a DCB using the new style settings string.
+ *   eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
+ */
+static BOOL COMM_BuildNewCommDCB(LPCSTR device, LPDCB lpdcb, LPCOMMTIMEOUTS lptimeouts)
+{
+	DWORD temp;
+	BOOL baud = FALSE, stop = FALSE;
+
+	while(*device)
+	{
+		while(*device == ' ') device++;
+
+		if(!strncasecmp("baud=", device, 5))
+		{
+			baud = TRUE;
+			
+			if(!(device = COMM_ParseNumber(device + 5, &lpdcb->BaudRate)))
+				return FALSE;
+		}
+		else if(!strncasecmp("parity=", device, 7))
+		{
+			if(!(device = COMM_ParseParity(device + 7, &lpdcb->Parity)))
+				return FALSE;
+		}
+		else if(!strncasecmp("data=", device, 5))
+		{
+			if(!(device = COMM_ParseByteSize(device + 5, &lpdcb->ByteSize)))
+				return FALSE;
+		}
+		else if(!strncasecmp("stop=", device, 5))
+		{
+			stop = TRUE;
+			
+			if(!(device = COMM_ParseStopBits(device + 5, &lpdcb->StopBits)))
+				return FALSE;
+		}
+		else if(!strncasecmp("to=", device, 3))
+		{
+			if(!(device = COMM_ParseOnOff(device + 3, &temp)))
+				return FALSE;
+
+			lptimeouts->ReadIntervalTimeout = 0;
+			lptimeouts->ReadTotalTimeoutMultiplier = 0;
+			lptimeouts->ReadTotalTimeoutConstant = 0;
+			lptimeouts->WriteTotalTimeoutMultiplier = 0;
+			lptimeouts->WriteTotalTimeoutConstant = temp ? 60000 : 0;
+		}
+		else if(!strncasecmp("xon=", device, 4))
+		{
+			if(!(device = COMM_ParseOnOff(device + 4, &temp)))
+				return FALSE;
+
+			lpdcb->fOutX = temp;
+			lpdcb->fInX = temp;
+		}
+		else if(!strncasecmp("odsr=", device, 5))
+		{
+			if(!(device = COMM_ParseOnOff(device + 5, &temp)))
+				return FALSE;
+
+			lpdcb->fOutxDsrFlow = temp;
+		}
+		else if(!strncasecmp("octs=", device, 5))
+		{
+			if(!(device = COMM_ParseOnOff(device + 5, &temp)))
+				return FALSE;
+
+			lpdcb->fOutxCtsFlow = temp;
+		}
+		else if(!strncasecmp("dtr=", device, 4))
+		{
+			if(!(device = COMM_ParseOnOff(device + 4, &temp)))
+				return FALSE;
+
+			lpdcb->fDtrControl = temp;
+		}
+		else if(!strncasecmp("rts=", device, 4))
+		{
+			if(!(device = COMM_ParseOnOff(device + 4, &temp)))
+				return FALSE;
+
+			lpdcb->fRtsControl = temp;
+		}
+		else if(!strncasecmp("idsr=", device, 5))
+		{
+			if(!(device = COMM_ParseOnOff(device + 5, &temp)))
+				return FALSE;
+
+			lpdcb->fDsrSensitivity = temp;
+		}
+		else
+			return FALSE;
+
+		/* After the above parsing, the next character (if not the end of
+		   the string) should be a space */
+		if(*device && *device != ' ')
+			return FALSE;
 	}
 
-	if (last == 'x') {
-		lpdcb->fInX		= TRUE;
-		lpdcb->fOutX		= TRUE;
-		lpdcb->fOutxCtsFlow	= FALSE;
-		lpdcb->fOutxDsrFlow	= FALSE;
-		lpdcb->fDtrControl	= DTR_CONTROL_ENABLE;
-		lpdcb->fRtsControl	= RTS_CONTROL_ENABLE;
-	} else if (last=='p') {
-		lpdcb->fInX		= FALSE;
-		lpdcb->fOutX		= FALSE;
-		lpdcb->fOutxCtsFlow	= TRUE;
-		lpdcb->fOutxDsrFlow	= FALSE;
-		lpdcb->fDtrControl	= DTR_CONTROL_ENABLE;
-		lpdcb->fRtsControl	= RTS_CONTROL_HANDSHAKE;
-	} else {
-		lpdcb->fInX		= FALSE;
-		lpdcb->fOutX		= FALSE;
-		lpdcb->fOutxCtsFlow	= FALSE;
-		lpdcb->fOutxDsrFlow	= FALSE;
-		lpdcb->fDtrControl	= DTR_CONTROL_ENABLE;
-		lpdcb->fRtsControl	= RTS_CONTROL_ENABLE;
+	/* If stop bits were not specified, a default is always supplied. */
+	if(!stop)
+	{
+		if(baud && lpdcb->BaudRate == 110)
+			lpdcb->StopBits = TWOSTOPBITS;
+		else
+			lpdcb->StopBits = ONESTOPBIT;
 	}
 
 	return TRUE;
@@ -318,83 +533,45 @@
 BOOL WINAPI BuildCommDCBAndTimeoutsA(
     LPCSTR         device,     /* [in] The ascii device control string. */
     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
-    LPCOMMTIMEOUTS lptimeouts) /* [in] The timeouts to use if asked to set them by the control string. */
+    LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
 {
-	int	port;
-	char	*ptr,*temp;
-
+	DCB dcb;
+	COMMTIMEOUTS timeouts;
+	BOOL result;
+	LPCSTR ptr = device;
+	
 	TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
 
-	if (!strncasecmp(device,"COM",3)) {
-		port=device[3]-'0';
-		if (port--==0) {
-			ERR("BUG! COM0 can't exist!\n");
-			return FALSE;
-		}
-		if ((*(device+4)!=':') && (*(device+4)!=' '))
-			return FALSE;
-		temp=(LPSTR)(device+5);
-	} else
-		temp=(LPSTR)device;
+	/* Set DCBlength. (Windows NT does not do this, but 9x does) */
+	lpdcb->DCBlength = sizeof(DCB);
 
-	memset(lpdcb,0,sizeof (DCB));
-	lpdcb->DCBlength	= sizeof(DCB);
-	if (strchr(temp,',')) {	/* old style */
-
-		return COMM_BuildOldCommDCB(device,lpdcb);
-	}
-	ptr=strtok(temp," ");
-	while (ptr) {
-		DWORD	flag,x;
-
-		flag=0;
-		if (!strncasecmp("baud=",ptr,5)) {
-			if (!sscanf(ptr+5,"%ld",&x))
-				WARN("Couldn't parse %s\n",ptr);
-			lpdcb->BaudRate = x;
-			flag=1;
-		}
-		if (!strncasecmp("stop=",ptr,5)) {
-			if (!sscanf(ptr+5,"%ld",&x))
-				WARN("Couldn't parse %s\n",ptr);
-			lpdcb->StopBits = x;
-			flag=1;
-		}
-		if (!strncasecmp("data=",ptr,5)) {
-			if (!sscanf(ptr+5,"%ld",&x))
-				WARN("Couldn't parse %s\n",ptr);
-			lpdcb->ByteSize = x;
-			flag=1;
-		}
-		if (!strncasecmp("parity=",ptr,7)) {
-			lpdcb->fParity	= TRUE;
-			switch (ptr[7]) {
-			case 'N':case 'n':
-				lpdcb->fParity	= FALSE;
-				lpdcb->Parity	= NOPARITY;
-				break;
-			case 'E':case 'e':
-				lpdcb->Parity	= EVENPARITY;
-				break;
-			case 'O':case 'o':
-				lpdcb->Parity	= ODDPARITY;
-				break;
-			case 'M':case 'm':
-				lpdcb->Parity	= MARKPARITY;
-				break;
-                        case 'S':case 's':
-                                lpdcb->Parity   = SPACEPARITY;
-                                break;
-			}
-			flag=1;
-		}
-		if (!flag)
-			ERR("Unhandled specifier '%s', please report.\n",ptr);
-		ptr=strtok(NULL," ");
+	/* Make a copy of the original data structures to work with since if
+	   if there is an error in the device control string the originals
+	   should not be modified (except possibly DCBlength) */
+	memcpy(&dcb, lpdcb, sizeof(DCB));
+	if(lptimeouts) memcpy(&timeouts, lptimeouts, sizeof(COMMTIMEOUTS));
+
+	ptr = COMM_ParseStart(ptr);
+
+	if(ptr == NULL)
+		result = FALSE;
+	else if(strchr(ptr, ','))
+		result = COMM_BuildOldCommDCB(ptr, &dcb);
+	else
+		result = COMM_BuildNewCommDCB(ptr, &dcb, &timeouts);
+
+	if(result)
+	{
+		memcpy(lpdcb, &dcb, sizeof(DCB));
+		if(lptimeouts) memcpy(lptimeouts, &timeouts, sizeof(COMMTIMEOUTS));
+		return TRUE;
 	}
-	if (lpdcb->BaudRate==110)
-		lpdcb->StopBits = 2;
-	return TRUE;
+	else
+	{
+		WARN("Invalid device control string: %s\n", device);
+		SetLastError(ERROR_INVALID_PARAMETER);
+		return FALSE;
+	}	
 }
 
 /**************************************************************************
@@ -411,7 +588,7 @@
 BOOL WINAPI BuildCommDCBAndTimeoutsW(
     LPCWSTR        devid,      /* [in] The unicode device control string. */
     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
-    LPCOMMTIMEOUTS lptimeouts) /* [in] The timeouts to use if asked to set them by the control string. */
+    LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
 {
 	BOOL ret = FALSE;
 	LPSTR	devidA;
@@ -2087,3 +2264,4 @@
 	}
 	return ret;
 }
+
diff -ur wine-20030813/include/winbase.h wine-20030813.patched/include/winbase.h
--- wine-20030813/include/winbase.h	2003-08-23 23:12:51.000000000 -0400
+++ wine-20030813.patched/include/winbase.h	2003-09-08 20:19:39.000000000 -0400
@@ -976,6 +976,7 @@
     char ErrorChar;
     char EofChar;
     char EvtChar;
+    WORD wReserved1;
 } DCB, *LPDCB;
 
 typedef struct tagCOMMCONFIG {

-------------- next part --------------
#include <windows.h>
#include <stdio.h>

void ShowResult(char* szVariable, DWORD data1, DWORD data2)
{
	printf(szVariable);

	if(data1 == data2)
		printf("%d\n", data1);
	else
		printf("n/a\n");
}

void main(void)
{
	char string[0x400];
	DCB dcb1, dcb2;
	COMMTIMEOUTS time1, time2;
	BOOL bResult;

	for(;;)
	{
		gets(string);
		if(strlen(string) == 0) break;

		memset(&dcb1, 0x00, sizeof(DCB));
		memset(&dcb2, 0xFF, sizeof(DCB));
		memset(&time1, 0x00, sizeof(COMMTIMEOUTS));
		memset(&time2, 0xFF, sizeof(COMMTIMEOUTS));

		bResult = BuildCommDCBAndTimeouts(string, &dcb1, &time1);
		BuildCommDCBAndTimeouts(string, &dcb2, &time2);

		if(bResult)
			printf("\nbResult : TRUE\n\n");
		else
		{
			printf("\nbResult : FALSE - ");
			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, string, sizeof(string), NULL);
			printf(string);
			printf("\n");
		}

		ShowResult("DCBlength         : ", dcb1.DCBlength, dcb2.DCBlength);
		ShowResult("BaudRate          : ", dcb1.BaudRate, dcb2.BaudRate);
		ShowResult("fBinary           : ", dcb1.fBinary, dcb2.fBinary);
		ShowResult("fParity           : ", dcb1.fParity, dcb2.fParity);
		ShowResult("fOutxCtsFlow      : ", dcb1.fOutxCtsFlow, dcb2.fOutxCtsFlow);
		ShowResult("fOutxDsrFlow      : ", dcb1.fOutxDsrFlow, dcb2.fOutxDsrFlow);
		ShowResult("fDtrControl       : ", dcb1.fDtrControl, dcb2.fDtrControl);
		ShowResult("fDsrSensitivity   : ", dcb1.fDsrSensitivity, dcb2.fDsrSensitivity);
		ShowResult("fTXContinueOnXoff : ", dcb1.fTXContinueOnXoff, dcb2.fTXContinueOnXoff);
		ShowResult("fOutX             : ", dcb1.fOutX, dcb2.fOutX);
		ShowResult("fInX              : ", dcb1.fInX, dcb2.fInX);
		ShowResult("fErrorChar        : ", dcb1.fErrorChar, dcb2.fErrorChar);
		ShowResult("fNull             : ", dcb1.fNull, dcb2.fNull);
		ShowResult("fRtsControl       : ", dcb1.fRtsControl, dcb2.fRtsControl);
		ShowResult("fAbortOnError     : ", dcb1.fAbortOnError, dcb2.fAbortOnError);
		ShowResult("fDummy2           : ", dcb1.fDummy2, dcb2.fDummy2);
		ShowResult("wReserved         : ", dcb1.wReserved, dcb2.wReserved);
		ShowResult("XonLim            : ", dcb1.XonLim, dcb2.XonLim);
		ShowResult("XoffLim           : ", dcb1.XoffLim, dcb2.XoffLim);
		ShowResult("ByteSize          : ", dcb1.ByteSize, dcb2.ByteSize);
		ShowResult("Parity            : ", dcb1.Parity, dcb2.Parity);
		ShowResult("StopBits          : ", dcb1.StopBits, dcb2.StopBits);
		ShowResult("XonChar           : ", dcb1.XonChar, dcb2.XonChar);
		ShowResult("XoffChar          : ", dcb1.XoffChar, dcb2.XoffChar);
		ShowResult("ErrorChar         : ", dcb1.ErrorChar, dcb2.ErrorChar);
		ShowResult("EofChar           : ", dcb1.EofChar, dcb2.EofChar);
		ShowResult("EvtChar           : ", dcb1.EvtChar, dcb2.EvtChar);
		ShowResult("wReserved1        : ", dcb1.wReserved1, dcb2.wReserved1);
		printf("\n");
		ShowResult("ReadIntervalTimeout         : ", time1.ReadIntervalTimeout, time2.ReadIntervalTimeout);
		ShowResult("ReadTotalTimeoutMultiplier  : ", time1.ReadTotalTimeoutMultiplier, time2.ReadTotalTimeoutMultiplier);
		ShowResult("ReadTotalTimeoutConstant    : ", time1.ReadTotalTimeoutConstant, time2.ReadTotalTimeoutConstant);
		ShowResult("WriteTotalTimeoutMultiplier : ", time1.WriteTotalTimeoutMultiplier, time2.WriteTotalTimeoutMultiplier);
		ShowResult("WriteTotalTimeoutConstant   : ", time1.WriteTotalTimeoutConstant, time2.WriteTotalTimeoutConstant);
		printf("\n");
	}
}


More information about the wine-patches mailing list