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