Attribute VB_Name = "modCOMM"
OPTION EXPLICIT
Public CONST LINE_BREAK = 1
Public CONST LINE_DTR = 2
Public CONST LINE_RTS = 3
Public CONST LINE_CTS = &H10&
Public CONST LINE_DSR = &H20&
Public CONST LINE_RING = &H40&
Public CONST LINE_RLSD = &H80&
Public CONST LINE_CD = &H80&
Private CONST ERROR_IO_INCOMPLETE = 996&
Private CONST ERROR_IO_PENDING = 997
Private CONST GENERIC_READ = &H80000000
Private CONST GENERIC_WRITE = &H40000000
Private CONST FILE_ATTRIBUTE_NORMAL = &H80
Private CONST FILE_FLAG_OVERLAPPED = &H40000000
Private CONST FORMAT_MESSAGE_FROM_SYSTEM = &H1000
Private CONST OPEN_EXISTING = 3
Private CONST MS_CTS_ON = &H10&
Private CONST MS_DSR_ON = &H20&
Private CONST MS_RING_ON = &H40&
Private CONST MS_RLSD_ON = &H80&
Private CONST PURGE_RXABORT = &H2
Private CONST PURGE_RXCLEAR = &H8
Private CONST PURGE_TXABORT = &H1
Private CONST PURGE_TXCLEAR = &H4
Private CONST CLRBREAK = 9
Private CONST CLRDTR = 6
Private CONST CLRRTS = 4
Private CONST SETBREAK = 8
Private CONST SETDTR = 5
Private CONST SETRTS = 3
Private TYPE COMSTAT
fBitFields AS LONG
cbInQue AS LONG
cbOutQue AS LONG
END TYPE
Private TYPE COMMTIMEOUTS
ReadIntervalTimeout AS LONG
ReadTotalTimeoutMultiplier AS LONG
ReadTotalTimeoutConstant AS LONG
WriteTotalTimeoutMultiplier AS LONG
WriteTotalTimeoutConstant AS LONG
END TYPE
Private TYPE DCB
DCBlength AS LONG
BaudRate AS LONG
fBitFields AS LONG
wReserved AS INTEGER
XonLim AS INTEGER
XoffLim AS INTEGER
ByteSize AS BYTE
Parity AS BYTE
StopBits AS BYTE
XonChar AS BYTE
XoffChar AS BYTE
ErrorChar AS BYTE
EofChar AS BYTE
EvtChar AS BYTE
wReserved1 AS INTEGER
END TYPE
Private TYPE OVERLAPPED
Internal AS LONG
InternalHigh AS LONG
offset AS LONG
OffsetHigh AS LONG
hEvent AS LONG
END TYPE
Private TYPE SECURITY_ATTRIBUTES
nLength AS LONG
lpSecurityDescriptor AS LONG
bInheritHandle AS LONG
END TYPE
DECLARE FUNCTION BuildCommDCB LIB "kernel32" ALIAS "BuildCommDCBA" _
(BYVAL lpDef AS STRING, lpDCB AS DCB) AS LONG
DECLARE FUNCTION ClearCommError LIB "kernel32" _
(BYVAL hFile AS LONG, lpErrors AS LONG, lpStat AS COMSTAT) AS LONG
DECLARE FUNCTION CloseHandle LIB "kernel32" (BYVAL hObject AS LONG) AS LONG
DECLARE FUNCTION CreateFile LIB "kernel32" ALIAS "CreateFileA" _
(BYVAL lpFileName AS STRING, BYVAL dwDesiredAccess AS LONG, _
BYVAL dwShareMode AS LONG, lpSecurityAttributes AS ANY, _
BYVAL dwCreationDisposition AS LONG, BYVAL dwFlagsAndAttributes AS LONG, _
BYVAL hTemplateFile AS LONG) AS LONG
DECLARE FUNCTION EscapeCommFunction LIB "kernel32" _
(BYVAL nCid AS LONG, BYVAL nFunc AS LONG) AS LONG
DECLARE FUNCTION FormatMessage LIB "kernel32" ALIAS "FormatMessageA" _
(BYVAL dwFlags AS LONG, lpSource AS ANY, BYVAL dwMessageId AS LONG, _
BYVAL dwLanguageId AS LONG, BYVAL lpBuffer AS STRING, BYVAL nSize AS LONG, _
Arguments AS LONG) AS LONG
DECLARE FUNCTION GetCommModemStatus LIB "kernel32" _
(BYVAL hFile AS LONG, lpModemStat AS LONG) AS LONG
DECLARE FUNCTION GetCommState LIB "kernel32" _
(BYVAL nCid AS LONG, lpDCB AS DCB) AS LONG
DECLARE FUNCTION GetLastError LIB "kernel32" () AS LONG
DECLARE FUNCTION GetOverlappedResult LIB "kernel32" _
(BYVAL hFile AS LONG, lpOverlapped AS OVERLAPPED, _
lpNumberOfBytesTransferred AS LONG, BYVAL bWait AS LONG) AS LONG
DECLARE FUNCTION PurgeComm LIB "kernel32" _
(BYVAL hFile AS LONG, BYVAL dwFlags AS LONG) AS LONG
DECLARE FUNCTION ReadFile LIB "kernel32" _
(BYVAL hFile AS LONG, BYVAL lpBuffer AS STRING, _
BYVAL nNumberOfBytesToRead AS LONG, ByRef lpNumberOfBytesRead AS LONG, _
lpOverlapped AS OVERLAPPED) AS LONG
DECLARE FUNCTION SetCommState LIB "kernel32" _
(BYVAL hCommDev AS LONG, lpDCB AS DCB) AS LONG
DECLARE FUNCTION SetCommTimeouts LIB "kernel32" _
(BYVAL hFile AS LONG, lpCommTimeouts AS COMMTIMEOUTS) AS LONG
DECLARE FUNCTION SetupComm LIB "kernel32" _
(BYVAL hFile AS LONG, BYVAL dwInQueue AS LONG, BYVAL dwOutQueue AS LONG) AS LONG
DECLARE FUNCTION WriteFile LIB "kernel32" _
(BYVAL hFile AS LONG, BYVAL lpBuffer AS STRING, _
BYVAL nNumberOfBytesToWrite AS LONG, lpNumberOfBytesWritten AS LONG, _
lpOverlapped AS OVERLAPPED) AS LONG
Private CONST MAX_PORTS = 4
Private TYPE COMM_ERROR
lngErrorCode AS LONG
strFunction AS STRING
strErrorMessage AS STRING
END TYPE
Private TYPE COMM_PORT
lngHandle AS LONG
blnPortOpen AS Boolean
udtDCB AS DCB
END TYPE
Private udtCommOverlap AS OVERLAPPED
Private udtCommError AS COMM_ERROR
Private udtPorts(1 TO MAX_PORTS) AS COMM_PORT
Public FUNCTION GetSystemMessage(lngErrorCode AS LONG) AS STRING
DIM intPos AS INTEGER
DIM strMessage AS STRING, strMsgBuff AS STRING * 256
CALL FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, lngErrorCode, 0, strMsgBuff, 255, 0)
intPos = INSTR(1, strMsgBuff, vbNullChar)
IF intPos > 0 THEN
strMessage = Trim$(LEFT$(strMsgBuff, intPos - 1))
ELSE
strMessage = Trim$(strMsgBuff)
END IF
GetSystemMessage = strMessage
END FUNCTION
Public FUNCTION CommOpen(intPortID AS INTEGER, strPort AS STRING, _
strSettings AS STRING) AS LONG
DIM lngStatus AS LONG
DIM udtCommTimeOuts AS COMMTIMEOUTS
ON ERROR GOTO Routine_Error
IF udtPorts(intPortID).blnPortOpen THEN
lngStatus = -1
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommOpen"
.strErrorMessage = "Port in use."
END WITH
GOTO Routine_Exit
END IF
udtPorts(intPortID).lngHandle = CreateFile(strPort, GENERIC_READ OR _
GENERIC_WRITE, 0, BYVAL 0&, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
IF udtPorts(intPortID).lngHandle = -1 THEN
lngStatus = SetCommError("CommOpen (CreateFile)")
GOTO Routine_Exit
END IF
udtPorts(intPortID).blnPortOpen = True
lngStatus = SetupComm(udtPorts(intPortID).lngHandle, 1024, 1024)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommOpen (SetupComm)")
GOTO Routine_Exit
END IF
lngStatus = PurgeComm(udtPorts(intPortID).lngHandle, PURGE_TXABORT OR _
PURGE_RXABORT OR PURGE_TXCLEAR OR PURGE_RXCLEAR)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommOpen (PurgeComm)")
GOTO Routine_Exit
END IF
WITH udtCommTimeOuts
.ReadIntervalTimeout = -1
.ReadTotalTimeoutMultiplier = 0
.ReadTotalTimeoutConstant = 1000
.WriteTotalTimeoutMultiplier = 0
.WriteTotalTimeoutMultiplier = 1000
END WITH
lngStatus = SetCommTimeouts(udtPorts(intPortID).lngHandle, udtCommTimeOuts)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommOpen (SetCommTimeouts)")
GOTO Routine_Exit
END IF
lngStatus = GetCommState(udtPorts(intPortID).lngHandle, _
udtPorts(intPortID).udtDCB)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommOpen (GetCommState)")
GOTO Routine_Exit
END IF
lngStatus = BuildCommDCB(strSettings, udtPorts(intPortID).udtDCB)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommOpen (BuildCommDCB)")
GOTO Routine_Exit
END IF
lngStatus = SetCommState(udtPorts(intPortID).lngHandle, _
udtPorts(intPortID).udtDCB)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommOpen (SetCommState)")
GOTO Routine_Exit
END IF
lngStatus = 0
Routine_Exit:
CommOpen = lngStatus
EXIT FUNCTION
Routine_Error:
lngStatus = Err.Number
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommOpen"
.strErrorMessage = Err.Description
END WITH
RESUME Routine_Exit
END FUNCTION
Private FUNCTION SetCommError(strFunction AS STRING) AS LONG
WITH udtCommError
.lngErrorCode = Err.LastDllError
.strFunction = strFunction
.strErrorMessage = GetSystemMessage(.lngErrorCode)
SetCommError = .lngErrorCode
END WITH
END FUNCTION
Private FUNCTION SetCommErrorEx(strFunction AS STRING, lngHnd AS LONG) AS LONG
DIM lngErrorFlags AS LONG
DIM udtCommStat AS COMSTAT
WITH udtCommError
.lngErrorCode = GetLastError
.strFunction = strFunction
.strErrorMessage = GetSystemMessage(.lngErrorCode)
CALL ClearCommError(lngHnd, lngErrorFlags, udtCommStat)
.strErrorMessage = .strErrorMessage & " COMM Error Flags = " & _
HEX$(lngErrorFlags)
SetCommErrorEx = .lngErrorCode
END WITH
END FUNCTION
Public FUNCTION CommSet(intPortID AS INTEGER, strSettings AS STRING) AS LONG
DIM lngStatus AS LONG
ON ERROR GOTO Routine_Error
lngStatus = GetCommState(udtPorts(intPortID).lngHandle, _
udtPorts(intPortID).udtDCB)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommSet (GetCommState)")
GOTO Routine_Exit
END IF
lngStatus = BuildCommDCB(strSettings, udtPorts(intPortID).udtDCB)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommSet (BuildCommDCB)")
GOTO Routine_Exit
END IF
lngStatus = SetCommState(udtPorts(intPortID).lngHandle, _
udtPorts(intPortID).udtDCB)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommSet (SetCommState)")
GOTO Routine_Exit
END IF
lngStatus = 0
Routine_Exit:
CommSet = lngStatus
EXIT FUNCTION
Routine_Error:
lngStatus = Err.Number
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommSet"
.strErrorMessage = Err.Description
END WITH
RESUME Routine_Exit
END FUNCTION
Public FUNCTION CommClose(intPortID AS INTEGER) AS LONG
DIM lngStatus AS LONG
ON ERROR GOTO Routine_Error
IF udtPorts(intPortID).blnPortOpen THEN
lngStatus = CloseHandle(udtPorts(intPortID).lngHandle)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommClose (CloseHandle)")
GOTO Routine_Exit
END IF
udtPorts(intPortID).blnPortOpen = False
END IF
lngStatus = 0
Routine_Exit:
CommClose = lngStatus
EXIT FUNCTION
Routine_Error:
lngStatus = Err.Number
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommClose"
.strErrorMessage = Err.Description
END WITH
RESUME Routine_Exit
END FUNCTION
Public FUNCTION CommFlush(intPortID AS INTEGER) AS LONG
DIM lngStatus AS LONG
ON ERROR GOTO Routine_Error
lngStatus = PurgeComm(udtPorts(intPortID).lngHandle, PURGE_TXABORT OR _
PURGE_RXABORT OR PURGE_TXCLEAR OR PURGE_RXCLEAR)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommFlush (PurgeComm)")
GOTO Routine_Exit
END IF
lngStatus = 0
Routine_Exit:
CommFlush = lngStatus
EXIT FUNCTION
Routine_Error:
lngStatus = Err.Number
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommFlush"
.strErrorMessage = Err.Description
END WITH
RESUME Routine_Exit
END FUNCTION
Public FUNCTION CommRead(intPortID AS INTEGER, strData AS STRING, _
lngSize AS LONG) AS LONG
DIM lngStatus AS LONG
DIM lngRdSize AS LONG, lngBytesRead AS LONG
DIM lngRdStatus AS LONG, strRdBuffer AS STRING * 1024
DIM lngErrorFlags AS LONG, udtCommStat AS COMSTAT
ON ERROR GOTO Routine_Error
strData = ""
lngBytesRead = 0
DOEVENTS
lngStatus = ClearCommError(udtPorts(intPortID).lngHandle, lngErrorFlags, _
udtCommStat)
IF lngStatus = 0 THEN
lngBytesRead = -1
lngStatus = SetCommError("CommRead (ClearCommError)")
GOTO Routine_Exit
END IF
IF udtCommStat.cbInQue > 0 THEN
IF udtCommStat.cbInQue > lngSize THEN
lngRdSize = udtCommStat.cbInQue
ELSE
lngRdSize = lngSize
END IF
ELSE
lngRdSize = 0
END IF
IF lngRdSize THEN
lngRdStatus = ReadFile(udtPorts(intPortID).lngHandle, strRdBuffer, _
lngRdSize, lngBytesRead, udtCommOverlap)
IF lngRdStatus = 0 THEN
lngStatus = GetLastError
IF lngStatus = ERROR_IO_PENDING THEN
WHILE GetOverlappedResult(udtPorts(intPortID).lngHandle, _
udtCommOverlap, lngBytesRead, True) = 0
lngStatus = GetLastError
IF lngStatus <> ERROR_IO_INCOMPLETE THEN
lngBytesRead = -1
lngStatus = SetCommErrorEx( _
"CommRead (GetOverlappedResult)", _
udtPorts(intPortID).lngHandle)
GOTO Routine_Exit
END IF
WEND
ELSE
lngBytesRead = -1
lngStatus = SetCommErrorEx("CommRead (ReadFile)", _
udtPorts(intPortID).lngHandle)
GOTO Routine_Exit
END IF
END IF
strData = LEFT$(strRdBuffer, lngBytesRead)
END IF
Routine_Exit:
CommRead = lngBytesRead
EXIT FUNCTION
Routine_Error:
lngBytesRead = -1
lngStatus = Err.Number
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommRead"
.strErrorMessage = Err.Description
END WITH
RESUME Routine_Exit
END FUNCTION
Public FUNCTION CommWrite(intPortID AS INTEGER, strData AS STRING) AS LONG
DIM i AS INTEGER
DIM lngStatus AS LONG, lngSize AS LONG
DIM lngWrSize AS LONG, lngWrStatus AS LONG
ON ERROR GOTO Routine_Error
lngSize = LEN(strData)
lngWrStatus = WriteFile(udtPorts(intPortID).lngHandle, strData, lngSize, _
lngWrSize, udtCommOverlap)
DOEVENTS
IF lngWrStatus = 0 THEN
lngStatus = GetLastError
IF lngStatus = 0 THEN
GOTO Routine_Exit
ELSEIF lngStatus = ERROR_IO_PENDING THEN
WHILE GetOverlappedResult(udtPorts(intPortID).lngHandle, _
udtCommOverlap, lngWrSize, True) = 0
lngStatus = GetLastError
IF lngStatus <> ERROR_IO_INCOMPLETE THEN
lngStatus = SetCommErrorEx( _
"CommWrite (GetOverlappedResult)", _
udtPorts(intPortID).lngHandle)
GOTO Routine_Exit
END IF
WEND
ELSE
lngWrSize = -1
lngStatus = SetCommErrorEx("CommWrite (WriteFile)", _
udtPorts(intPortID).lngHandle)
GOTO Routine_Exit
END IF
END IF
FOR i = 1 TO 10
DOEVENTS
NEXT
Routine_Exit:
CommWrite = lngWrSize
EXIT FUNCTION
Routine_Error:
lngStatus = Err.Number
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommWrite"
.strErrorMessage = Err.Description
END WITH
RESUME Routine_Exit
END FUNCTION
Public FUNCTION CommGetLine(intPortID AS INTEGER, intLine AS INTEGER, _
blnState AS Boolean) AS LONG
DIM lngStatus AS LONG
DIM lngComStatus AS LONG, lngModemStatus AS LONG
ON ERROR GOTO Routine_Error
lngStatus = GetCommModemStatus(udtPorts(intPortID).lngHandle, lngModemStatus)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommReadCD (GetCommModemStatus)")
GOTO Routine_Exit
END IF
IF (lngModemStatus AND intLine) THEN
blnState = True
ELSE
blnState = False
END IF
lngStatus = 0
Routine_Exit:
CommGetLine = lngStatus
EXIT FUNCTION
Routine_Error:
lngStatus = Err.Number
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommReadCD"
.strErrorMessage = Err.Description
END WITH
RESUME Routine_Exit
END FUNCTION
Public FUNCTION CommSetLine(intPortID AS INTEGER, intLine AS INTEGER, _
blnState AS Boolean) AS LONG
DIM lngStatus AS LONG
DIM lngNewState AS LONG
ON ERROR GOTO Routine_Error
IF intLine = LINE_BREAK THEN
IF blnState THEN
lngNewState = SETBREAK
ELSE
lngNewState = CLRBREAK
END IF
ELSEIF intLine = LINE_DTR THEN
IF blnState THEN
lngNewState = SETDTR
ELSE
lngNewState = CLRDTR
END IF
ELSEIF intLine = LINE_RTS THEN
IF blnState THEN
lngNewState = SETRTS
ELSE
lngNewState = CLRRTS
END IF
END IF
lngStatus = EscapeCommFunction(udtPorts(intPortID).lngHandle, lngNewState)
IF lngStatus = 0 THEN
lngStatus = SetCommError("CommSetLine (EscapeCommFunction)")
GOTO Routine_Exit
END IF
lngStatus = 0
Routine_Exit:
CommSetLine = lngStatus
EXIT FUNCTION
Routine_Error:
lngStatus = Err.Number
WITH udtCommError
.lngErrorCode = lngStatus
.strFunction = "CommSetLine"
.strErrorMessage = Err.Description
END WITH
RESUME Routine_Exit
END FUNCTION
Public FUNCTION CommGetError(strMessage AS STRING) AS LONG
WITH udtCommError
CommGetError = .lngErrorCode
strMessage = "Error (" & CStr(.lngErrorCode) & "): " & .strFunction & _
" - " & .strErrorMessage
END WITH
END FUNCTION
|
|