¿Funciona Visual FoxPro 9 en Windows 10?

Artículo original: Does Microsoft Visual FoxPro 9 run on Windows 10?
http://mattslay.com/does-microsoft-visual-foxpro-run-on-windows-10
Autor: Matt Slay
Traducido por: Luis María Guayán

Estoy seguro que muchos desarrolladores empedernidos de FoxPro tienen la curiosidad si Visual FoxPro 9.0 SP 2 se instalará y ejecutará en Windows 10. Bueno, yo quería ser uno de los primeros en descubrirlo, al igual que lo hice antes cuando Windows 8 fue lanzado por primera vez en su primera vista previa.

Por lo tanto vamos a averiguarlo...

En primer lugar, he instalado Windows 10 Preview (64 bits) en una partición de BootCamp en mis 15" MacBook Pro. (No se preocupen por estas cosas de Mac, es sólo Windows corriendo en hardware vivo, como si fuera una computadora Dell o HP). Eso salió muy bien e hice una instalación completa, quitando el Windows 8 que había estado utilizando en esa partición, en vez de actualizar desde Windows 8 a Windows 10.

A continuación, inserté con cuidado el CD de Visual FoxPro 9 que aún tengo desde 2004. En primer lugar, me impulsó a instalar unos "requisitos previos", cosa que hizo sin problemas. Luego seguí con la instalación principal de VFP y escogí todos los valores predeterminados, entonces el CD giraba y paraba un poco, y finalmente, me mostró una pantalla con un lindo mensaje indicando "Instalación completa" y "No hubo ningún error durante la instalación." Hasta ahora se ve bien!



A continuación, descargué e instalé el Service Pack 2 para VFP 9 y una vez más tengo este no muy bonito cuadro de mensaje de confirmación:



Por último, "instalé" el VFP 9 Hotfix 3 para SP2 (es decir, copié los archivos de reemplazo en los lugares correctos según las instrucciones del archivo "leeame" de la descarga).

Ahora tenemos una prometedora entrada de Microsoft Visual FoxPro 9.0 en el nuevo y lujoso Menú Inicio de Windows 10:



Sí, pero en realidad funciona??

Ahora, finalmente puedo averiguar si puedo ejecutar Microsoft Visual FoxPro 9.0 SP2 versión 09.00.0000.7423 con todos los parches en Windows 10. Entonces lo ejecuto y rápidamente voy a Menú Inicio -> Ayuda -> Acerca de:



Bien, muestra que el número de versión es correcto, pero nosotros necesitamos ejecutar código FoxPro para asegurarnos de que esto realmente funciona... Entonces, he descargado la Herramienta de Administración Thor para VFP9 de vfpx.codeplex.com y ejecuté Thor.app para realizar la primera prueba de VFP 9 en Windows 10. Thor utiliza toneladas de código FoxPro bien diseñado para hacer su magia, junto con algunos formularios de interfaz de usuario y hace uso de nuestros amados cursores de FoxPro, así que me imaginé que esto sería una buena prueba. Seleccioné 10 de mis herramientas favoritas de VFPx desde el formulario de comprobar actualizaciones de Thor, y perfectamente procedió a descargar e instalar todas las herramientas y mostró en el escritorio de VFP los resultados de confirmación de que realizó la tarea para cada una:



Creo que son buenos amigos!

A continuación, ejecuté algunas de estas herramientas, para asegurarme de que correrian y lo hicieron. Estoy seguro en este momento, que mis aplicaciones de negocio funcionaran muy bien, aquí si me tomé tiempo para terminar de instalar la configuración de desarrollador.

Por lo pronto no he hecho ningún trabajo de codificación real en el IDE, y probablemente no lo haga en el corto tiempo, pero de mis pruebas básicas en este experimento, me parece que nuestro viejo amigo Visual FoxPro está listo para continuar con su legado de ser una increíble herramienta de desarrollo, incluso en Windows 10 y espero que en Windows 20 y Windows 30 también.

Finalmente, aquí está completo y maximizado el IDE, corriendo en Windows 10. Pueden ver algunas ventanas acopladas, y pueden ver el efecto de sombreado que Windows 10 agrega alrededor de las ventanas individuales.




