1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/misc/comm.c
Alexandre Julliard dba420a731 Release 940201
Tue Feb  1 21:14:47 1994  Bob Amstadt  (bob@pooh)

	* [loader/selector.c]
	Added function CreateNewSegments().  Modified IPCCopySelector
	to allow aliasing to any arbitrary memory space.

	* [memory/global.c]
	Fixed potential bug in GlobalGetFreeSegments().

	* [memory/linear.c]
	Created functions GlobalLinearLock() and GlobalLinearUnlock().

Tue Feb  1 05:51:43 1994  julliard@di.epfl.ch (Alexandre Julliard)

	* [controls/widgets.c]
	Removed CAPTION window class.

	* [loader/cursor.c]
	Bug fix in LoadCursor(): don't allocate memory every time for
	built-in cursors.

	* [windows/clipping.c]
	Invalidate child windows in InvalidateRgn().

	* [windows/defwnd.c]
	Added repaint of the caption when changing window text.

	* [windows/event.c]
	Modified SetCapture() to allow keyboard events while capturing.

	* [windows/message.c]
	New function MSG_GetHardwareMessage(), to do mouse tracking
	without returning control to the Windows program.

	* [windows/nonclient.c]
	A couple of changes in frame drawing for DLGMODALFRAME windows.
	Rewritten window moving code, to use MSG_GetHardwareMessage()
	instead of non-client mouse events (this is the way Windows
	does it), and to send WM_ENTERSIZEMOVE messages.
	Removed WM_NCBUTTONUP and WM_NCMOUSEMOVE handlers.

	* [windows/win.c]
	Allocate temporary structures on the USER heap instead of
	using GlobalAlloc().

	* [windows/winpos.c]
	Added function WINPOS_GetMinMaxInfo() to get sizing informations.

Jan 31, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [windows/nonclient.c]
	Call to StdDrawScrollBar() during NC's drawing.
	Call to NC_ScrollBarButtonDown() on NC mouse events WM_LBUTTONDOWN.
	Call to NC_ScrollBarButtonUp() on NC mouse events WM_LBUTTONUP.
	Call to NC_ScrollBarMouseMove() on NC mouse events WM_MOUSEMOVE.

	* [controls/menu.c]
	New GetSubMenu() function.
	Move GetMenu() & SetMenu() functions from 'windows/win.c'.

	* [controls/listbox.c]
	Start changes to satisfy recent changes in scrollbars/windows.

	* [loader/resource.c]
	Put some code in LoadAccelerators() stub.
	New TranslateAccelerator() function.

	* [windows/win.c]
	Remove GetMenu() & SetMenu() functions.
	Call to NC_CreateScrollBars() if required by CreateWindow().

Mon Jan 24 10:40:10 EST 1994 John Richardson (jrichard@cs.uml.edu)

        * [window/win.c]
        Added functions EnumWindows, EnumChildWindows, and helper
        WIN_EnumChildWin.  EnumWindows won't list all wine windows
        because GetDesktopWindow isn't complete.  However, the code
        is in place for it to work correctly and only needs 
        GetDesktopWindow to do so.  

Tue Jan 25 05:51:47 1994  julliard@di.epfl.ch (Alexandre Julliard)

	* [windows/defwnd.c]
	Added handling of activation messages (WM_ACTIVATE,
	WM_NCACTIVATE, WM_MOUSEACTIVATE)

	* [windows/event.c]
	De-activate the window when losing input focus.

	* [windows/focus.c]
	Bug fix in SetFocus().

	* [windows/message.c]
	Added activation of the window on mouse-clicks.

	* [windows/nonclient.c]
	Changed non-client area painting to use the correct colors
	depending upon the activation state.
	Added WM_NCACTIVATE message handling.
	Fixed a couple of bugs in window moving and resizing.

	* [windows/winpos.c]
	Implemented Get/SetActiveWindow().
	Implemented SWP_NOACTIVATE flag in SetWindowPos().

