Está en la página 1de 8

Cmo usar el MSCOMM32.

OCX
Por Pedro Pascua Copyrights 1998 by FoxPress, All rights reserved FoxPress, Marzo 1998 En este artculo vamos a ver un ejemplo de formulario de comunicaciones va puerto serie utilizando el control de comunicaciones de Microsoft que viene en la edicin profesional del VFP. Dicho control se incluye como una OCX (MSCOMM32.OCX) y slo funciona en Windows 95 y NT. El control MSComm, nos permite acceder a cualquier puerto COMn: para transmitir o recibir datos, a travs de unas pocas propiedades y mtodos con un requerimiento mnimo de cdigo. Cada control gestiona un puerto serie por lo que si necesitamos controlar ms de un puerto a la vez deberemos usar tantos controles MSComm como puertos queramos acceder simultneamente. Una advertencia importante: el ejemplo est realizado utilizando la versin 5.0 del control, correspondiente al Service Pack2. Si se utiliza otra versin del control, al intentar modificar o ejecutar el formulario se puede producir un error de control OLE. Este problema que se produce si pegamos el control en el formulario, se puede solventar instanciando directamente el control mediante la sentencia: oComm =CreateObject("MsCommLib.MsComm") pero entonces no podemos codificar directamente el evento OnComm del control que es desde donde se gestionan el flujo de datos de la transmisin y la programacin resulta algo ms compleja. En nuestro caso, para no complicar el ejemplo, vamos a utilizar el control pegndolo en el formulario y codificando el evento OnComm. Antes de entrar de lleno en el ejemplo, podemos hacer alguna prueba para comprobar la funcionalidad del control. Vamos a crear un programa my sencillo con las siguientes lneas: oCom=CreateObject("MSCOMMLIB.MSCOMM") oCom.CommPort = 2 oCom.Settings = "14400,N,8,1" oCom.PortOpen = .T. oCom.Output = "ATDT123456789"+CHR(13) Con estas cinco lneas deberamos conseguir que el mdem que tenemos en el puerto COM2, llamara al nmero 123456789 y conectara a 14400 baudios, sin paridad, con 8 bits de datos y uno de parada. La conexin se cortara sin ms que aadir oCom.PortOpen = .T. Sencillo, no?... Las propiedades ms usadas de este control son: - CommPort: especifica el nmero de puerto COM asignado al control. Puede ser 1,2,3 4 segn los puertos que tengamos instalados.

- Settings: como hemos visto en el ejemplo anterior, especifica la configuracin de velocidad, paridad bits de datos y bit de parada para el puerto serie. Es una cadena con los correspondientes valores separados por comas. Por defecto su valor es "9600,N,8,1" - PortOpen: valor lgico que indica si el puerto est abierto y activo. Para abrir el puerto basta poner este valor a True. - Output: a esta propiedad se le asigna la cadena de caracteres que queremos enviar a travs del puerto y automticamente, enva dicha cadena al bufer de salida. - CommEvent: contiene el valor correspondiente al ltimo evento o error de comunicacin que se haya producido. - Sthreshold: especifica el nmero mnimo de caracteres en el bufer de salida que son enviados. - OutBufferCount: guarda el nmero de caracteres que estn esperando en el bufer de transmisin. Este ser cero si hemos puesto a cero la propiedad Sthreshold. Dndole a esta propiedad el valor 0 limpiaremos el bufer de salida. - OutBufferSize: especifica el tamao del bufer de transmisin. Por defecto es de 512 bytes. Todas estas propiedades se pueden encontrar en la ayuda que acompaa al control, accesible desde el men que aparece al pulsar el botn derecho sobre el icono del control, una vez pegado en el formulario. Aparte de estas propiedades, el otro punto clave para utilizar este control es el evento OnComm. El es el encargado de notificarnos todos los sucesos que ocurren durante la conexin, desde la llegada de un carcter, cambios en las lneas Carrier Detect (CD) y Request To Send (RTS) o errores producidos en la comunicacin. Es aqu pues, donde deberemos programar la gestin de estos sucesos. Todas las constantes correspondientes a los valores de los eventos de error y de comunicacin estn especificadas en la ayuda. El ejemplo que hemos creado para ilustrar la utilidad del control est realizado con el VFP5.0 . Consiste en un formulario desde el que podemos llamar o recibir una llamada a travs de un mdem estndar, mantener una sesin de Chat entre las dos mquinas y transferir ficheros en ambas direcciones. El formulario es el mismo para el que llama que para el que recibe la llamada ya que funciona en ambos sentidos. Por si alguien no tiene posibilidad de probarlo a travs de mdem, comentar que tambin funciona conectando directamente los puertos series de dos ordenadores a travs de un cable tipo "Modem Null". Con la nica diferencia de que no hay que marcar nmero, sino que basta con abrir el puerto. Adems, resulta ms econmico. Utilizamos los Combobox de la parte superior para seleccionar el Puerto de conexin y la velocidad. Obviamente, la velocidad est supeditada a la capacidad del mdem que utilicemos. Adems, el que seleccionemos 14400 y el mdem lo soporte, no asegura que la conexin se realice a esa velocidad, ya que a veces, el

