*!* Q291535: HOWTO: Find installed modems using Microsoft Visual FoxPro *!* This article use Mscom32.ocx to detect if any modems are installed *!* and reports the COM port it is using. *!* PUBLIC oform1 oform1=CREATEOBJECT([MODEMFORM]) oform1.Show RETURN ************************************************** * DEFINE CLASS MODEMFORM AS form Height = 128 Width = 160 DoCreate = .T. AutoCenter = .T. BorderStyle = 2 Caption = [Com Port Test] MaxButton = .F. MinButton = .F. Visible = .F. AlwaysOnTop = .T. BackColor = RGB(0,0,255) Name = [Form1] *-- Form array that stores information about available machine com ports. DIMENSION acommports[1,2] ADD OBJECT ocxCOMM AS MSCOMM_OCX WITH ; Top = 101, ; Left = 72, ; Height = 21, ; Width = 38, ; Name = [ocxCOMM] ADD OBJECT lblava_ports AS label WITH ; AutoSize = .T., ; FontName = [Verdana], ; Caption = [Available COM Ports:], ; Height = 16, ; Left = 14, ; Top = 15, ; Width = 133, ; ForeColor = RGB(255,255,255), ; BackColor = RGB(0,0,255), ; Name = [lblAVA_PORTS] ADD OBJECT command1 AS commandbutton WITH ; Top = 78, ; Left = 11, ; Height = 27, ; Width = 138, ; FontName = [Tahoma], ; Caption = [\<Test Ports for Modem], ; Name = [Command1] ADD OBJECT timer1 AS timer WITH ; Top = 105, ; Left = 12, ; Height = 23, ; Width = 23, ; Enabled = .F., ; Interval = 1500, ; Name = [Timer1] ADD OBJECT lblports AS label WITH ; FontName = [Verdana], ; Alignment = 2, ; Caption = [lblPORTS], ; Height = 17, ; Left = 42, ; Top = 46, ; Width = 77, ; ForeColor = RGB(255,255,255), ; BackColor = RGB(0,0,255), ; Name = [lblPORTS] PROCEDURE WaitForResponse *~ This method loops for the specified *~ amount of time calling DOEVENTS(). *~ This allows time for the modem to respond to the requests. LPARAMETERS lnDelayInSeconds LOCAL lnStartTime lnStartTime = SECO() DO WHILE SECO() <= (lnStartTime + lnDelayInSeconds) ; AND NOT SECO() < lnStartTime DOEVENTS() ENDDO ENDPROC PROCEDURE Error LPARAMETERS nError, cMethod, nLine *~ In THIS.INIT we loop through 10 COM ports, *~ attempting to open each with the MSCOMM32.OCX control. *~ We trap the errors here and if it's an OLE error, *~ nError will be 1429 (this came from the control). IF INLIST(nError, 1429, 1426) *~ Populate an error array and check the OLE message. LOCAL aErrArray(1) AERROR(aErrArray) *~ If the error msg was "Invalid Port Number" *~ the control tried to open a port that either *~ doesn't exist or has nothing on it. *~ Set a global var (glBadPort) to .T. *~ this var is used in THIS.INIT loop. IF [INVALID PORT NUMBER] $ UPPER(aErrArray(3)) or ; [UNKNOWN OLE STATUS CODE] $ UPPER(aErrArray(3)) glBadPort = .T. ENDIF ELSE *~ We experienced a non - OLE error. Report it. MESSAGEBOX([Error #: ] + ALLT(STR(nError)) + CHR(13) + ; [Message: ] + MESSAGE() + CHR(13) + ; [Line with error: ] + ALLT(STR(nLine)) + CHR(13) + ; [Method: ] + cMethod) ENDIF ENDPROC PROCEDURE Init *~ Var that indicates a non-existent or inactive COM port. *~ This var is flipped by THISFORM.ERROR() _VFP.AutoYield=.F. PUBLIC glBadPort glBadPort = .F. LOCAL i, lcGoodPorts *~ lcGoodPorts used to build string displayed *~ in THISFORM.lblPORTS.CAPTION lcGoodPorts = [] *~ Set initial properties of MSCOMM .OCX WITH THIS.ocxCOMM .RThreshold = 1 .SThreshold = 1 .Settings = [9600,n,8,1] .RTSEnable = .F. .InputLen = 0 ENDWITH *~ Loop through 10 ports, trying to open each. FOR i = 1 TO 10 WITH THIS.ocxCOMM .CommPort = i .PortOpen = .T. *~ glBadPort set to .T. by THIS.ERROR if the # was bad. IF !glBadPort *~ Expand the array if i>1. The array is initally 1 row. IF i > 1 DIMENSION THIS.aCommPorts[ALEN(THIS.aCommPorts,1)+1,2] ENDIF *~ Valid port, so store the port # to the first column *~ and a blank to the second column of the current row *~ in THISFORM.aCommPorts. We will use this space later *~ in THISFORM.COMMAND1.CLICK() to store return value *~ communication with the port. *~ Also store the port # to the lcGoodPorts variable. THIS.aCommPorts(i,1) = i THIS.aCommPorts(i,2) = [] lcGoodPorts = lcGoodPorts + ALLT(STR(i)) + [ ] ENDIF *~ Reset glBadPort for next loop. glBadPort = .F. *~ Close the port if it was opened to avoid error on next try. IF .PortOpen .PortOpen = .F. ENDIF ENDWITH ENDFOR *~ List the valid ports in THISFORM.lblPORTS.CAPTION THIS.lblPORTS.CAPTION = lcGoodPorts RELEASE glBadPort ENDPROC PROCEDURE ocxCOMM.OnComm *** ActiveX Control Event *** *~ CommEvent = 2 means the control received data. *~ Store the data the control received to *~ the appropriate array row/column. *~ The row/column to store to is determined by *~ global variable "gnPortNum" which is set in the *~ thisform.command1.click() loop. WAIT WINDOW "TRACY IS HERE" IF THIS.commevent = 2 THISFORM.aCommPorts(gnPortNum,2) = ; THISFORM.aCommPorts(gnPortNum,2) + THIS.INPUT ENDIF ENDPROC PROCEDURE command1.Error LPARAMETERS nError, cMethod, nLine *~ Trap OLE error from the COMM .OCX *~ nError = 1429: we experienced an OLE error. This may *~ be because we tried to open or communicate via *~ the port and there is a non-standard object attached to *~ it (such as a printer). Do nothing here; it's not a modem *~ since we cannot open AND communicate with it. *~ You may want to enhance this error trap. IF INLIST(nError, 1429, 1426) ELSE *~ We experienced a non - OLE error. Report it. MESSAGEBOX([Error #: ] + ALLT(STR(nError)) + CHR(13) + ; [MESSAGE: ] + MESSAGE() + CHR(13) + ; [LINE WITH ERROR: ] + ALLT(STR(nLine)) + CHR(13) + ; [Method: ] + cMethod) ENDIF ENDPROC PROCEDURE command1.Click *~ gnPortNum is used in the ONCOMM event of the .OCX PUBLIC gnPortNum LOCAL i, lnModemPort lnModemPort = 0 WITH THISFORM *~ Loop through the form array... FOR i = 1 TO ALEN(.aCommPorts,1) gnPortNum = i WAIT WINDOW [Testing COM ] + ; ALLT(STR(.aCommPorts(i,1))) + [...] NOWAIT NOCLEAR IF .ocxCOMM.PortOpen .ocxCOMM.PortOpen = .F. ENDIF *~ Open the port and send standard Hayes-compatible *~ commands to it. These commands first reset ([ATZ]) *~ the modem if it's there, then tell it to return *~ an ID string ([ATI0]). The return string from a modem *~ will contain an [OK], which is how we can tell it's a modem. .ocxCOMM.CommPort = .aCommPorts(i,1) .ocxCOMM.PortOpen = .T. .ocxCOMM.OUTPUT = [ATZ] + CHR(13) .WaitForResponse(2) .ocxCOMM.OUTPUT = [ATI0] + CHR(13) .WaitForResponse(2) WAIT CLEAR ENDFOR WAIT WINDOW [Compiling Results...] NOWAIT NOCLEAR .timer1.ENABLED = .T. ENDWITH ENDPROC PROCEDURE timer1.Timer *~ Clear the variable used in the ONCOMM event *~ of the .OCX. RELE gnPortNum LOCAL i, lnModemPort lnModemPort = 0 *~ Disable this timer so the code only runs once. THIS.ENABLED = .F. WITH THISFORM *~ Close the port if it is open. .ocxCOMM.PortOpen = .F. *~ Loop through the completed array. *~ If the first element is <> 0, *~ check the second in the row for an "OK". *~ If present, that means the port has a modem. FOR i = 1 TO ALEN(.aCommPorts,1) IF .aCommPorts(i,1) <> 0 IF [OK] $ UPPER(.aCommPorts(i,2)) *~ Modem found, exit the loop. lnModemPort = .aCommPorts(i,1) EXIT ENDIF ENDIF NEXT i ENDWITH *~ Report to user. WAIT CLEAR IF lnModemPort <> 0 MESSAGEBOX([Modem Found On COM ] + ALLT(STR(lnModemPort)),0,[]) ELSE MESSAGEBOX([No Modem Found.] ,0,[]) ENDIF ENDPROC ENDDEFINE * *-- EndDefine: form1 ************************************************** DEFINE CLASS MSCOMM_OCX AS OLECONTROL OLECLASS = [MSCOMMLib.MSComm.1] ENDDEFINE>How can I find out what comm ports are on a PC? I have a PC that doesn't have comm port 2 defined even though there is one on the PC. Any ideas?