'' Comunicaciones con MSCOMM32.OCX

Por Pedro Pascua






En el número correspondiente a Marzo de 1998 escribí un artículo sobre el control MSCOMM32.OCX y tengo que reconocer que me ‘llovieron’ bastantes sugerencias y comentarios de multitud de programadores de todos el mundo.

Como el VFP 6.0 ha salido hace poco creo que ha llegado el momento de actualizar ese código incorporando todas las sugerencias que he recibido y adaptándolo a la nueva versión.

La versión del control que se instala con el VS6.0 (v.6.00.8169) no presenta diferencias apreciables con respecto a su predecesor (v.5.01.4319)(recuerdo que esta versión a su vez cambio al instalar el SP2 para VFP 5.0) a excepción de su tamaño (101 Kb frente a 95,2 Kb). Las ventanas de propiedades son idénticas a las que ya conocíamos.

Antes de continuar quiero reseñar que ese código (el que salió en Marzo de 1998) adolece de un grave problema y es que sólo es válido para el caso de trasmisión de ficheros planos tipo ASCII pero no es válido para los ficheros binarios. Dentro de los ficheros binarios podemos agrupar los ficheros tipo .GIF,JPG, etc...

Otra notable carencia que me parece que no fue reseñada suficientemente en ese artículo es que siempre que uses controles del tipo .OCX en tus formularios debes de probar si funciona mejor poniendo el AUTOYIELD a .T. ó a .F. Esto es algo básico que ha hecho perder muchas horas a muchos programadores.

Para el caso de este control si lo pones a .F. verás que la trasmisión va a golpes e incluso se para en lugares aleatorios sin ninguna explicación.

Por contra, si lo pones a .T. la trasmisión ira fenomenal pero por contra tendrás algunos problemas a la hora de poner un termomentro o algúna otra utilidad que le indique al usuario el estado de su comunicación.

La propiedad AUTOYIELD la ayuda nos dice que sirve para indicar si “una instancia de Visual FoxPro procesa eventos de Windows pendientes entre la ejecución de cada línea de código de programa de usuario.”

Y la propia Ayuda comenta: “Debería establecerse la propiedad AutoYield como falso (.F.) siempre que un formulario contenga un control ActiveX. El hecho de establecer AutoYield en falso (.F.) impide que los eventos para un control ActiveX se ejecuten entre líneas de código de programa de usuario. Por ejemplo, si AutoYield está establecida en verdadera (.T.), el hecho de hacer clic en un control ActiveX mientras se está ejecutando código de programa de usuario puede provocar que se ejecute un evento para el control ActiveX, ignorando el código de programa de usuario para el evento, lo que tendría consecuencias impredecibles o indeseables.”

La parte de código que gestióna el ‘chat’, permanece invariable, las modificaciones interesantes son las destinadas a enviar/recibir ficheros. El proceso se inicia cuando pulsamos el botón de enviar y seleccionamos el fichero que queremos transmitir. En ese momento, enviamos una cadena especial en modo texto en la cual indicamos al otro comunicante que vamos a iniciar el envío de un fichero, pasándole a la vez la información del nombre del fichero y su tamaño. En este momento, el formulario receptor configura el control para iniciar la recepción, modificando las propiedades del control para permitir la recepción de datos binarios como veremos a continuación . A partir de aquí comienza una comunicación.

Registrar el MSCOMM32.OCX

También es importante en el momento en el que se va a realizar la instalación en un cliente la obligación de registrar el control mediante el REGSRV32.exe o mediante algunas funciones que acudan al Registry a realizar esta operación.

En tu entorno de desarrollo si por la razón que sea no lo tienes registrado puedes escoger la opción de abrir el herramientas/Opciones. Activar la página de controles, comprobar los controles ActiveX. Mira en la lista para ver si encuentras en Microsoft Communication Control. Si está marcado entonces no tienes que hacer nada. Si no está marcado entonces deberás añadirlo desde el directorio de:

C:\windows\system\mscomm32.ocx.

a continuación crea un formulario, activa los controles ActveX (deberías ver este control simbolizado en un teléfono). A continuación, basta con que lo arrastres al formulario. Si lo has conseguido quiere decir que vamos bien.

En caso de que no lo consigas se deberá de usar el Regsrv32.EXE. Este programa reside en el directorio de VFP. Si lo ejecutas con C:\WINDOWS\MSCOMM32.OCX se debería registrar el ActiveX y dejarlo disponible. Vuelve en este caso a intetar hacer drag and drop con el control y soltarlo en el formulario.

Las Propiedades

De todas las propiedades que tiene este control en realidad se usan muy pocas por eso uno no debe dejarse avasallar por tal cúmulo de propiedades. No obstante, si se quieren ver en detalle y conocer su funcionamiento correcto puedes mirar la bibliografía que te trascribo .

Las propiedades que principalmente usamos son las siguientes:

Commport
Portopen
Settings
Inputlen
Input
Output

A continuación tienes una equivalencia entre esas propiedades y las funciones tradicionales que teníamos en el mundo xBase.

Otro asunto interesante es la forma de depurar tu código sin tener que estar continuamente comunicándote con un modem, etc...