ruido de fondo de la lnea telefnica puede hacer que la velocidad de conexin sea inferior a la terica. Una vez establecidos los parmetros del puerto, lo activamos al pulsar el botn Abrir puerto con el siguiente cdigo: If Thisform.CommControl.PortOpen = .F. Thisform.CommControl.PortOpen = .T. Thisform.CommControl.Output="ATZ"+Chr(13) Thisform.CommControl.Output="ATE1"+Chr(13) Thisform.LuzDTR.DisabledBackColor =RGB(0,255,0) Thisform.Start.Value = 1 This.Caption = "Cerrar Puerto" else Thisform.CommControl.PortOpen = .F. Thisform.LuzDTR.DisabledBackColor = RGB(192,192,192) Thisform.Start.Value = 0 This.Caption = "Abrir Puerto" Endif Hemos puesto unos textbox que cambiamos de color para simular las luces que nos indican el estado del mdem. Dicho estado se chequea peridicamente segn los intervalos que marca un control Timer que hay pegado en en el formulario. ** Evento Timer() ** ** Luz CTS (Clear To Send) if ThisForm.CommControl.CTSHolding = .T. Thisform.LuzCTS.DisabledBackColor=RGB(0,255,0) else Thisform.LuzCTS.DisabledBackColor=RGB(192,192,192) endif ** Luz CD (Carrier Detect) if ThisForm.CommControl.CDHolding = .T. Thisform.LuzCD.DisabledBackColor = RGB(0,255,0) else Thisform.LuzCD.DisabledBackColor=RGB(192,192,192) endif ** Luz DSR (Data Set Ready) if ThisForm.CommControl.DSRHolding = .T. Thisform.LuzDSR.DisabledBackColor=RGB(0,255,0) else Thisform.LuzDSR.DisabledBackColor=RGB(192,192,192) endif ** Luz DTR (Data Terminal Ready) if ThisForm.CommControl.DTREnable = .T. Thisform.LuzDSR.DisabledBackColor=RGB(0,255,0) else Thisform.LuzDSR.DisabledBackColor=RGB(192,192,192) Endif Estas "luces" nos avisan en el caso de que se corte alguna de estas lneas de conexin entre los puertos. Una vez abierto el puerto podemos mandar al mdem que marque el nmero indicado en el textbox situado a tal efecto sin ms que mandar al puerto la secuencia de control de marcado: If Thisform.CommControl.PortOpen = .T. Secuencia = "ATD"

Secuencia = Secuencia + ; AllTrim(Thisform.Telefono.Value)+Chr(13) Thisform.CommControl.Output = Secuencia Else Wait Window Nowait "Abra primero el puerto..." Endif

En el caso de que el formulario est funcionando como receptor de la llamada, detectaremos que alguien est llamando capturando el mensaje comEventRing (= 6) en el evento OnComm del control como veremos despus, mandando al mdem receptor que conteste a la llamada. Si todo ha ido bien hasta ahora, deberamos haber conseguido establecer la comunicacin entre los dos modems, hecho lo cual slo queda enviar los datos por la lnea que hemos abierto. Para distinguir si los datos que vamos a mandar son mensajes de Chat o parte de un fichero que estamos transfiriendo, creamos una propiedad del form llamada lChat y que almacena un valor True cuando la cadena es de un mensaje para as poder interpretar los datos recibidos consecuentemente. As pues, cuando mandamos una lnea de chat, (lo que se produce en el valid del texbox OutData), el receptor va almacenando los caracteres en otra propiedad custom llamada InBuffer hasta que nos llega un retorno de carro (ASCII 13) que interpretamos como fin de lnea. ** OutData.Valid() If Empty(This.Value) Return 1 EndIf If Thisform.CommControl.PortOpen = .T. * Generamos la secuencia de envo Secuencia = AllTrim(Thisform.OutData.Value); +CHR(13) * La enviamos al puerto