Cómo añadir un generador a sus clases


Articulo original: How to add a Builder to your Class
http://weblogs.foxite.com/bernardbout/2014/09/18/how-to-add-a-builder-to-your-class
Autor: Bernard Bout
Traductor: Luis María Guayán

Es posible que haya visto que varias de mis clases vienen con un generador (builder) incorporado que hace mas fácil configurar las propiedades correctas y brinda una visión correcta de cómo se verá el objeto con las propiedades ya establecidas.

Recientemente uno de los chicos de Foxite ha creado una clase Spinner ideal para tocar con dedos grandes y yo le envié un Generador para ello. Me pidió un tutorial sobre cómo crear un generador así, y como también había estado pensando que esto sería útil, me decidí a documentar el proceso aquí. Nosotros vamos a usar la clase Spinner creada por Tony Vignone para esto (todo está incluido en la descarga) o Ud. puede utilizar cualquier otra clase que desee.

Una clase visual personalizada puede tener una serie de propiedades que necesitan configurarse, y es útil que el usuario final tenga todo esto en un solo lugar, en vez de una larga lista. Así que lo primero que hay que hacer es agregar las propiedades que el usuario puede cambiar, en la solapa Favoritos. De esta manera las propiedades que cambian, son independientes de las propiedades internas y que no cambian.

Para esto la clase necesita tener MemberData. Así que este es el primer paso en la creación de la clase.

1. Abra la clase y agregue una propiedad personalizada _memberdata [guión bajo - memberdata]




1.2. En la hoja de propiedades, seleccione cada propiedad para ser agregada a la solapa Favoritos, haga clic derecho sobre ella y en el menú emergente seleccione "Agregar a favoritos"

2. Añada otra propiedad personalizada a su clase y nómbrela _BigSpinnerBuilder. Darle un valor inicial de 0 [cero]. Haga clic derecho sobre ella, y añadirla a la solapa de Favoritos.

3. Haga clic derecho sobre esta nueva propiedad _BigSpinnerBuilder y seleccione "Editor MemberData" en la ventana emergente, y se abre el Editor MemberData. Configurarlo como en la siguiente imagen, haga clic en el icono de lupa y en la ventana de código que se abre, pegar el siguiente código:

nControls = ASelObj(aObjects)
If nControls # 0
   oObject = aObjects(1)
   Set Classlib To (oObject.ClassLibrary)
    IF VARTYPE(_screen.oWiz) = "U"
       _screen.addproperty("oWiz","")
    ENDIF
   _screen.oWiz = Createobject("BigSpinnerBuilder", oObject)
   _screen.oWiz.Show()
EndIf


Controlar múltiples monitores

Artículo original: Handling Multiple Monitors
http://doughennig.blogspot.com/2007/04/handling-multiple-monitors.html
Autor: Doug Hennig
Traducido por: Ana María Bisbé York

Una de las cosas que hice con mi nuevo portátil fue configurarle múltiples monitores. Algunos desarrolladores que conozco y respeto lo han hecho desde hace años, así que supongo que ya sea hora de que yo también lo intente. No hay nada que decir, me gusta. Tengo generalmente el Examinador y explorador de Windows abiertos en el segundo monitor y mantengo el monitor primario para aquellas cosas que hago a lo largo del día (principalmente VFP y Outlook). Soy más productivo ahora que no tengo que moverme entre la pila de ventanas ni moverme o redimensionar constantemente una ventana.

Sin embargo, una de las cosas que he descubierto hoy, es que algunas de mis aplicaciones no respetan el segundo monitor. Por ejemplo, tengo una clase llamada SFPersistentForm que arrastro a la mayoría de mis formularios. Esta clase guarda el tamaño y posición del formulario cuando se cierra y lo restaura cuando se abre nuevamente, dando al usuario la experiencia que el espera al trabajar con este formulario. Sin embargo, he descubierto que si abro el formulario y lo muevo al segundo monitor, luego llo cierro, y cuando lo reabro el formulario se muestra sin embargo, en el primer monitor (es un formulario con Desktop = .T., por tanto puede existir fuera de la aplicación).

