home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1997 October / PCO1097.ISO / FilesBBS / WIN3X / MSTARTER.ARJ / MSCOMM.ZIP / mscomm.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-11-07  |  19.2 KB  |  567 lines

  1. unit MSComm;
  2.  
  3. { TMSComm VCL component version history
  4.   -----------------------------------
  5.  
  6.   7/24/95 Version 1.00, FREEWARE by Jeff Atwood
  7.  
  8.   General information
  9.   -------------------
  10.  
  11.   This is a drop-in replacement for the MSCOMM control available in VB 3.0
  12.   professional! I modified it with the goal of making the control work like that
  13.   one, since I used it all the time.. but that was pre-Delphi. :)
  14.  
  15.   There are no known bugs. This control is freely distributable. Any comments,
  16.   rants, raves, or other horticultural delights can be E-Mailed to me at
  17.   JAtwood@a.crl.com. Especially let me know if you find a bug or add a new
  18.   nifty feature!
  19.  
  20.   How to Use
  21.   ----------
  22.  
  23.   See the demo code for a good example. Otherwise, check the code below for
  24.   comments. IMPORTANT: when opening the port, make sure that the TxBuf
  25.   is larger than the largest chunk of data you will send through the port.
  26.  
  27.   11/7/95 This component is partially based on the work of Mr. Fred Bulback! Thanks Fred!
  28.  
  29.  }
  30.  
  31. interface
  32.  
  33. uses Messages, WinTypes, WinProcs, Classes, Forms, SysUtils;
  34.  
  35. { These are the enumerated types supported by the TMSComm control }
  36.  
  37. type
  38.   TBaudRate = (br110, br300, br600, br1200, br2400, br4800, br9600, br14400,
  39.                br19200, br38400, br56000, br128000, br256000);
  40.   TParityBits = (pbNone, pbOdd, pbEven, pbMark, pbSpace);
  41.   TDataBits = (dbFour, dbFive, dbSix, dbSeven, dbEight);
  42.   TStopBits = (sbOne, sbOnePointFive, sbTwo);
  43.   TCommEvent = (ceBreak, ceCts, ceCtss, ceDsr, ceErr, cePErr, ceRing, ceRlsd,
  44.                 ceRlsds, ceRxChar, ceRxFlag, ceTxEmpty);
  45.   TFlowControl = (fcNone, fcRTSCTS, fcXONXOFF);
  46.   TCommEvents = set of TCommEvent;
  47.  
  48. type
  49.  
  50.   { These are the events for the TComm object }
  51.  
  52.   TNotifyCommEventEvent = procedure(Sender: TObject; CommEvent: TCommEvents) of object;
  53.   TNotifyReceiveEvent = procedure(Sender: TObject; Count: Word) of object;
  54.   TNotifyTransmitLowEvent = procedure(Sender: TObject; Count: Word) of object;
  55.  
  56.   { This is the TMSComm object }
  57.  
  58.   TMSComm = class(TComponent)
  59.   private
  60.     FVersion: Single;
  61.     FPort: Byte;
  62.     FBaudRate: TBaudRate;
  63.     FParityBits: TParityBits;
  64.     FDataBits: TDataBits;
  65.     FStopBits: TStopBits;
  66.     FFlowControl: TFlowControl;
  67.     FRxBufSize: Word;
  68.     FTxBufSize: Word;
  69.     FRxFull: Word;
  70.     FTxLow: Word;
  71.     FEvents: TCommEvents;
  72.     FOnCommEvent: TNotifyCommEventEvent;
  73.     FOnReceive: TNotifyReceiveEvent;
  74.     FOnTransmitLow: TNotifyTransmitLowEvent;
  75.     FhWnd: hWnd;
  76.     cId: Integer;                        { handle to comm port }
  77.     Error: String;
  78.     procedure SetPort(Value: Byte);
  79.     procedure SetBaudRate(Value: TBaudRate);
  80.     procedure SetParityBits(Value: TParityBits);
  81.     procedure SetDataBits(Value: TDataBits);
  82.     procedure SetStopBits(Value: TStopBits);
  83.     procedure SetFlowControl(Value: TFlowControl);
  84.     procedure SetRxBufSize(Value: Word);
  85.     procedure SetTxBufSize(Value: Word);
  86.     procedure SetRxFull(Value: Word);
  87.     procedure SetTxLow(Value: Word);
  88.     procedure SetEvents(Value: TCommEvents);
  89.     procedure WndProc(var Msg: TMessage);
  90.     procedure DoEvent;
  91.     procedure DoReceive;
  92.     procedure DoTransmit;
  93.     function parseOpenErr(Errcode: Integer): String;
  94.     function parseGenErr: String;
  95.   public
  96.     constructor Create(AOwner: TComponent); override;
  97.     destructor Destroy; override;
  98.     procedure Write(Data: PChar; Len: Word);
  99.     procedure Read(Data: PChar; Len: Word);
  100.     function Open: Boolean;
  101.     procedure Close;
  102.     function GetError: String;
  103.   published
  104.     property Version: Single read FVersion;
  105.     property Port: Byte read FPort write SetPort;
  106.     property BaudRate: TBaudRate read FBaudRate write SetBaudRate;
  107.     property ParityBits: TParityBits read FParityBits write SetParityBits;
  108.     property DataBits: TDataBits read FDataBits write SetDataBits;
  109.     property StopBits: TStopBits read FStopBits write SetStopBits;
  110.     property FlowControl: TFlowControl read FFlowControl write SetFlowControl;
  111.     property TxBufSize: Word read FTxBufSize write SetTxBufSize;
  112.     property RxBufSize: Word read FRxBufSize write SetRxBufSize;
  113.     property RxFullCount: Word read FRxFull write SetRxFull;
  114.     property TxLowCount: Word read FTxLow write SetTxLow;
  115.     property Events: TCommEvents read FEvents write SetEvents;
  116.     property OnCommEvent: TNotifyCommEventEvent read FOnCommEvent write FOnCommEvent;
  117.     property OnReceive: TNotifyReceiveEvent read FOnReceive write FOnReceive;
  118.     property OnTransmitLow: TNotifyTransmitLowEvent read FOnTransmitLow write FOnTransmitLow;
  119.   end;
  120.  
  121. procedure Register;
  122.  
  123. implementation
  124.  
  125. { Set com port value. Used when you open the port. NOTE: This only takes effect when
  126.  opening the port-- obviously! Only works for ports 1 thru 9 currently, though I
  127.  think newer versions of Windows support up to 254 comm ports. Set this to port
  128.  zero (0) if you want to disable the comm control.}
  129. procedure TMSComm.SetPort(Value: Byte);
  130. begin
  131.   FPort := Value;
  132. end;
  133.  
  134. { Set baud rate: 110-256,000. Notice that this will change the baud rate of the port
  135.  immediately-- if it is currently open! This goes for most of the other com port
  136.  settings below as well.}
  137. procedure TMSComm.SetBaudRate(Value: TBaudRate);
  138. var
  139.   DCB: TDCB;
  140. begin
  141.   FBaudRate := Value;
  142.   if cId >= 0 then begin
  143.     GetCommState(cId, DCB);
  144.     case Value of
  145.       br110: DCB.BaudRate := CBR_110;
  146.       br300: DCB.BaudRate := CBR_300;
  147.       br600: DCB.BaudRate := CBR_600;
  148.       br1200: DCB.BaudRate := CBR_1200;
  149.       br2400: DCB.BaudRate := CBR_2400;
  150.       br4800: DCB.BaudRate := CBR_4800;
  151.       br9600: DCB.BaudRate := CBR_9600;
  152.       br14400: DCB.BaudRate := CBR_14400;
  153.       br19200: DCB.BaudRate := CBR_19200;
  154.       br38400: DCB.BaudRate := CBR_38400;
  155.       br56000: DCB.BaudRate := CBR_56000;
  156.       br128000: DCB.BaudRate := CBR_128000;
  157.       br256000: DCB.BaudRate := CBR_256000;
  158.     end;
  159.     SetCommState(DCB);
  160.   end;
  161. end;
  162.  
  163. { set parity: none, odd, even, mark, space }
  164. procedure TMSComm.SetParityBits(Value: TParityBits);
  165. var
  166.   DCB: TDCB;
  167. begin
  168.   FParityBits := Value;
  169.   if cId < 0 then
  170.     exit;
  171.   GetCommState(cId, DCB);
  172.   case Value of
  173.     pbNone: DCB.Parity := 0;
  174.     pbOdd: DCB.Parity := 1;
  175.     pbEven: DCB.Parity := 2;
  176.     pbMark: DCB.Parity := 3;
  177.     pbSpace: DCB.Parity := 4;
  178.   end;
  179.   SetCommState(DCB);
  180. end;
  181.  
  182. { set # of data bits 4-8 }
  183. procedure TMSComm.SetDataBits(Value: TDataBits);
  184. var
  185.   DCB: TDCB;
  186. begin
  187.   FDataBits := Value;
  188.   if cId < 0 then
  189.     exit;
  190.   GetCommState(cId, DCB);
  191.   case Value of
  192.     dbFour: DCB.ByteSize := 4;
  193.     dbFive: DCB.ByteSize := 5;
  194.     dbSix: DCB.ByteSize := 6;
  195.     dbSeven: DCB.ByteSize := 7;
  196.     dbEight: DCB.ByteSize := 8;
  197.   end;
  198.   SetCommState(DCB);
  199. end;
  200.  
  201. { set number of stop bits 1, 1.5 or 2 }
  202. procedure TMSComm.SetStopBits(Value: TStopBits);
  203. var
  204.   DCB: TDCB;
  205. begin
  206.   FStopBits := Value;
  207.   if cId < 0 then
  208.     exit;
  209.   GetCommState(cId, DCB);
  210.   case Value of
  211.     sbOne: DCB.StopBits := 0;
  212.     sbOnePointFive: DCB.StopBits := 1;
  213.     sbTwo: DCB.StopBits := 2;
  214.   end;
  215.   SetCommState(DCB);
  216. end;
  217.  
  218. { Set flow control: None, RTS/CTS, or Xon/Xoff. Flow control works in conjunction
  219. with the read and write buffers to ensure that the flow of data *will* stop if
  220. the buffers get critically full. If there is no flow control, it's possible
  221. to lose data.. with flow control on, technically, it's impossible since if the
  222. buffers get full, flow control will kick in and stop the data flow until the
  223. buffers have time to get clear. }
  224. procedure TMSComm.SetFlowControl(Value: TFlowControl);
  225. var
  226.   DCB: TDCB;
  227. begin
  228.   FFlowControl := Value;
  229.   if cId < 0 then
  230.     exit;
  231.   GetCommState(cId, DCB);
  232.   DCB.Flags := DCB.Flags xor (dcb_OutxCtsFlow or dcb_Rtsflow or dcb_OutX or dcb_InX);
  233.   case Value of
  234.     fcNone: ;
  235.     fcRTSCTS: DCB.Flags := DCB.Flags or dcb_OutxCtsFlow or dcb_Rtsflow;
  236.     fcXONXOFF: DCB.Flags := DCB.Flags or dcb_OutX or dcb_InX;
  237.   end;
  238.   SetCommState(DCB);
  239. end;
  240.  
  241. { RxBuf is the amount of memory set aside to buffer reads (incoming data)
  242. to the serial port. It is possible to overflow the read buffer depending on how
  243. frequently you are servicing (reading) the incoming data and how fast data is
  244. coming in the serial port. NOTE: This setting takes effect only when opening
  245. the port. }
  246. procedure TMSComm.SetRxBufSize(Value: Word);
  247. begin
  248.   FRxBufSize := Value;
  249. end;
  250.  
  251. { TxBuf is the amount of memory set aside to buffer writes (outgoing data)
  252. to the serial port. Must be larger than any chunk of data you plan to write at
  253. once. It is possible to overflow the tx buffer depending on how fast data
  254. is going out of the modem, and how fast you're writing to the serial port. NOTE: this
  255. setting takes effect only when opening the port. }
  256. procedure TMSComm.SetTxBufSize(Value: Word);
  257. begin
  258.   FTxBufSize := Value;
  259. end;
  260.  
  261. { RxFull indicates the number of bytes the COM driver must write to the
  262. application's input queue before sending a notification message. The message
  263. signals the application to read information from the input queue. This "forces"
  264. the driver to send notification during periods of data "streaming." It will
  265. stop what it's doing and notify you when it gets at least this many chars.
  266. This will only affect data streaming; normally data is sent during lulls in
  267. the "stream." If there are no lulls, this setting comes into effect. The
  268. event OnReceive fires when ANY amount of data is received. The maximum
  269. chunk of data you will receive is set by the RxFull amount. }
  270. procedure TMSComm.SetRxFull(Value: Word);
  271. begin
  272.   FRxFull := Value;
  273.   if cId < 0 then
  274.     exit;
  275.   EnableCommNotification(cId, FhWnd, FRxFull, FTxLow);
  276. end;
  277.  
  278. { TxLow Indicates the minimum number of bytes in the output queue. When the
  279. number of bytes in the output queue falls below this number, the COM driver
  280. sends the application a notification message, signaling it to write information
  281. to the output queue. This can be handy to avoid overflowing the (outgoing)
  282. read buffer. The event OnTransmitLow fires when this happens.}
  283. procedure TMSComm.SetTxLow(Value: Word);
  284. begin
  285.   FTxLow := Value;
  286.   if cId < 0 then
  287.     exit;
  288.   EnableCommNotification(cId, FhWnd, FRxFull, FTxLow);
  289. end;
  290.  
  291. { Build the event mask. Indicates which misc events we want the comm control to
  292. tell us about. }
  293. procedure TMSComm.SetEvents(Value: TCommEvents);
  294. var
  295.   Events: Word;
  296. begin
  297.   FEvents := Value;
  298.   if cId < 0 then
  299.     exit;
  300.   Events := 0;
  301.   if ceBreak in FEvents then Events := Events or EV_BREAK;
  302.   if ceCts in FEvents then Events := Events or EV_CTS;
  303.   if ceCtss in FEvents then Events := Events or EV_CTSS;
  304.   if ceDsr in FEvents then Events := Events or EV_DSR;
  305.   if ceErr in FEvents then Events := Events or EV_ERR;
  306.   if cePErr in FEvents then Events := Events or EV_PERR;
  307.   if ceRing in FEvents then Events := Events or EV_RING;
  308.   if ceRlsd in FEvents then Events := Events or EV_RLSD;
  309.   if ceRlsds in FEvents then Events := Events or EV_RLSDS;
  310.   if ceRxChar in FEvents then Events := Events or EV_RXCHAR;
  311.   if ceRxFlag in FEvents then Events := Events or EV_RXFLAG;
  312.   if ceTxEmpty in FEvents then Events := Events or EV_TXEMPTY;
  313.   SetCommEventMask(cId, Events);
  314. end;
  315.  
  316. { This is the message handler for the invisible window; it handles comm msgs
  317. that are handed to the invisible window. We hook into these messages using
  318. EnableCommNotification and our invisible window handle. This routine hands
  319. off to the "do(x)" routines below. }
  320. procedure TMSComm.WndProc(var Msg: TMessage);
  321. begin
  322.   with Msg do begin
  323.     if Msg = WM_COMMNOTIFY then begin
  324.       case lParamLo of
  325.         CN_EVENT: DoEvent;
  326.         CN_RECEIVE: DoReceive;
  327.         CN_TRANSMIT: DoTransmit;
  328.       end;
  329.       end
  330.     else
  331.       Result := DefWindowProc(FhWnd, Msg, wParam, lParam);
  332.   end;
  333. end;
  334.  
  335. { some comm event occured. see if we need to report it as an event based
  336.  on the FOnEvent flags set in the control. }
  337. procedure TMSComm.DoEvent;
  338. var
  339.   CommEvent: TCommEvents;
  340.   Events: Word;
  341. begin
  342.   if (cId < 0) or not Assigned(FOnCommEvent) then
  343.     exit;
  344.   Events := GetCommEventMask(cId, Integer($FFFF));
  345.   CommEvent := [];
  346.   if (ceBreak in FEvents) and (events and EV_BREAK <> 0) then
  347.     CommEvent := CommEvent + [ceBreak];
  348.   if (ceCts in FEvents) and (events and EV_CTS <> 0) then
  349.     CommEvent := CommEvent + [ceCts];
  350.   if (ceCtss in FEvents) and (events and EV_CTSS <> 0) then
  351.     CommEvent := CommEvent + [ceCtss];
  352.   if (ceDsr in FEvents) and (events and EV_DSR <> 0) then
  353.     CommEvent := CommEvent + [ceDsr];
  354.   if (ceErr in FEvents) and (events and EV_ERR <> 0) then
  355.     CommEvent := CommEvent + [ceErr];
  356.   if (cePErr in FEvents) and (events and EV_PERR <> 0) then
  357.     CommEvent := CommEvent + [cePErr];
  358.   if (ceRing in FEvents) and (events and EV_RING <> 0) then
  359.     CommEvent := CommEvent + [ceRing];
  360.   if (ceRlsd in FEvents) and (events and EV_RLSD <> 0) then
  361.     CommEvent := CommEvent + [ceRlsd];
  362.   if (ceRlsds in FEvents) and (events and EV_RLSDS <> 0) then
  363.     CommEvent := CommEvent + [ceRlsds];
  364.   if (ceRxChar in FEvents) and (events and EV_RXCHAR <> 0) then
  365.     CommEvent := CommEvent + [ceRxChar];
  366.   if (ceRxFlag in FEvents) and (events and EV_RXFLAG <> 0) then
  367.     CommEvent := CommEvent + [ceRxFlag];
  368.   if (ceTxEmpty in FEvents) and (events and EV_TXEMPTY <> 0) then
  369.     CommEvent := CommEvent + [ceTxEmpty];
  370.   FOnCommEvent(Self, CommEvent);
  371. end;
  372.  
  373. { we rec'd some data, see if receive event is on and fire }
  374. procedure TMSComm.DoReceive;
  375. var
  376.   Stat: TComStat;
  377. begin
  378.   if (cId < 0) or not Assigned(FOnReceive) then
  379.     exit;
  380.   GetCommError(cId, Stat);
  381.   FOnReceive(Self, Stat.cbInQue);
  382.   GetCommError(cId, Stat);
  383. end;
  384.  
  385. { This event will fire when the transmit buffer goes BELOW the point set
  386.  in txLowCount. It will NOT fire when a transmission takes place. }
  387. procedure TMSComm.DoTransmit;
  388. var
  389.   Stat: TComStat;
  390. begin
  391.   if (cId < 0) or not Assigned(FOnTransmitLow) then
  392.     exit;
  393.   GetCommError(cId, Stat);
  394.   FOnTransmitLow(Self, Stat.cbOutQue);
  395. end;
  396.  
  397. { construct: create invisible message window, set default values }
  398. constructor TMSComm.Create(AOwner: TComponent);
  399. begin
  400.   inherited Create(AOwner);
  401.   FhWnd := AllocateHWnd(WndProc);
  402.   Error := '';
  403.   FVersion := 1.00;
  404.   FPort := 2;
  405.   FBaudRate := br9600;
  406.   FParityBits := pbNone;
  407.   FDataBits := dbEight;
  408.   FStopBits := sbOne;
  409.   FTxBufSize := 2048;
  410.   FRxBufSize := 2048;
  411.   FRxFull := 512;
  412.   FTxLow := 512;
  413.   FEvents := [];
  414.   cId := -1;
  415. end;
  416.  
  417. { destructor: close invisible message window, close comm port }
  418. destructor TMSComm.Destroy;
  419. begin
  420.   DeallocatehWnd(FhWnd);
  421.   if cId >= 0 then
  422.     CloseComm(cId);
  423.   inherited Destroy;
  424. end;
  425.  
  426. { Write data to comm port. This routine will reject an attempt
  427.  to write a chunk of data larger than the write buffer size. WARNING: This
  428.  routine could *potentially* wait forever for the buffer to clear. But at least
  429.  your machine won't lock up since we're processing messages in the wait loop.
  430.  NOTE: theoretically, you should check the Error property for errors
  431.  after every write. Any error during read or write can stop flow of data. }
  432. procedure TMSComm.Write(Data: PChar; Len: Word);
  433. var
  434.   Stat: TComStat;
  435.   bufroom: Integer;
  436. begin
  437.   if cId < 0 then
  438.     exit;
  439.   if Len > FTxBufSize then begin
  440.     Error := 'write larger than transmit buffer size';
  441.     exit;
  442.   end;
  443.  
  444.   repeat
  445.     GetCommError(cId, Stat);
  446.     bufroom := FTxBufSize - stat.cbOutQue;
  447.     Application.ProcessMessages;
  448.   until bufroom >= len;
  449.  
  450.   if WriteComm(cId, Data, Len) < 0 then
  451.     Error := ParseGenErr;
  452.   GetCommEventMask(cId, Integer($FFFF));
  453. end;
  454.  
  455. { Read data from comm port. Should only do read when you've been notified you
  456.  have data. Attempting to read when nothing is in read buffer results
  457.  in spurious error. You can never read a larger chunk than the read buffer
  458.  size. NOTE: theoretically, you should check the Error property for errors
  459.  after every read. Any error during read or write can stop flow of data. }
  460. procedure TMSComm.Read(Data: PChar; Len: Word);
  461. begin
  462.   if cId < 0 then
  463.     exit;
  464.   if ReadComm(cId, Data, Len) < 0 then
  465.     Error := ParseGenErr;
  466.   GetCommEventMask(cId, Integer($FFFF));
  467. end;
  468.  
  469. { failure to open results in a negative cId, this will translate the
  470.   negative cId value into an explanation. }
  471. function TMSComm.parseOpenErr(Errcode: Integer): String;
  472. begin
  473.   case errcode of
  474.     IE_BADID: result := 'Device identifier is invalid or unsupported';
  475.     IE_OPEN: result := 'Device is already open.';
  476.     IE_NOPEN: result := 'Device is not open.';
  477.     IE_MEMORY: result := 'Cannot allocate queues.';
  478.     IE_DEFAULT: result := 'Default parameters are in error.';
  479.     IE_HARDWARE: result := 'Hardware not available (locked by another device).';
  480.     IE_BYTESIZE: result := 'Specified byte size is invalid.';
  481.     IE_BAUDRATE: result := 'Device baud rate is unsupported.';
  482.  else
  483.    result := 'Open error ' + IntToStr(Errcode);
  484.  end;
  485. end;
  486.  
  487. { failure to read or write to comm port results in a negative returned
  488. value. This will translate the value into an explanation. }
  489. function TMSComm.ParseGenErr: String;
  490. var
  491.   stat: TComStat;
  492.   errCode: Word;
  493. begin
  494.   errCode := GetCommError(cId, stat);
  495.   case errcode of
  496.     CE_BREAK: result := 'Hardware detected a break condition.';
  497.     CE_CTSTO: result := 'CTS (clear-to-send) timeout.';
  498.     CE_DNS: result := 'Parallel device was not selected.';
  499.     CE_DSRTO: result := 'DSR (data-set-ready) timeout.';
  500.     CE_FRAME: result := 'Hardware detected a framing error.';
  501.     CE_IOE: result := 'I/O error during communication with parallel device.';
  502.     CE_MODE: result := 'Requested mode is not supported';
  503.     CE_OOP: result := 'Parallel device is out of paper.';
  504.     CE_OVERRUN: result := 'Character was overwritten before it could be retrieved.';
  505.     CE_PTO: result := 'Timeout during communication with parallel device.';
  506.     CE_RLSDTO: result := 'RLSD (receive-line-signal-detect) timeout.';
  507.     CE_RXOVER: result := 'Receive buffer overflow.';
  508.     CE_RXPARITY: result := 'Hardware detected a parity error.';
  509.     CE_TXFULL: result := 'Transmit buffer overflow.';
  510.   else
  511.     result := 'General error ' + IntToStr(errcode);
  512.   end;
  513. end;
  514.  
  515. { returns error text (if any) and clears it }
  516. function TMSComm.GetError: String;
  517. begin
  518.   Result := Error;
  519.   Error := '';
  520. end;
  521.  
  522. { Explicitly open port. Returns success/failure, check error property for details.
  523.  This routine also begins hooking the comm messages to our invisible window we
  524.  created upon instantiation. Will close port (if open) before re-opening. }
  525. function TMSComm.Open: Boolean;
  526. var
  527.   commName: PChar;
  528.   tempStr: String;
  529. begin
  530.   if Fport = 0 then
  531.     exit;
  532.   close;
  533.   tempStr := 'COM' + IntToStr(Fport) + ':';
  534.   commName := StrAlloc(10);
  535.   StrPCopy(commName, tempStr);
  536.   cId := OpenComm(commName, RxBufSize, TxBufSize);
  537.   StrDispose(commName);
  538.   if cId < 0 then begin
  539.     Error := parseOpenErr(cId);
  540.     result := False;
  541.     exit;
  542.   end;
  543.   SetBaudRate(FBaudRate);
  544.   SetParityBits(FParityBits);
  545.   SetDataBits(FDataBits);
  546.   SetStopBits(FStopBits);
  547.   SetFlowControl(FFlowControl);
  548.   SetEvents(FEvents);
  549.   EnableCommNotification(cId, FhWnd, FRxFull, FTxLow);
  550.   result := True;
  551. end;
  552.  
  553. { closes the comm port, if it is open. }
  554. procedure TMSComm.Close;
  555. begin
  556.   if cId >= 0 then
  557.     CloseComm(cId);
  558. end;
  559.  
  560. { registers this VCL component and adds the icon to the palette }
  561. procedure Register;
  562. begin
  563.   RegisterComponents('System', [TMSComm]);
  564. end;
  565.  
  566. end.
  567.