home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2002 September / PCPlus_193_Laplink2000.iso / Prog / vb / comm / CommControl.vb < prev    next >
Encoding:
Text File  |  2002-04-29  |  14.6 KB  |  383 lines

  1. Imports System.Runtime.InteropServices
  2. Imports System.Threading
  3. Public Class CommControl
  4.     Inherits System.Windows.Forms.UserControl
  5.  
  6. #Region " Windows Form Designer generated code "
  7.  
  8.     Public Sub New()
  9.         MyBase.New()
  10.  
  11.         'This call is required by the Windows Form Designer.
  12.         InitializeComponent()
  13.  
  14.         'Add any initialization after the InitializeComponent() call
  15.  
  16.     End Sub
  17.  
  18.     'UserControl overrides dispose to clean up the component list.
  19.     Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
  20.         If disposing Then
  21.             If Not (components Is Nothing) Then
  22.                 components.Dispose()
  23.             End If
  24.         End If
  25.         MyBase.Dispose(disposing)
  26.     End Sub
  27.  
  28.     'Required by the Windows Form Designer
  29.     Private components As System.ComponentModel.IContainer
  30.  
  31.     'NOTE: The following procedure is required by the Windows Form Designer
  32.     'It can be modified using the Windows Form Designer.  
  33.     'Do not modify it using the code editor.
  34.     <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
  35.         '
  36.         'CommControl
  37.         '
  38.         Me.Name = "CommControl"
  39.  
  40.     End Sub
  41.  
  42. #End Region
  43.  
  44.     Private Sub CommControl_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  45.  
  46.         GCHandle.Alloc(o, GCHandleType.Pinned)
  47.         GCHandle.Alloc(bytesWritten, GCHandleType.Pinned)
  48.         GCHandle.Alloc(bytesRead, GCHandleType.Pinned)
  49.         GCHandle.Alloc(readBuffer, GCHandleType.Pinned)
  50.  
  51.     End Sub
  52.  
  53.     Private o As OVERLAPPED
  54.     Private evtMask As Integer ' event mask
  55.     Private h As Integer ' port handle
  56.     Private bytesRead As Integer ' number of bytes in read
  57.     Private bytesWritten As Integer ' number of bytes written
  58.     Private readBuffer(1000) As Byte ' main read buffer
  59.     Private readBufferPosition As Integer ' position in main read buffer
  60.     Event commEvent(ByVal m As Integer)
  61.     Private CTS_State As Boolean ' CTS property value
  62.     Private DTR_State As Boolean ' DTR property value
  63.     Private write_in_progress As Boolean
  64.  
  65.     Structure SECURITY_ATTRIBUTES
  66.         Public nLength As Integer
  67.         Public lpSecurityDescriptor As Integer
  68.         Public bInheritHandle As Integer
  69.     End Structure
  70.  
  71.     Structure OVERLAPPED
  72.         Private Internal As Integer
  73.         Private InternalHigh As Integer
  74.         Private offset As Integer
  75.         Private OffsetHigh As Integer
  76.         Public hEvent As Integer
  77.     End Structure
  78.  
  79.     Public Structure DCB
  80.         Public DCBlength As Integer
  81.         Public BaudRate As Integer
  82.         Public fBitFields As Integer
  83.         Private wReserved As Short
  84.         Public XonLim As Short
  85.         Public XoffLim As Short
  86.         Public ByteSize As Byte
  87.         Public Parity As Byte
  88.         Public StopBits As Byte
  89.         Public XonChar As Byte
  90.         Public XoffChar As Byte
  91.         Public ErrorChar As Byte
  92.         Public EofChar As Byte
  93.         Public EvtChar As Byte
  94.         Private wReserved1 As Short
  95.     End Structure
  96.  
  97.     Public Structure COMMTIMEOUTS
  98.         Public ReadIntervalTimeout As Integer
  99.         Public ReadTotalTimeoutMultiplier As Integer
  100.         Public ReadTotalTimeoutConstant As Integer
  101.         Public WriteTotalTimeoutMultiplier As Integer
  102.         Public WriteTotalTimeoutConstant As Integer
  103.     End Structure
  104.  
  105.     Const GENERIC_WRITE As Integer = &H40000000
  106.     Const GENERIC_READ As Integer = &H80000000
  107.     Const CREATE_ALWAYS As Integer = 2
  108.     Const OPEN_EXISTING As Integer = 3
  109.     Const FILE_FLAG_NO_BUFFERING As Integer = &H20000000
  110.     Const FILE_FLAG_WRITE_THROUGH As Integer = &H80000000
  111.     Const FILE_FLAG_DELETE_ON_CLOSE As Integer = &H4000000
  112.     Const FILE_FLAG_OVERLAPPED As Integer = &H40000000
  113.     Const ERROR_IO_INCOMPLETE As Integer = 996
  114.     Const ERROR_IO_PENDING As Integer = 997
  115.     Const INFINITE = &HFFFFFFFF ' infinite timeout
  116.  
  117.     Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Integer, ByVal dwShareMode As Integer, ByVal lpSecurityAttributes As Integer, ByVal dwCreationDisposition As Integer, ByVal dwFlagsAndAttributes As Integer, ByVal hTemplateFile As Integer) As Integer
  118.     Declare Function GetLastError Lib "kernel32" Alias "GetLastError" () As Integer
  119.     Declare Function ReadFile Lib "kernel32" (ByVal hFile As Integer, ByRef lpBuffer As Byte, ByVal nNumberOfBytesToRead As Integer, ByRef lpNumberOfBytesRead As Integer, ByRef lpOverlapped As OVERLAPPED) As Integer
  120.     Declare Function WriteFile Lib "kernel32" (ByVal hFile As Integer, ByVal lpBuffer() As Byte, ByVal nNumberOfBytesToWrite As Integer, ByRef lpNumberofBytesWritten As Integer, ByRef lpOverlapped As OVERLAPPED) As Integer
  121.     Declare Function CloseHandle Lib "kernel32" (ByVal hFile As Integer) As Integer
  122.     Declare Function SetCommState Lib "kernel32" Alias "SetCommState" (ByVal hFile As Integer, ByRef lpDCB As DCB) As Integer
  123.     Declare Function EscapeCommFunction Lib "kernel32" Alias "EscapeCommFunction" (ByVal hFile As Integer, ByVal nFunc As Integer) As Integer
  124.     Declare Function GetCommModemStatus Lib "kernel32" Alias "GetCommModemStatus" (ByVal hFile As Integer, ByRef lpModemStat As Integer) As Integer
  125.     Declare Function SetCommMask Lib "kernel32" Alias "SetCommMask" (ByVal hFile As Integer, ByVal dwEvtMask As Integer) As Integer
  126.     Declare Function WaitCommEvent Lib "kernel32" Alias "WaitCommEvent" (ByVal hFile As Integer, ByRef lpEvtMask As Integer, ByRef lpOverlapped As OVERLAPPED) As Integer
  127.     Declare Function CreateEvent Lib "kernel32" Alias "CreateEventW" (ByRef lpEventAttributes As SECURITY_ATTRIBUTES, ByVal bManualReset As Integer, ByVal bInitialState As Integer, ByVal lpName As String) As Integer
  128.     Declare Function WaitForSingleObject Lib "kernel32" Alias "WaitForSingleObject" (ByVal hHandle As Integer, ByVal dwMilliseconds As Integer) As Integer
  129.     Declare Function GetOverlappedResult Lib "kernel32" Alias "GetOverlappedResult" (ByVal hFile As Integer, ByRef lpOverlapped As OVERLAPPED, ByRef lpNumberOfBytesTransferred As Integer, ByVal bWait As Integer) As Integer
  130.     Declare Function ResetEvent Lib "kernel32" Alias "ResetEvent" (ByVal hEvent As Integer) As Integer
  131.     Declare Function SetCommTimeouts Lib "kernel32" Alias "SetCommTimeouts" (ByVal hFile As Integer, ByRef lpCommTimeouts As COMMTIMEOUTS) As Integer
  132.  
  133.     Public Const EV_RXCHAR = &H1                '  character received
  134.     Public Const EV_TXEMPTY = &H4              '  Write completed
  135.     Public Const EV_RLSD = &H20                 '  RLSD changed state
  136.     Public Const EV_CTS = &H8                   '  CTS changed state
  137.     Public Const EV_DSR = &H10                  '  DSR changed state
  138.     Public Const EV_RING = &H100                '  Ring signal detected
  139.  
  140.     Const SETRTS = 3 '  Set RTS high
  141.     Const CLRRTS = 4 '  Set RTS low
  142.     Const SETDTR = 5 '  Set DTR high
  143.     Const CLRDTR = 6 '  Set DTR low
  144.  
  145.     Const MS_CTS_ON = &H10
  146.     Const MS_DSR_ON = &H20
  147.     Const MS_RING_ON = &H40
  148.     Const MS_RLSD_ON = &H80
  149.  
  150.     Const WAIT_OBJECT_0 = &H0
  151.     Const WAIT_TIMEOUT = &H102
  152.  
  153.     WriteOnly Property DTR() As Boolean
  154.         Set(ByVal Value As Boolean)
  155.             Dim r As Integer
  156.             If Value = True Then
  157.                 r = EscapeCommFunction(h, SETDTR)
  158.             Else
  159.                 r = EscapeCommFunction(h, CLRDTR)
  160.             End If
  161.             If r <> 1 Then
  162.                 r = GetLastError()
  163.                 Throw New System.Exception("Failed to set/clear DTR")
  164.             End If
  165.         End Set
  166.     End Property
  167.     WriteOnly Property RTS() As Boolean
  168.         Set(ByVal Value As Boolean)
  169.             Dim r As Integer
  170.             If Value = True Then
  171.                 r = EscapeCommFunction(h, SETRTS)
  172.             Else
  173.                 r = EscapeCommFunction(h, CLRRTS)
  174.             End If
  175.             If r <> 1 Then
  176.                 r = GetLastError()
  177.                 Throw New System.Exception("Failed to set/clear RTS")
  178.             End If
  179.         End Set
  180.     End Property
  181.     ReadOnly Property DSR() As Boolean
  182.         Get
  183.             Dim r As Integer
  184.             Dim modem_status As Integer
  185.  
  186.             r = GetCommModemStatus(h, modem_status)
  187.             If r <> 1 Then
  188.                 r = GetLastError()
  189.                 Throw New System.Exception("Failed to get DSR state")
  190.             End If
  191.  
  192.             Return CBool(modem_status And MS_DSR_ON)
  193.  
  194.         End Get
  195.     End Property
  196.     ReadOnly Property CTS() As Boolean
  197.         Get
  198.             Dim r As Integer
  199.             Dim modem_status As Integer
  200.  
  201.             r = GetCommModemStatus(h, modem_status)
  202.             If r <> 1 Then
  203.                 r = GetLastError()
  204.                 Throw New System.Exception("Failed to get CTS state")
  205.             End If
  206.  
  207.             Return CBool(modem_status And MS_CTS_ON)
  208.  
  209.         End Get
  210.     End Property
  211.  
  212.     Public Function Open(ByVal portnumber As Integer) As Integer
  213.         Dim r As Integer, portname As String
  214.  
  215.         portname = "COM" + portnumber.ToString
  216.         Try
  217.             h = CreateFile(portname, GENERIC_READ Or GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0)
  218.             If h = -1 Then
  219.                 r = GetLastError()
  220.                 Throw New System.Exception("Port open failed")
  221.             End If
  222.         Finally
  223.             r = 1
  224.         End Try
  225.         Open = r
  226.  
  227.     End Function
  228.     Public Function Open(ByVal portnumber As Integer, ByVal speed As String) As Integer
  229.         Dim r As Integer, d As DCB
  230.  
  231.         Open(portnumber)
  232.         d.BaudRate = Int(speed)
  233.         d.ByteSize = 8
  234.         d.Parity = 0 ' no parity
  235.         d.StopBits = 0 ' one stop bit
  236.         d.fBitFields = 1 ' set binary mode
  237.         d.DCBlength = Marshal.SizeOf(d)
  238.         r = SetCommState(h, d)
  239.         If r <> 1 Then
  240.             r = GetLastError()
  241.             Throw New System.Exception("Port open failed")
  242.         End If
  243.         r = 1
  244.  
  245.     End Function
  246.     Public Function OpenWithEvents(ByVal portnumber As Integer, ByVal speed As String) As Integer
  247.         Dim r, m As Integer
  248.         Dim t As Thread
  249.         Dim cto As COMMTIMEOUTS
  250.  
  251.         Open(portnumber, speed)
  252.         o.hEvent = CreateEvent(Nothing, 1, 0, portnumber.ToString)
  253.         m = EV_CTS Or EV_DSR Or EV_RING Or EV_RLSD Or EV_RXCHAR Or EV_TXEMPTY
  254.         r = SetCommMask(h, m)
  255.         If r <> 1 Then
  256.             r = GetLastError()
  257.             Throw New System.Exception("SetCommMask failed")
  258.         End If
  259.  
  260.         cto.ReadIntervalTimeout = INFINITE
  261.         cto.ReadTotalTimeoutConstant = 0
  262.         cto.ReadTotalTimeoutMultiplier = 0
  263.         cto.WriteTotalTimeoutConstant = 0
  264.         cto.WriteTotalTimeoutMultiplier = 0
  265.         r = SetCommTimeouts(h, cto)
  266.         If r <> 1 Then
  267.             r = GetLastError()
  268.             Throw New System.Exception("SetCommTimeouts failed")
  269.         End If
  270.  
  271.         t = New Thread(AddressOf eventThread)
  272.         t.Start()
  273.  
  274.     End Function
  275.     Public Sub Write(ByRef buf As String)
  276.         Dim r As Integer, i As Integer
  277.         Dim b(buf.Length - 1) As Byte
  278.  
  279.         SyncLock GetType(CommControl)
  280.             If write_in_progress Then
  281.                 Throw New System.Exception("Write in progress")
  282.             Else
  283.                 ' copy into byte array
  284.                 For i = 0 To buf.Length - 1
  285.                     b(i) = Asc(buf.Chars(i))
  286.                 Next
  287.                 ' issue the write
  288.                 r = WriteFile(h, b, b.Length, bytesWritten, o)
  289.                 If r <> 1 Then
  290.                     r = GetLastError()
  291.                     If r <> ERROR_IO_PENDING Then
  292.                         Throw New System.Exception("Write failed")
  293.                     End If
  294.                 End If
  295.                 ' set the wip flag
  296.                 write_in_progress = True
  297.             End If
  298.         End SyncLock
  299.  
  300.     End Sub
  301.  
  302.     Public Function Read() As String
  303.         Dim s As String
  304.         Dim c As Char()
  305.         Dim i As Integer
  306.  
  307.         SyncLock GetType(CommControl)
  308.             ReDim c(readBufferPosition)
  309.             For i = 0 To readBufferPosition - 1
  310.                 c(i) = ChrW(readBuffer(i))
  311.             Next
  312.             readBufferPosition = 0
  313.             s = New String(c)
  314.         End SyncLock
  315.         Return s
  316.  
  317.     End Function
  318.  
  319.     Private Sub eventThread()
  320.         Dim r As Integer
  321.  
  322.         Do
  323.             evtMask = 0 ' clear the event mask
  324.             r = WaitCommEvent(h, evtMask, o) ' start the wait operation
  325.             If r <> 1 Then
  326.                 r = GetLastError()
  327.                 If r <> ERROR_IO_PENDING Then
  328.                     Throw New System.Exception("WaitCommEvent failed")
  329.                 End If
  330.             End If
  331.             r = WaitForSingleObject(o.hEvent, INFINITE) ' do the waiting
  332.             If r <> 1 Then
  333.                 r = GetLastError()
  334.                 If r <> ERROR_IO_PENDING Then
  335.                     Throw New System.Exception("WaitForSingleObject failed")
  336.                 End If
  337.             End If
  338.             r = GetOverlappedResult(h, o, Nothing, 0) ' get the event mask
  339.             If r <> 1 Then
  340.                 r = GetLastError()
  341.                 ' just in case the wait hasn't really completed
  342.                 If r = ERROR_IO_INCOMPLETE Then
  343.                     evtMask = -1
  344.                 Else
  345.                     Throw New System.Exception("GetOverlappedResult failed")
  346.                 End If
  347.             End If
  348.             r = ResetEvent(o.hEvent)
  349.             If r <> 1 Then
  350.                 r = GetLastError()
  351.                 Throw New System.Exception("ResetEvent failed")
  352.             End If
  353.  
  354.             ' release the wip flag if the write completed
  355.             SyncLock GetType(CommControl)
  356.                 If evtMask And EV_TXEMPTY Then
  357.                     write_in_progress = False
  358.                 End If
  359.                 If evtMask And EV_RXCHAR Then
  360.                     Do
  361.                         r = ReadFile(h, readBuffer(readBufferPosition), 1, bytesRead, Nothing)
  362.                         If r <> 1 Then
  363.                             r = GetLastError()
  364.                             Throw New System.Exception("ResetEvent failed")
  365.                         End If
  366.                         If bytesRead <> 1 Then
  367.                             Exit Do
  368.                         Else
  369.                             readBufferPosition += 1
  370.                         End If
  371.                     Loop
  372.                 End If
  373.             End SyncLock
  374.             ' only raise an event if there is somthing to do
  375.             If evtMask > 0 Then
  376.                 RaiseEvent commEvent(evtMask)
  377.             End If
  378.         Loop
  379.  
  380.     End Sub
  381.  
  382. End Class
  383.