Rápidamente encontré la razón: el código intentaba evitar la situación en la que el formulario pudiera abrirse fuera de los límites de la pantalla, haciéndolo invisible. El siguiente código controla esto:
Thisform.Width = min(max(Thisform.Width, 0, Thisform.MinWidth), ;
  _screen.Width)
Thisform.Height = min(max(Thisform.Height, 0, Thisform.MinHeight), ;
  _screen.Height)
Thisform.Left = min(max(Thisform.Left, 0), _screen.Width - 50)
Thisform.Top = min(max(Thisform.Top, 0), _screen.Height - 50)
("-50"  se utiliza para garantizar que el formulario no comience exactamente  la derecha del borde del monitor, haciéndolo esencialmente invisible.)

Existen dos problemas con este código. Primero, la confiabilidad en _SCREEN asume que el formulario existe con _SCREEN, que es un formulario de nivel superior o uno con Desktop = .T., que no es necesariamente el caso. Segundo, si se maximiza _SCREEN, solo cabe en el monitor actual. Si el formulario está en el otro monitor, las dimensiones de _SCREEN son irrelevantes.

Inicialmente cambié el código:
if Thisform.Desktop or Thisform.ShowWindow = 2
  lnWidth = sysmetric(1)
  lnHeight = sysmetric(2)
else
  lnWidth = _screen.Width
  lnHeight = _screen.Height
endif Thisform.Desktop ...
Thisform.Width = min(max(Thisform.Width, 0, Thisform.MinWidth), ;
  lnWidth)
Thisform.Height = min(max(Thisform.Height, 0, Thisform.MinHeight), ;
  lnHeight)
Thisform.Left = min(max(Thisform.Left, 0), lnWidth - 50)
Thisform.Top = min(max(Thisform.Top, 0), lnHeight - 50)
Sin embargo, SYSMETRIC() sólo devuelve valores para el monitor primario. Entonces, cambié las sentencias a:
declare integer GetSystemMetrics in Win32API integer
#define SM_CXVIRTUALSCREEN 78 && Ancho Virtual 
#define SM_CYVIRTUALSCREEN 79 && Altura Virtual 
lnWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN)
lnHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN)
Ahora el formulario se reabre en la misma posición exacta, incluyendo el monitor donde estaba antes.

Evolución del tratamiento de cadenas con TEXTMERGE

Como siempre, VFP ha ido evolucionando, y desde hace tres versiones el manejo de cadenas y TEXTMERGE ha sido uno de los que más impacto y mejora de funcionalidad ha tenido.

A continuación una experiencia que me llevé al manejarlo para crear cadenas de conexión hacia cliente servidor.

Estaba desarrollando una clase para manejo de conexiones y usarios a bases de datos remotas (a servidores de Base de Datos para ser más específico), cuando me tope con un código que según mi vieja memoria, podría optimizarse (o reducirse) un poco.

El caso estaba en que teniendo una tabla con los usuarios y passwords, poder armar una cadena de conexión hacia SQLServer:
SET TEXTMERGE ON
SET TEXTMERGE TO MEMVAR lcStringConnection
Driver={SQL Server};Server=<<alltrim(cServer)>>
;Database=<<alltrim(cDataBase)>>;Uid=<<alltrim(cUser)>>
;Pwd=<<alltrim(cPassword)>>;
SET TEXTMERGE TO
SET TEXTMERGE OFF

Esto funciona correctamente, y hace su trabajo como debe ser, pero puede quedar aún mejor!!, por lo que revisé la ayuda de SET TEXTMERGE, encontrándome que ésta puede simplificarse...
TEXT TO lcString NOSHOW TEXTMERGE
Driver={SQL Server};Server=<<alltrim(cServer)>>
;Database=<<alltrim(cDataBase)>>;Uid=<<alltrim(cUser)>>
;Pwd=<<alltrim(cPassword)>>;
ENDTEXT