Lo mejor es que abras dos proyectos en tu misma máquina y los formularios (al menos en depuración) sean del tipo SDI pues de esa manera es mucho más fácil pasar de una aplicación a otra.

La otra propiedad importante en este proceso es el InputMode del control MsComm32. Cuando está a 0 (=text) , cada byte se envía en modo texto, con lo que los caracteres especiales o no imprimibles, desaparecen por el camino. cando el InputMode=1 (=binary), el buffer de entrada del control Thisform.CommConTrol.Input pasa de ser una cadena de caracteres a convertirse en una matriz de números, uno por cada byte recibido, que guarda el código ascii de cada carácter enviado. De este modo, cada byte del fichero enviado llega integro al receptor, no habiendo más que convertirlo con la función CHR() y escribirlo en el fichero.

En las primeras pruebas, implementamos este proceso como acabamos de describir, enviando de uno en uno cada byte del fichero. Funcionaba bien, pero era demasiado lento, por lo que hubo que modificar el código para aprovechar los buffers de entrada y salida del control y enviar bloques de bytes con lo cual conseguimos una velocidad más razonable. Después de muchas pruebas, hemos dejado el ejemplo funcionando con un envío en bloques de 1024 bytes, para lo cual hay que configurar el control como sigue:

Formulario Emisor
----------------
.CommConTrol.InputMode     = 0
.CommConTrol.InBufferSize  = 1024
.CommConTrol.OutBufferSize = 1024
  .CommConTrol.Sthreshold    = 1024
.CommConTrol.Rthreshold    = 1
.CommConTrol.InputLen      = 1


Formulario Receptor
-------------------
.CommConTrol.InputMode     = 1
.CommConTrol.InBufferSize  = 1024
.CommConTrol.OutBufferSize = 1024
.CommConTrol.Sthreshold    = 1
.CommConTrol.Rthreshold    = 1024
.CommConTrol.InputLen      = 1024
Esta configuración indica al control emisor que no debe envíar nada hasta que no tenga un bloque de 1024 bytes en el buffer de salida, pero que debe generar un evento OnComm de notificación de entrada cada vez que tenga un carácter de entrada (el carácter que le manda el receptor cuando está listo). Del mismo modo, el receptor esperará a tener todo el bloque de bytes en el buffer para notificarlo, y cuando leamos de este nos pasará el bloque entero, pues así lo especificamos en la propiedad InputLen. Sin embargo, en el momento que tenga un carácter en salida (notificación al emisor de que continue el envío) lo mandará hacia el puerto.

Está configuración funciona bastante bien y sólo requiere un pequeño truco del lado del emisor, que consiste en ajustar el último bloque de bytes que se lea del fichero, que obviamente no tiene por que ser de 1024 bytes y rellenarlo con blancos hasta completar el bloque para llenar el tamaño del buffer y que el control le de salida.

El ejemplo se puede adaptar en cuestión de minutos para utilizar bloques de bytes mayores y mejorar el rendimiento de la transmisión, no obstante, hay que ser cautos pues existen ciertos rumores de que al utilizar el control con buffers mayores de 2048 bytes, pueden llegar algunos bytes erroneos. Así que quizás sea mejor quedarse con el dicho de que “lento pero seguro”...

No quiero trascribir todo el código pues está en el fichero fuente. Pero, para los que no pudieron ver o leer el artículo anterior únicamente hacer la salvedad de que antes de intentar ejecutar o mirar este código se deben asegurar de que la versión de su control coincide con ésta.

Unicamente voy a poner el código que recibe los caracteres por el puerto.


Else		&&	Recibiendo un fichero
	lcStr = ""
	nBufferLen = Min(1024,gnSize - ;
		gnParcial)
	For i = 1 To nBufferLen
		lcStr = lcStr + CHR(lcInput(i))
	EndFor
	lnNumChars = FWRITE(ThisForm.;
		NuevoFichero,lcStr)

	Thisform.CommControl.Output = "."
	lcError = FERROR()
	IF lcERROR != 0 
		wait wind nowait "Se ha producido ;
			un error en la escritura del ;
			fichero"
	ENDIF
	gnParcial = gnParcial + lnNumChars
	Thisform.txtStatus.Value = ;
		"Recibiendo Fichero : "+gcName+" ;
		- Completados ; "+ALLT(STR(gnParcial))+;
		" bytes de "+ALLT(STR(gnSize))
	ThisForm.Status.Value = 100 * ;
		gnParcial / gnSize
	If gnParcial = gnSize
		FCLOSE(ThisForm.NuevoFichero)
		MessageBox("Fichero ;
			recibido",0+64,"Aviso")
		?CHR(7)
		ThisForm.Status.Value = 0
		Thisform.txtStatus.Value = ""
		ThisForm.lChat = .T.
		lcInput = Thisform.CommConTrol.Input	
		ThisForm.InBuffer = ""
		Thisform.OutData.Enabled = .T.
		Thisform.CommControl.InputMode = 0
		Thisform.CommControl.InputLen = 1
		Thisform.CommControl.RThreshold = 1	
		Thisform.CommControl.SThreshold = 1	
	EndIf
	ThisForm.refresh()
EndIF

Pedro Pascua es programador de Visual FoxPro y Visual Basic y últimamente también de HTML


© 1998 FoxPress. All rights reserved.