Jan 17, 94 martin2@trgcorp.solucorp.qc.ca (Martin Ayotte)

	* [misc/message.c]
	MessageBox has a CaptionBar for his title except for
		MB_SYSTEMMODAL with MB_ICONHAND.

	* [windows/nonclient.c]
	Call to NC_TrackSysMenu on SysMenu button mouse click.

	* [windows/defwnd.c]
	Call to NC_TrackSysMenu on Alt key (VK_MENU).

	* [controls/menu.c]
	New GetSystemMenu() function.
	New CopySystemMenu() internal function.
	New NC_TrackSysMenu() internal function.

	* [include/windows.h]
	New WM_INITMENU, WM_INITMENUPOPUP, WM_MENUSELECT & WM_MENUCHAR defines.
1994-02-02 06:48:31 +00:00

883 lines
16 KiB
C

/*
* DEC 93 Erik Bos (erik@trashcan.hacktic.nl)
*/
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#if defined(__NetBSD__) || defined(__FreeBSD__)
#include <errno.h>
#include <sys/ioctl.h>
#endif
#include "wine.h"
#include "windows.h"
#define DEBUG_COMM
#define MAX_PORTS 16
int commerror = 0, eventmask = 0;
struct DosDeviceStruct {
char *devicename; /* /dev/cua1 */
int fd;
int suspended;
int unget;
int unget_byte;
};
struct DosDeviceStruct COM[MAX_PORTS];
struct DosDeviceStruct LPT[MAX_PORTS];
void Comm_DeInit(void);
void Comm_Init(void)
{
int x, serial = 0, parallel = 0;
char option[10], temp[256], *ptr;
struct stat st;
for (x=0; x!=MAX_PORTS; x++) {
strcpy(option,"COMx");
option[3] = '0' + x;
option[4] = '\0';
GetPrivateProfileString("serialports", option, "*", temp, sizeof(temp), WINE_INI);
if (!strcmp(temp, "*") || *temp == '\0')
COM[serial].devicename = NULL;
else {
stat(temp, &st);
if (!S_ISCHR(st.st_mode))
fprintf(stderr,"comm: can 't use `%s' as COM%d !\n", temp, x);
else
if ((ptr = malloc(strlen(temp)+1)) == NULL)
fprintf(stderr,"comm: can't malloc for device info!\n");
else {
COM[serial].fd = 0;
COM[serial].devicename = ptr;
strcpy(COM[serial++].devicename, temp);
}
}
strcpy(option, "LPTx");
option[3] = '0' + x;
option[4] = '\0';
GetPrivateProfileString("parallelports", option, "*", temp, sizeof(temp), WINE_INI);
if (!strcmp(temp, "*") || *temp == '\0')
LPT[parallel].devicename = NULL;
else {
stat(temp, &st);
if (!S_ISCHR(st.st_mode))
fprintf(stderr,"comm: can 't use `%s' as LPT%d !\n", temp, x);
else
if ((ptr = malloc(strlen(temp)+1)) == NULL)
fprintf(stderr,"comm: can't malloc for device info!\n");
else {
LPT[serial].fd = 0;
LPT[serial].devicename = ptr;
strcpy(LPT[serial++].devicename, temp);
}
}
}
atexit(Comm_DeInit);
}
void Comm_DeInit(void)
{
int x;
for (x=0; x!=MAX_PORTS; x++) {
if (COM[x].devicename) {
if (COM[x].fd)
close(COM[x].fd);
free(COM[x].devicename);
}
if (LPT[x].devicename) {
if (LPT[x].fd)
close(LPT[x].fd);
free(LPT[x].devicename);
}
}
}
struct DosDeviceStruct *GetDeviceStruct(int fd)
{
int x;
for (x=0; x!=MAX_PORTS; x++) {
if (COM[x].fd == fd)
return &COM[x];
if (LPT[x].fd == fd)
return &LPT[x];
}
return NULL;
}
int ValidCOMPort(int x)
{
return(x < MAX_PORTS ? (int) COM[x].devicename : 0);
}
int ValidLPTPort(int x)
{
return(x < MAX_PORTS ? (int) LPT[x].devicename : 0);
}
int WinError(void)
{
perror("comm");
switch (errno) {
default:
return CE_IOE;
}
}
int BuildCommDCB(LPSTR device, DCB FAR *lpdcb)
{
/* "COM1:9600,n,8,1" */
/* 012345 */
int port;
char *ptr, *ptr2, temp[256],temp2[10];
#ifdef DEBUG_COMM
fprintf(stderr,"BuildCommDCB: (%s), ptr %d\n", device, lpdcb);
#endif
commerror = 0;
if (!strncmp(device,"COM",3)) {
port = device[3] - '0';
if (!ValidCOMPort(port)) {
commerror = IE_BADID;
return -1;
}
if (!COM[port].fd) {
commerror = IE_NOPEN;
return -1;
}
lpdcb->Id = COM[port].fd;
if (!*(device+4))
return 0;
if (*(device+4) != ':')
return -1;
strcpy(temp,device+5);
ptr = strtok(temp, ",");
fprintf(stderr,"BuildCommDCB: baudrate (%s)\n", ptr);
lpdcb->BaudRate = atoi(ptr);
ptr = strtok(NULL, ",");
if (islower(*ptr))
*ptr = toupper(*ptr);
fprintf(stderr,"BuildCommDCB: parity (%c)\n", *ptr);
switch (*ptr) {
case 'N':
lpdcb->Parity = NOPARITY;
lpdcb->fParity = 0;
break;
lpdcb->fParity = 1;
case 'E':
lpdcb->Parity = EVENPARITY;
break;
case 'M':
lpdcb->Parity = MARKPARITY;
break;
case 'O':
lpdcb->Parity = ODDPARITY;
break;
default:
fprintf(stderr,"comm: unknown parity `%c'!\n", *ptr);
return -1;
}
ptr = strtok(NULL, ",");
fprintf(stderr, "BuildCommDCB: charsize (%c)\n", *ptr);
lpdcb->ByteSize = *ptr - '0';
ptr = strtok(NULL, ",");
fprintf(stderr, "BuildCommDCB: stopbits (%c)\n", *ptr);
switch (*ptr) {
case '1':
lpdcb->StopBits = ONESTOPBIT;
break;
case '2':
lpdcb->StopBits = TWOSTOPBITS;
break;
default:
fprintf(stderr,"comm: unknown # of stopbits `%c'!\n", *ptr);
return -1;
}
}
return 0;
}
int OpenComm(LPSTR device, UINT cbInQueue, UINT cbOutQueue)
{
int port, fd;
#ifdef DEBUG_COMM
fprintf(stderr,"OpenComm: %s, %d, %d\n", device, cbInQueue, cbOutQueue);
#endif
commerror = 0;
if (!strncmp(device,"COM",3)) {
port = device[3] - '0';
if (!ValidCOMPort(port)) {
commerror = IE_BADID;
return -1;
}
if (COM[port].fd) {
commerror = IE_OPEN;
return -1;
}
fd = open(COM[port].devicename, O_RDWR | O_NONBLOCK, 0);
if (fd == -1) {
commerror = WinError();
return -1;
} else {
COM[port].fd = fd;
return fd;
}
}
else
if (!strncmp(device,"LPT",3)) {
port = device[3] - '0';
if (!ValidLPTPort(port)) {
commerror = IE_BADID;
return -1;
}
if (LPT[port].fd) {
commerror = IE_OPEN;
return -1;
}
fd = open(LPT[port].devicename, O_RDWR | O_NONBLOCK, 0);
if (fd == -1) {
commerror = WinError();
return -1;
} else {
LPT[port].fd = fd;
return fd;
}
}
return 0;
}
int CloseComm(int fd)
{
int status;
#ifdef DEBUG_COMM
fprintf(stderr,"CloseComm: fd %d\n", fd);
#endif
if (close(fd) == -1) {
commerror = WinError();
return -1;
} else {
commerror = 0;
return 0;
}
}
int SetCommBreak(int fd)
{
struct DosDeviceStruct *ptr;
#ifdef DEBUG_COMM
fprintf(stderr,"SetCommBreak: fd: %d\n", fd);
#endif
if ((ptr = GetDeviceStruct(fd)) == NULL) {
commerror = IE_BADID;
return -1;
}
ptr->suspended = 1;
commerror = 0;
return 0;
}
int ClearCommBreak(int fd)
{
struct DosDeviceStruct *ptr;
#ifdef DEBUG_COMM
fprintf(stderr,"ClearCommBreak: fd: %d\n", fd);
#endif
if ((ptr = GetDeviceStruct(fd)) == NULL) {
commerror = IE_BADID;
return -1;
}
ptr->suspended = 0;
commerror = 0;
return 0;
}
LONG EscapeCommFunction(int fd, int nFunction)
{
int max;
struct termios port;
#ifdef DEBUG_COMM
fprintf(stderr,"EscapeCommFunction fd: %d, function: %d\n", fd, nFunction);
#endif
if (tcgetattr(fd, &port) == -1) {
commerror = WinError();
return -1;
}
switch (nFunction) {
case RESETDEV:
break;
case GETMAXCOM:
for (max = 0;COM[max].devicename;max++)
;
return max;
break;
case GETMAXLPT:
for (max = 0;LPT[max].devicename;max++)
;
return 0x80 + max;
break;
case CLRDTR:
port.c_cflag &= TIOCM_DTR;
break;
case CLRRTS:
port.c_cflag &= TIOCM_RTS;
break;
case SETDTR:
port.c_cflag |= CRTSCTS;
break;
case SETRTS:
port.c_cflag |= CRTSCTS;
break;
case SETXOFF:
port.c_iflag |= IXOFF;
break;
case SETXON:
port.c_iflag |= IXON;
break;
default:
fprintf(stderr,"EscapeCommFunction fd: %d, unknown function: %d\n", fd, nFunction);
break;
}
if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
commerror = WinError();
return -1;
} else {
commerror = 0;
return 0;
}
}
int FlushComm(int fd, int fnQueue)
{
int queue;
#ifdef DEBUG_COMM
fprintf(stderr,"FlushComm fd: %d, queue: %d\n", fd, fnQueue);
#endif
switch (fnQueue) {
case 0:
queue = TCOFLUSH;
break;
case 1:
queue = TCIFLUSH;
break;
default:
fprintf(stderr,"FlushComm fd: %d, UNKNOWN queue: %d\n", fd, fnQueue);
return -1;
}
if (tcflush(fd, fnQueue)) {
commerror = WinError();
return -1;
} else {
commerror = 0;
return 0;
}
}
int GetCommError(int fd, COMSTAT FAR *lpStat)
{
#ifdef DEBUG_COMM
fprintf(stderr,"GetCommError: fd %d (current error %d)\n", fd, commerror);
#endif
return(commerror);
}
UINT FAR* SetCommEventMask(int fd, UINT fuEvtMask)
{
#ifdef DEBUG_COMM
fprintf(stderr,"SetCommEventMask: fd %d, mask %d\n", fd, fuEvtMask);
#endif
eventmask |= fuEvtMask;
return (UINT *)&eventmask;
}
UINT GetCommEventMask(int fd, int fnEvtClear)
{
#ifdef DEBUG_COMM
fprintf(stderr,"GetCommEventMask: fd %d, mask %d\n", fd, fnEvtClear);
#endif
eventmask &= ~fnEvtClear;
return eventmask;
}
int SetCommState(DCB FAR *lpdcb)
{
struct termios port;
#ifdef DEBUG_COMM
fprintf(stderr,"SetCommState: fd %d, ptr %d\n", lpdcb->Id, lpdcb);
#endif
if (tcgetattr(lpdcb->Id, &port) == -1) {
commerror = WinError();
return -1;
}
cfmakeraw(&port);
port.c_cc[VMIN] = 0;
port.c_cc[VTIME] = 0;
fprintf(stderr,"SetCommState: baudrate %d\n",lpdcb->BaudRate);
#ifdef CBAUD
port.c_cflag &= ~CBAUD;
switch (lpdcb->BaudRate) {
case 110:
case CBR_110:
port.c_cflag |= B110;
break;
case 300:
case CBR_300:
port.c_cflag |= B300;
break;
case 600:
case CBR_600:
port.c_cflag |= B600;
break;
case 1200:
case CBR_1200:
port.c_cflag |= B1200;
break;
case 2400:
case CBR_2400:
port.c_cflag |= B2400;
break;
case 4800:
case CBR_4800:
port.c_cflag |= B4800;
break;
case 9600:
case CBR_9600:
port.c_cflag |= B9600;
break;
case 19200:
case CBR_19200:
port.c_cflag |= B19200;
break;
case 38400:
case CBR_38400:
port.c_cflag |= B38400;
break;
default:
commerror = IE_BAUDRATE;
return -1;
}
#else
switch (lpdcb->BaudRate) {
case 110:
case CBR_110:
port.c_ospeed = B110;
break;
case 300:
case CBR_300:
port.c_ospeed = B300;
break;
case 600:
case CBR_600:
port.c_ospeed = B600;
break;
case 1200:
case CBR_1200:
port.c_ospeed = B1200;
break;
case 2400:
case CBR_2400:
port.c_ospeed = B2400;
break;
case 4800:
case CBR_4800:
port.c_ospeed = B4800;
break;
case 9600:
case CBR_9600:
port.c_ospeed = B9600;
break;
case 19200:
case CBR_19200:
port.c_ospeed = B19200;
break;
case 38400:
case CBR_38400:
port.c_ospeed = B38400;
break;
default:
commerror = IE_BAUDRATE;
return -1;
}
port.c_ispeed = port.c_ospeed;
#endif
fprintf(stderr,"SetCommState: bytesize %d\n",lpdcb->ByteSize);
port.c_cflag &= ~CSIZE;
switch (lpdcb->ByteSize) {
case 5:
port.c_cflag |= CS5;
break;
case 6:
port.c_cflag |= CS6;
break;
case 7:
port.c_cflag |= CS7;
break;
case 8:
port.c_cflag |= CS8;
break;
default:
commerror = IE_BYTESIZE;
return -1;
}
fprintf(stderr,"SetCommState: parity %d\n",lpdcb->Parity);
port.c_cflag &= ~(PARENB | PARODD);
if (lpdcb->fParity)
switch (lpdcb->Parity) {
case NOPARITY:
port.c_iflag &= ~INPCK;
break;
case ODDPARITY:
port.c_cflag |= (PARENB | PARODD);
port.c_iflag |= INPCK;
break;
case EVENPARITY:
port.c_cflag |= PARENB;
port.c_iflag |= INPCK;
break;
default:
commerror = IE_BYTESIZE;
return -1;
}
fprintf(stderr,"SetCommState: stopbits %d\n",lpdcb->StopBits);
switch (lpdcb->StopBits) {
case ONESTOPBIT:
port.c_cflag &= ~CSTOPB;
break;
case TWOSTOPBITS:
port.c_cflag |= CSTOPB;
break;
default:
commerror = IE_BYTESIZE;
return -1;
}
if (lpdcb->fDtrflow || lpdcb->fRtsflow || lpdcb->fOutxCtsFlow)
port.c_cflag |= CRTSCTS;
if (lpdcb->fDtrDisable)
port.c_cflag &= ~CRTSCTS;
if (lpdcb->fInX)
port.c_iflag |= IXON;
if (lpdcb->fOutX)
port.c_iflag |= IXOFF;
if (tcsetattr(lpdcb->Id, TCSADRAIN, &port) == -1) {
commerror = WinError();
return -1;
} else {
commerror = 0;
return 0;
}
}
int GetCommState(int fd, DCB FAR *lpdcb)
{
struct termios port;
#ifdef DEBUG_COMM
fprintf(stderr,"GetCommState: fd %d, ptr %d\n", fd, lpdcb);
#endif
if (tcgetattr(fd, &port) == -1) {
commerror = WinError();
return -1;
}
lpdcb->Id = fd;
#ifdef CBAUD
switch (port.c_cflag & CBAUD) {
#else
switch (port.c_ospeed) {
#endif
case B110:
lpdcb->BaudRate = 110;
break;
case B300:
lpdcb->BaudRate = 300;
break;
case B600:
lpdcb->BaudRate = 600;
break;
case B1200:
lpdcb->BaudRate = 1200;
break;
case B2400:
lpdcb->BaudRate = 2400;
break;
case B4800:
lpdcb->BaudRate = 4800;
break;
case B9600:
lpdcb->BaudRate = 9600;
break;
case B19200:
lpdcb->BaudRate = 19200;
break;
case B38400:
lpdcb->BaudRate = 38400;
break;
}
switch (port.c_cflag & CSIZE) {
case CS5:
lpdcb->ByteSize = 5;
break;
case CS6:
lpdcb->ByteSize = 6;
break;
case CS7:
lpdcb->ByteSize = 7;
break;
case CS8:
lpdcb->ByteSize = 8;
break;
}
switch (port.c_cflag & ~(PARENB | PARODD)) {
case 0:
lpdcb->fParity = NOPARITY;
break;
case PARENB:
lpdcb->fParity = EVENPARITY;
break;
case (PARENB | PARODD):
lpdcb->fParity = ODDPARITY;
break;
}
if (port.c_cflag & CSTOPB)
lpdcb->StopBits = TWOSTOPBITS;
else
lpdcb->StopBits = ONESTOPBIT;
lpdcb->RlsTimeout = 50;
lpdcb->CtsTimeout = 50;
lpdcb->DsrTimeout = 50;
lpdcb->fNull = 0;
lpdcb->fChEvt = 0;
lpdcb->fBinary = 1;
lpdcb->fDtrDisable = 0;
if (port.c_cflag & CRTSCTS) {
lpdcb->fDtrflow = 1;
lpdcb->fRtsflow = 1;
lpdcb->fOutxCtsFlow = 1;
lpdcb->fOutxDsrFlow = 1;
} else
lpdcb->fDtrDisable = 1;
if (port.c_iflag & IXON)
lpdcb->fInX = 1;
else
lpdcb->fInX = 0;
if (port.c_iflag & IXOFF)
lpdcb->fOutX = 1;
else
lpdcb->fOutX = 0;
/*
lpdcb->XonChar =
lpdcb->XoffChar =
*/
lpdcb->XonLim = 10;
lpdcb->XoffLim = 10;
commerror = 0;
return 0;
}
int TransmitCommChar(int fd, char chTransmit)
{
struct DosDeviceStruct *ptr;
#ifdef DEBUG_COMM
fprintf(stderr,"TransmitCommChar: fd %d, data %d \n", fd, chTransmit);
#endif
if ((ptr = GetDeviceStruct(fd)) == NULL) {
commerror = IE_BADID;
return -1;
}
if (ptr->suspended) {
commerror = IE_HARDWARE;
return -1;
}
if (write(fd, (void *) &chTransmit, 1) == -1) {
commerror = WinError();
return -1;
} else {
commerror = 0;
return 0;
}
}
int UngetCommChar(int fd, char chUnget)
{
struct DosDeviceStruct *ptr;
#ifdef DEBUG_COMM
fprintf(stderr,"UngetCommChar: fd %d (char %d)\n", fd, chUnget);
#endif
if ((ptr = GetDeviceStruct(fd)) == NULL) {
commerror = IE_BADID;
return -1;
}
if (ptr->suspended) {
commerror = IE_HARDWARE;
return -1;
}
ptr->unget = 1;
ptr->unget_byte = chUnget;
commerror = 0;
return 0;
}
int ReadComm(int fd, LPSTR lpvBuf, int cbRead)
{
int status, length;
struct DosDeviceStruct *ptr;
#ifdef DEBUG_COMM
fprintf(stderr,"ReadComm: fd %d, ptr %d, length %d\n", fd, lpvBuf, cbRead);
#endif
if ((ptr = GetDeviceStruct(fd)) == NULL) {
commerror = IE_BADID;
return -1;
}
if (ptr->suspended) {
commerror = IE_HARDWARE;
return -1;
}
if (ptr->unget) {
*lpvBuf = ptr->unget_byte;
lpvBuf++;
ptr->unget = 0;
length = 1;
} else
length = 0;
status = read(fd, (void *) lpvBuf, cbRead);
if (status == -1) {
commerror = WinError();
return -1 - length;
} else {
commerror = 0;
return length + status;
}
}
int WriteComm(int fd, LPSTR lpvBuf, int cbWrite)
{
int x, length;
struct DosDeviceStruct *ptr;
#ifdef DEBUG_COMM
fprintf(stderr,"WriteComm: fd %d, ptr %d, length %d\n", fd, lpvBuf, cbWrite);
#endif
if ((ptr = GetDeviceStruct(fd)) == NULL) {
commerror = IE_BADID;
return -1;
}
if (ptr->suspended) {
commerror = IE_HARDWARE;
return -1;
}
#ifdef DEBUG_COMM
for (x=0; x != cbWrite ; x++)
fprintf(stderr,"%c", *(lpvBuf + x) );
#endif
length = write(fd, (void *) lpvBuf, cbWrite);
if (length == -1) {
commerror = WinError();
return -1;
} else {
commerror = 0;
return length;
}
}