Hasta ahí todo funciona correcto, ya he quitado algunas líneas sin perder funcionalidad, pero se me ocurrió algo, que de éste modo estaría atado a escribir en el código cada cadena de conexion si es que quisiera tener más de un servidor de bases de datos, teniendo con esto, que modificar mi código fuente en el caso que dicha cadena de conexión llegara a cambiar en un futuro, o si deseara agregar algún otro tipo de servidor (quizás MySQL, FireBird, PostgreSQL)...

Mi primera idea vino en tener tambien en una tabla DBF, las correspondientes cadenas de conexión según el servidor a usar, y simplemente hacer un textmerge desde esa cadena escrita en mi tabla, sonaba bien en un inico, pero me topé con un problema, cómo macrosustituia mi campo de mi tabla dentro de un bloque TEXT ... ENDTEXT??

Los siguientes fueron mis intentos:
1.- Pondré el campo de mi tabla en el bloque...
TEXT TO lcStringConnection NOSHOW PRETEXT
   cServer.cStringConnection
ENDTEXT

2.- Poner el campo de mi tabla macrosustituyendo...
TEXT TO lcStringConnection NOSHOW PRETEXT
  &cServer.cStringConnection
ENDTEXT

3.- Poner el campo de mi tabla con expresión de nombres...
TEXT TO lcStringConnection NOSHOW PRETEXT
  (cServer.cStringConnection)
ENDTEXT

4.- Poner el campo de mi tabla evaluando...
TEXT TO lcStringConnection NOSHOW PRETEXT
  EVALUATE(cServer.cStringConnection)
ENDTEXT

No está demás decir que ninguna de las opciones funcionó :'(, el problema radica en que lo que se pone en un bloque TEXT... ENDTEXT, se evalua literalmente, por lo que tendría que hacer un TEXTMERGE de lo que contenia la variable...

TEXT TO lcStringConnection NOSHOW TEXTMERGE
  <<cServer.cStringConnection>>
ENDTEXT

Bingo!, ya se expandió la variable, pero no era precisamente lo que quería, ya que el contenido de esa variable era el texto de mi campo, pero aún le faltaba expandir los campos de mi tabla, tales como usuario, password, etc. Por lo que necesitaba algo así como un textmerge anidado :S. Se me ocurrieron varias cosas, como mandarlo a ejecutar con ExecScript primero, retomar el valor y hacerle un segundo TEXTMERGE, hmm, no, demasiado rollo para sólo eso, recorrer la cadena expandida y cambiar los valores... si, quizás, pero nada adecuado.

Una vuelta más a la ayuda de SET TEXTMERGE me dió la solución, la función TextMerge(), que aparentemente hace lo mismo que SET TEXTMERGE TO MEMVAR y los bloques TEXT .. ENDTEXT, probé y milagro!, justo lo que esperaba (segun lo leido), tienen la función... pero con esteroides, ya que también implementa la expansión de variables de manera recursiva, en este caso primero expande lo que hay en cServer.cServidor, y como ésta misma tiene expansión de variables, vuelve a hacer un textmerge de manera implícita, expandiendo igualmente el contenido de las variables de servidor, usuario, contraseña, contenidas en la tabla de perfiles de usuario, con lo que mi código se había reducido a lo siguiente:

IF SEEK(lcTipoServer,"cServer")
  IF SEEK(lcPerfilUsuario,"cPerfiles")
    lcStringConnection = TextMerge(cStringConnection)
  ELSE
     *** Perfil de usuario no encontrado
  ENDIF
ELSE
   *** Tipo de Servidor no encontrado 
ENDIF

Con esto, sólo tuve que mover la cadena a sustituir hacia mi tabla dónde ahora puedo guardar distintas cadenas de conexión y simplemente sustituirlas, de este modo no solo tengo cómo conectarme, sino también la flexibilidad de usar cualquier tipo de servidor que acepte una cadena de conexión (hasta ahora todos los que he usado).

Para colmo, cinco dias después de andar batallando con esto, me encuentro con el siguiente artículo en FoxAdvisor:

--- Understanding TEXTMERGE ---
http://advisorupdate.info/Articles.nsf/nl/16362

Moraleja de la historia, nunca hay que dejar de leer por completo, la ayuda del producto, más en específico, los What's New de cada versión.

Espero que la información les sea de utilidad...

Espartaco Palma Martínez