Thisform.CommControl.Output = Secuencia * guardamos la lnea en el cursor cLog Insert Into cLog (User_id,Mensaje,Hora); Values; ('Local:',ThisForm.OutData.Value,DATETIME()) ThisForm.Grid1.Refresh() Thisform.OutData.Value = "" Return 0 else Wait Window Nowait [Abra primero el puerto] endif Los mensajes los vamos guardando en un cursor que se crea en el Init() del formulario con un campo que identifica si el mensaje es del usuario local o remoto y otro campo en el guardamos la fecha-hora de envo. De este modo si nos interesara, podramos volcar toda la conversacin en un fichero tipo log. Este cursor lo vinculamos a un grid con el que conseguimos mediante la propiedad DynamicForeColor de las columnas, diferenciar con colores los mensajes de los dos comunicantes. ** Mtodo Init() del form Create cursor cLog (User_id C(8),; MensajeC(200),; Hora T) ThisForm.Grid1.RecordSource = 'cLog' ThisForm.Grid1.Column1.Dynamicforecolor=; "IIF(User_id='Local:',RGB(0,192,0),; RGB(0,0,192))" ThisForm.Grid1.Column2.Dynamicforecolor=; "IIF(User_id='Local:',; RGB(0,192,0),RGB(0,0,192))" Para mandar un fichero, lo primero que hacemos es enviar un cdigo que informe al receptor de que va a recibir un fichero. Adems le enviamos dentro de ese cdigo el nombre del fichero y su tamao. A partir de ah, abrimos el fichero y vamos leyendo bloques de 2 Kb y envindolos directamente al puerto. El tamao de los bloques de fichero que se van enviando depende de como hayamos configurado los bufers de transmisin y recepcin, ya que si stos no son pequeos con respecto al tamao de los bloques que enviamos, pueden llenarse saturando la comunicacin. Otra cosa importante a la hora de transmitir ficheros es asegurarse de que la propiedad NullDiscard est a false para que nos se descarte ningn carcter del fichero. ************************************ * Click() del botn enviar fichero * ************************************ If Not Thisform.CommControl.PortOpen MessageBox("Abra primero la conexin",0+64,"Aviso") Return EndIF * Seleccionamos el fichero lcFile = GetFile() lcName = lcFile * extraemos el nombre sin path Do While AT("\",lcName)>0 lcName = substr(lcName,at("\",lcName)+1) Enddo lnSize = FSIZE(lcFile) lnCanal = FOPEN(lcFile,0)

* abrimos el fichero a bajo nivel en modo * lectura If lnCanal = -1 MessageBox("Error al abrir el fichero "+ lcFile,0+16,"Aviso") Return EndIf * Mandamos aviso de Inicio transmisin Thisform.CommControl.Output = "**ITF/"+ALLT(lcName)+; "/"+ALLT(STR(lnSize))+"**"+CHR(13) Wait Wind "Iniciando transmisin ; " TimeOut 3 lnParcial = 0 Do While Not FEOF(lnCanal) lcBufferOut = FREAD(lnCanal,2048) Thisform.CommControl.Output = lcBufferOut lnParcial = lnParcial +LEN(lcBufferOut) ThisForm.Status.Value=100*lnParcial/ lnSize ThisForm.txtStatus.Value = "Enviando fichero: "+lcName+". Completados "+ALLT(STR(lnParcial))+" de "+ALLT(STR(lnSize))+" bytes." EndDo ?CHR(7) MessageBox("Fichero enviado",0+64,"Aviso") Thisform.Status.Value = 0 ThisForm.txtStatus.Value = "" ThisForm.Refresh() FCLOSE(lnCanal) ThisForm.lChat = .T. Veamos la codificacin del evento OnComm : * Capturamos el ltimo evento producido Evento = ThisForm.CommControl.CommEvent Do case Case Evento = 2 && Recibo datos ThisForm.ProcesaEntrada Case Evento = 7 Thisform.txtStatus.Value = "Se ha recibido un caracter EOF" Case Evento = 6 Thisform.txtStatus.Value = "Alguien est llamando ..." * descolgamos... Secuencia = "ATA" Secuencia = Secuencia + Chr(13) Thisform.CommControl.Output = Secuencia Case Evento = 1001 Thisform.txtStatus.Value = "Se ha recibido un BREAK " Case Evento = 1007 Thisform.txtStatus.Value = "Carrier Detect Timeout" Case Evento = 1002 Thisform.txtStatus.Value = "Clear To Send Timeout" Case Evento = 1003 Thisform.txtStatus.Value = "Data Set Ready Timeout" Case Evento = 1004 Thisform.txtStatus.Value = "Framing Error" Case Evento = 1006 Thisform.txtStatus.Value = "Port Overrun" Case Evento = 1008 Thisform.txtStatus.Value = "Receive Buffer Overflow" Case Evento = 1009 Thisform.txtStatus.Value = "Parity Error"

Case Evento = 1010 Thisform.txtStatus.Value = "Transmit Buffer Full" Endcase Faltara en este ejemplo implementar todas las actuaciones necesarias en funcin de los diversos tipos de error producido. Finalmente, veamos el mtodo que hemos creado para procesar los datos de entrada segn sean mensajes de chat o parte del fichero en transmisin: ******************************* * Mtodo ProcesaEntrada() * ******************************* lcEntrada = Thisform.CommConTrol.Input If ThisForm.lChat && modo chat lnLen = LEN(lcEntrada) lnCRpos = AT(CHR(13),lcEntrada) ThisForm.InBuffer = ThisForm.InBuffer + SUBSTR(lcEntrada,1,lnLen-IIF(lnCRpos>0,1,0)) If lnCRpos > 0 IF LEFT(ThisForm.InBuffer,5) = "**ITF" ThisForm.lChat = .F. * Leemos el nombre y tamao del fichero que * nos envan ThisForm.InBuffer = ; STRTRAN(ThisForm.InBuffer,"*","") lnNamePos = AT("/",ThisForm.InBuffer,1) + 1 lnSizePos = AT("/",ThisForm.InBuffer,2) + 1 lcName = SUBSTR(ThisForm.InBuffer,; lnNamePos,lnSizePos-lnNamepos-1) lnSize = VAL(SUBSTR(ThisForm.InBuffer,lnSizePos)) ThisForm.txtStatus.Value = "Recibiendo Fichero : "+lcName+" - "+"Tamao : "+ALLT(STR(lnSize))+" bytes" lnParcial = 0 ThisForm.NuevoFichero = FCREATE(lcName) Else Insert Into cLog (User_id,Mensaje,Hora) Values ("Remoto:", ThisForm.InBuffer,DateTime()) ThisForm.Grid1.Refresh() ThisForm.InBuffer = "" EndIf EndIf Else && modo transmisin fichero ThisForm.Status.Value=100*lnParcial/lnSize lnNumChars=FWRITE(ThisForm.NuevoFichero, lcEntrada) lcError = FERROR() IF lcERROR != 0 wait wind nowait "Se ha producido un error en la escritura del fichero" ENDIF lnParcial = lnParcial + lnNumChars Thisform.txtStatus.Value = "Recibiendo Fichero : "+lcName+" Completados "+ALLT(STR(lnParcial))+" bytes de "+ALLT(STR(lnSize)) EndIf If lnParcial = lnSize && fin transmisin FCLOSE(ThisForm.NuevoFichero) MessageBox("Fichero recibido",0+64,"Aviso") ?CHR(7) ThisForm.Status.Value = 0

Thisform.txtStatus.Value = "" EndIf EndIF Puede que el cdigo parezca algo enrevesado, debido a que hemos incluido la funcionalidad de enviar ficheros mezclada con la de mandar cadenas de texto. Desde luego, resultara ms sencillo hacerlo por separado, pero bueno, esto no es sino una pequea muestra de lo que puede dar de s el control. Con unos pocos cambios, tambin podramos adaptar este ejemplo para copiar ficheros a nuestro portatil si no tenemos tarjeta de red, ya que como hemos dicho al principio, no hace falta que haya un mdem entre los puertos COM conectados. Otra posible utilidad de este control sera la de capturar datos de los lectores de cdigos de barras que tienen la conexin por puerto serie en vez de por teclado, para introducir lecturas en aplicaciones de TPV. En general, podemos obtener lecturas de cualquier dispositivo que conectemos a un puerto serie

También podría gustarte