29 de febrero de 2008

Actualización de VFPCompression - Corrección de rutas relativas

Artículo original: VFPCompression Update - Relative Path Fixes
http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,41e05bd6-f856-4837-93f0-b295ff1d2bb6.aspx
Autor: Craig Boyd
Traducido por: Luis María Guayán

Actualización de VFPCompression

Esta actualización contiene la corrección a los problemas sobre las rutas relativas al comprimir carpetas y archivos que no estan relacionados unos a otros, o con el archivo zip que se esta creando. Antes de esta versión los desarrolladores tenían que pasar .T. para el parámetro lIgnorePath cuando llamaban a las funciones con el fin de crear el zip con los archivos y carpetas que no eran relativos. Este no era una solucion aceptable cuando la ruta relativa para subcarpetas sería ignorada luego también. Este ha sido un escollo para algunos que implementaron este FLL, entonces me alegro que finalmente este corregido y lamento que esto me tomó demasiado tiempo para corregir este problema.

Un agradecimiento muy especial para Sergey Berezniker y Elliot Selick. Ellos de manera independiente me informaron sobre el tema de las rutas relativas y ayudaron con las pruebas una vez que yo me había ocupado del tema.

El código de ejemplo para usar la biblioteca y la documentación de biblioteca puede ser encontrado en mi artículo anterior. Aquí está el enlace habitual para la descarga...

Actualización de VFP Compression:

Descarga de VFPCompression FLL (35 KB aprox.)

25 de febrero de 2008

Actualización de aplicación VFP de manera sencilla

Artículo original: VFP Application Updating Made Simple
http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,06bb82c3-9e4c-4048-9b3b-87cc8579eb59.aspx
Autor: Craig Boyd
Traducido por: Luis María Guayán

Corrección del 16/02/2008: Gracias a Dave Crozier por encontrar un error en el código (vea los comentarios más abajo). Un nuevo archivo .Zip de AppUpdate.zip se ha subido al servidor. Si ya ha descargado el .Zip, puede descargarlo de nuevo o hacer los cambios que se describen en los comentarios de este artículo.

Actualizando aplicaciones Visual FoxPro

Una de las cosas que he tratado de hacer en mi artículo sobre ClickOnce, era proporcionar a los desarrolladores Visual FoxPro, la comprensión de una de las tantas soluciones disponibles para la actualización de las aplicaciones una vez que ya se han distribuido. Aunque ClickOnce es muy poderoso, hay momentos en que una solución mas de cosecha propia, puede ser más apropiada. La actualización de aplicaciones, con aplicaciones que los desarrolladores han escrito y/o poseen el código fuente, también pueden ofrecer un grado de flexibilidad y poder que sólo no se encuentra disponible en soluciones como ClickOnce, ni en el servicio de actualización de InstallShield. Así que en esta entrada del blog, presentaré una aplicación que he creado usando Visual FoxPro SP2 que se puede utilizar para actualizar prácticamente cualquier aplicación Visual FoxPro.

AppUpdate.exe AppUpdate.exe

AppUpdate.exe es lo que se conoce como un 'cargador' (loader). Esto significa básicamente que es responsable de la comprobación de las actualizaciones, la instalación en caso de que estas existan, y luego la ejecución de la aplicación que se actualizó. Basándose en gran medida en la utilización de las nuevas vfpcompression.fll y vfpconnection.fll, AppUpdate.exe está diseñada para permitir a los desarrolladores de Visual FoxPro, añadir rápida y fácilmente, la capacidad de actualización de sus aplicaciones. Aquí hay un par de capturas de pantalla de AppUpdate ejecutándose...





Si bien estoy incluyendo el código fuente del proyecto AppUpdate, este no es necesario para modificar AppUpdate con el fin de configurarlo para actualizar una aplicación particular. AppUpdate obtiene su información del archivo appupdate.ini que proporciona una gran variedad de secciones y de entradas que le permitirá especificar qué aplicación se supone que la carga, cuando comprobar si hay actualizaciones, la manera de cargar la aplicación, lo que se muestra al usuario, donde copia localmente las actualizaciones con el fin de que la misma actualización sólo debe descargarse una vez en un entorno multiusuario, cuando mostrar las actualizaciones, que código VFP se ejecutará una vez que la actualización se ha instalado, etc. Así que, como desarrollador sólo necesita modificar el archivo ini para adaptar AppUpdate, con su conjunto de aplicaciones VFP.

En la descarga ...

En la descarga he incluido un ejemplo totalmente funcional de AppUpdate, junto al código fuente. He incluido sampleapp.exe que es la versión 1.0 y he puesto una actualización para este (la versión 2.0) en el servidor de SweetPotato Software para este fin, por lo que puede realmente probar AppUpdate y ver cómo funciona directamente del servidor. He incluido muchos comentarios en el archivo appupdate.ini que deseara examinar y un par de archivos ReadMe.txt. Simplemente descargue el archivo zip de abajo, extráigalo en algún lugar, lea rápidamente el archivo ini y el archivo ReadMe.txt incluidos, y luego ejecute AppUpdate.exe. Cuando comience a querer crear sus propias actualizaciones, puede echar un vistazo a la carpeta ServerUpdate que he incluido en la descarga, y contiene los archivos que están en el servidor de SweetPotato Software que está actualizando sampleapp.exe provisto en la descarga.

Quiero saber lo que piensas

Si prueba AppUpdate, me encantaría saber lo que piensas de él. Si tiene alguna sugerencia para mejorar o encuentra algún error, no dudes en dejar un comentario y yo responderé.
Hasta la próxima… Visual FoxPro Rocks!

Descarga del Proyecto AppUpdate y Ejemplo (922 KB aprox.)


Comentarios:

Craig,
Hay un problema en el proyecto ApplicationUpdate. En el formulario UpdateMessage, en el método downloadupdate() hay dos líneas mal:
* Lineas antiguas 
* m.lcUpdateFile = "File://" + m.lcUpdateFile 
* m.llReturn = FileGet(this.updateFile, m.lcUpdateURL,"m.goThisForm.ProgressHandler()") 
* Nueva linea 
This.UpdateURL = "File://" + This.UpdateURL m.llReturn = ;
  FileGet(this.updateurl, m.lcUpdateFile, "m.goThisForm.ProgressHandler()") 
Saludos,
Dave Crozier

Gran captura Dave!!
He subido un archivo .Zip corregido. El código en el método downloadupdate() fue modificado por el siguiente ...
OTHERWISE 
  IF UPPER(LEFT(This.UpdateURL, 7)) != "FILE://" 
    This.UpdateURL = "File://" + This.UpdateURL 
  ENDIF 
  m.llReturn = FileGet(This.UpdateURL, m.lcUpdateFile, "m.goThisForm.ProgressHandler()") 
ENDCASE 
Craig Boyd

22 de febrero de 2008

Cargando/descargando en VFP de manera sencilla

Artículo original: VFP Uploading/Downloading Made Simple
http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,e7cccb45-7d99-4c35-85bc-e123c81c8794.aspx
Autor: Craig Boyd
Traducido por: Luis María Guayán

Cargando, descargando y mas

Siempre he querido algunos comandos en lenguaje Visual FoxPro que realizaran cargas y descargas de archivos de sitios Web, de sitios FTP u otra ubicación, realmente fácil. Ah, también he querido un indicador de progreso para estas cargas y descargas que sea fácil de implementar. Habiéndome enredado con varias librerías de clases, y componentes de terceros por algunos años, decidí que era tiempo de escribir una FLL que haga lo que yo quería, entonces cree vfpconnection.fll.

VFP Connection FLL

Internamente vfpconnection.fll está utilizando la biblioteca LibCurl (aquí esta su licencia), por lo que hay toneladas de otras características que puedo, y podría, agregar como esto avance. Por ahora proveeré a los desarrolladores VFP con lo que creo que es mas fácil y sencillo, funciones de carga y descarga de archivos en Visual FoxPro (FTPGet, HTTPGet, FileGet, FTPPut, HTTPPut, FilePut, FTPToStr, y HTTPToStr). También se ofrece la posibilidad de descargar archivos de FTP y HTTP en la memoria (similar a la función FileToStr) que evita la escritura y lectura de disco, y puede resultar muy conveniente cuando un desarrollador sólo quiere leer algo de un servidor. Y ofrece una vía sumamente fácil de implementar un indicador de progreso a través de una llamada a una función o método.

Lo que viene ...

He creado un ejemplo bien bonito de lo útil de tener una FLL como ésta. En mi próxima entrada de mi blog, presentaré una aplicación VFP que he creado llamada AppUpdate, con lo que usted será capaz de usar Cargas/Descargas para sus aplicaciones Visual FoxPro como muy avanzado (aunque sea simple). Un agradecimiento especial a un cliente mío por permitirme salir antes de tiempo y compartir con mis lectores. ¡Pase lo que pase, hasta próxima … Visual FoxPro Rocks!

Aquí está el enlace de descarga acostumbrado, algunos ejemplos de código para usar vfpconnection.fll, y la documentación de la librería:
Descarga de VFPConnection FLL (90 KB aprox.)

Código de ejemplo de VFPConnection:

SET LIBRARY TO (LOCFILE("vfpconnection.fll","FLL"))
? FTPGet("FTP://myusername:mypassword@mysite.com/mydir/myfile.zip", "C:\myfile.zip", "MyCommand()")
? HTTPGet("http://www.mysite.com/mypage.htm", "C:\mypage.htm", "MyCommand()")
? FILEGet("File://C:\MyFile.txt", "C:\MyFileCopy.txt", "MyCommand()")
? FTPPut("C:\myfile.zip", "FTP://myusername:mypassword@mysite.com/mydir/myfile.zip", "MyCommand()")
? HTTPPut("C:\mypage.htm", "http://www.mysite.com/mypage.htm", "MyCommand()")
? FilePut("C:\myfile.zip", "File://C:\myfile.zip", "MyCommand()")
m.lcString1 = FTPToStr("FTP://myusername:mypassword@mysite.com/mydir/myfile.txt", "MyCommand()")
m.lcString2 = HTTPToStr("http://www.mysite.com/mypage.htm", "MyCommand()")
SET LIBRARY TO

FUNCTION MyCommand()
  ? nConnectTotalBytes
  ? nConnectBytesSoFar
ENDFUNC


Documentación de VFPConnection (Gracias Germán!!!)

Function FTPGet()

Sintaxis: FTPGet(cSourceURL, cDestination[, cCallbackFunction)

Parámetros:
cSourceURL - La URL para el archivo que desea descargar.
cDestination - La ruta (directorio) completa y el nombre de archivo donde desea guardar el archivo fuente.
cCallbackFunction - Una cadena opcional que indica una función, procedimiento o método que desea desencadenar cuando ocurra una lectura/escritura, algo como "MyCallback()".

Valor devuelto:
Lógico - regresa .T. si tiene éxito o .F. si la operación ha fallado.

Comentarios:
Esta función le da la capacidad para descargar un archivo desde un sitio FTP.
Para especificar el puerto o información de ingreso, simplemente debe incluirla en cSourceURL, como por ejemplo:

"FTP://myusername:mypassword@myftpsite.com:21/mydir/myfile.zip".

Cuando se llama a la función cCallbackFunction, la FLL crea dos (2) variables  (nConnectTotalBytes y nConnectBytesSoFar) dinámicamente. Estas variables pueden utilizarse con la función, procedimiento o método especificado para determinar el tamaño total en bytes del archivo fuente, así como el progreso total de la operación (Porcentaje = 100 * nConnectBytesSoFar / nConnectTotalBytes).


Function HTTPGet()

Sintaxis: HTTPGet(cSourceURL, cDestination[, cCallbackFunction)

Parámetros:
cSourceURL - La URL para el archivo que desea descargar.
cDestination - La ruta (directorio) completo y nombre de archivo donde desea guardar el archivo fuente.
cCallbackFunction - Una cadena opcional que indica una función, procedimiento o método que desea desencadenar cuando ocurra una lectura/escritura, algo como "MyCallback()".

Valor devuelto:
Lógico - regresa .T. si tiene éxito o .F. si la operación ha fallado.

Comentarios:
Esta función le da la habilidad para descargar un archivo desde un sitio web.

Cuando se llama a la función cCallbackFunction, la FLL crea dos (2) variables  (nConnectTotalBytes y nConnectBytesSoFar) dinámicamente. Estas variables pueden utilizarse con la función, procedimiento o método especificado para determinar el tamaño total en bytes del archivo fuente, así como el progreso total de la operación (Porcentaje = 100 * nConnectBytesSoFar / nConnectTotalBytes).


Function FILEGet()

Sintaxis: FILEGet(cSourceURL, cDestination[, cCallbackFunction])

Parámetros:
cSourceURL - La ruta (directorio) completo y nombre del archivo que desea copiar.
cDestination - La ruta (directorio) completo y nombre de archivo donde desea guardar el archivo fuente.
cCallbackFunction - Una cadena opcional que indica una función, procedimiento o método que desea desencadenar cuando ocurra una lectura/escritura, algo como "MyCallback()".

Valor devuelto:
Lógico - regresa .T. si tiene éxito o .F. si la operación ha fallado.

Comentarios:
Esta función le da la capacidad para copiar un archivo desde una ubicación local o remota..

El formato para el parámetro cSourceURL es ligeramente diferente a lo que podría esperarse. Para copiar el archivo C:\MyDir\MyFile.zip debe especificar cSourceURL como "FILE:// C:\MyDir\MyFile.zip".

Cuando se llama a la función cCallbackFunction, la FLL crea dos (2) variables  (nConnectTotalBytes y nConnectBytesSoFar) dinámicamente. Estas variables pueden utilizarse con la función, procedimiento o método especificado para determinar el tamaño total en bytes del archivo fuente, así como el progreso total de la operación (Porcentaje = 100 * nConnectBytesSoFar / nConnectTotalBytes).


Function FTPPut()

Sintaxis: FTPGet(cSource, cDestinationURL[, cCallbackFunction)

Parámetros:
cSource - La ruta (directorio) completo y nombre del archivo que desea subir.
cDestinationURL - La URL a donde debe subirse el archivo especificado en cSource.
cCallbackFunction - Una cadena opcional que indica una función, procedimiento o método que desea desencadenar cuando ocurra una lectura/escritura, algo como "MyCallback()".

Valor devuelto:
Lógico - regresa .T. si tiene éxito o .F. si la operación ha fallado.

Comentarios:
Esta función le da la habilidad para subir un archivo a un sitio FTP.
Para especificar el puerto o información de ingreso, simplemente debe incluirla en cDestinationURL, como por ejemplo:

"FTP://myusername:mypassword@myftpsite.com:21/mydir/myfile.zip".

Cuando se llama a la función cCallbackFunction, la FLL crea dos (2) variables  (nConnectTotalBytes y nConnectBytesSoFar) dinámicamente. Estas variables pueden utilizarse con la función, procedimiento o método especificado para determinar el tamaño total en bytes del archivo fuente, así como el progreso total de la operación (Porcentaje = 100 * nConnectBytesSoFar / nConnectTotalBytes).


Function HTTPPut()

Sintaxis: HTTPGet(cSource, cDestinationURL[, cCallbackFunction)

Parámetros:
cSource - La ruta (directorio) completo y nombre del archivo que desea subir.
cDestinationURL - La URL a donde debe subirse el archivo especificado en cSource.
cCallbackFunction - Una cadena opcional que indica una función, procedimiento o método que desea desencadenar cuando ocurra una lectura/escritura, algo como "MyCallback()".

Valor devuelto:
Lógico - regresa .T. si tiene éxito o .F. si la operación ha fallado.

Comentarios:
Esta función le da la habilidad subir un archivo a un sitio Web.

Cuando se llama a la función cCallbackFunction, la FLL crea dos (2) variables  (nConnectTotalBytes y nConnectBytesSoFar) dinámicamente. Estas variables pueden utilizarse con la función, procedimiento o método especificado para determinar el tamaño total en bytes del archivo fuente, así como el progreso total de la operación (Porcentaje = 100 * nConnectBytesSoFar / nConnectTotalBytes).


Function FILEPut()

Sintaxis: FILEPut(cSource, cDestinationURL[, cCallbackFunction])

Parámetros:
cSource - La ruta (directorio) completo y nombre del archivo que desea copiar.
cDestinationURL - La ruta (directorio) completo y nombre de archivo donde desea copiar el archivo especificado en cSource.
cCallbackFunction - Una cadena opcional que indica una función, procedimiento o método que desea desencadenar cuando ocurra una lectura/escritura, algo como "MyCallback()".

Valor devuelto:
Lógico - regresa .T. si tiene éxito o .F. si la operación ha fallado.

Comentarios:
Esta función le da la capacidad para copiar un archivo desde una ubicación local o remota..

El formato para el parámetro cDestinationURL es ligeramente diferente a lo que podría esperarse. Para copiar el archivo C:\MyDir\MyFile.zip se debe especificar cDestinationURL como "FILE:// C:\MyDir\MyFile.zip".

Cuando se llama a la función cCallbackFunction, la FLL crea dos (2) variables  (nConnectTotalBytes y nConnectBytesSoFar) dinámicamente. Estas variables pueden utilizarse con la función, procedimiento o método especificado para determinar el tamaño total en bytes del archivo fuente, así como el progreso total de la operación (Porcentaje = 100 * nConnectBytesSoFar / nConnectTotalBytes).


Function FTPToStr()

Sintaxis: FTPToStr(cSourceURL[, cCallbackFunction)

Parámetros:
cSourceURL - La ruta (directorio) completo y nombre del archivo que desea retornar como una cadena de texto.
cCallbackFunction - Una cadena opcional que indica una función, procedimiento o método que desea desencadenar cuando ocurra una lectura/escritura, algo como "MyCallback()".

Valor devuelto:
Caracter - el contenido del archivo especificado por cSourceURL

Comentarios:
Esta función le da la habilidad para recuperar una archivo desde un sitio FTP como una cadena de texto.

Para especificar el puerto o información de ingreso, simplemente debe incluirla en cSourceURL, como por ejemplo:

"FTP://myusername:mypassword@myftpsite.com:21/mydir/myfile.zip".
Cuando se llama a la función cCallbackFunction, la FLL crea dos (2) variables  (nConnectTotalBytes y nConnectBytesSoFar) dinámicamente. Estas variables pueden utilizarse con la función, procedimiento o método especificado para determinar el tamaño total en bytes del archivo fuente, así como el progreso total de la operación (Porcentaje = 100 * nConnectBytesSoFar / nConnectTotalBytes).


Function HTTPToStr()

Sintaxis: HTTPToStr(cSourceURL[, cCallbackFunction)

Parámetros:
cSourceURL - La ruta (directorio) completo y nombre del archivo que desea copiar.
cCallbackFunction - Una cadena opcional que indica una función, procedimiento o método que desea desencadenar cuando ocurra una lectura/escritura, algo como "MyCallback()".

Valor devuelto:
Lógico - regresa .T. si tiene éxito o .F. si la operación ha fallado.

Comentarios:
Esta función le da la capacidad para recuperar una archivo desde un sitio Web como una cadena de texto.

Cuando se llama a la función cCallbackFunction, la FLL crea dos (2) variables  (nConnectTotalBytes y nConnectBytesSoFar) dinámicamente. Estas variables pueden utilizarse con la función, procedimiento o método especificado para determinar el tamaño total en bytes del archivo fuente, así como el progreso total de la operación (Porcentaje = 100 * nConnectBytesSoFar / nConnectTotalBytes).


15 de febrero de 2008

Conocer la IP de la conexión a Internet

Una función para saber la dirección IP de nuestra conexión a Internet.

Con esta función que descarga la página de inicio del sitio www.WhatIsMyIP.org podemos saber con que IP estamos conectados a Internet.

Esta función tiene dos opciones:

Opción 1: Con la nueva libreria My incluida en Sedna para VFP 9.0:
? IpInternet()

FUNCTION IpInternet()
  LOCAL My AS My
  My = NEWOBJECT("My","My.vcx")
  ERASE "IP.txt"
  IF 0 = My.Computer.Network.DownloadFile("http://www.whatismyip.org", "IP.txt")
    RETURN FILETOSTR("IP.txt")
  ELSE
    RETURN ""
  ENDIF
ENDPROC

Opción 2: Con la API de Windows (esta opción es válida para todas las versiones de Visual FoxPro):
? IpInternet()

FUNCTION IpInternet()
  DECLARE LONG URLDownloadToFile IN URLMON.DLL ;
    LONG, STRING, STRING, LONG, LONG
  ERASE "IP.txt"
  IF 0 = URLDownloadToFile(0, "http://www.whatismyip.org", "IP.txt", 0, 0)
    RETURN FILETOSTR("IP.txt")
  ELSE
    RETURN ""
  ENDIF
ENDPROC
En realidad ambas funciones realizan lo mismo, ya que el método My.Computer.Network.DownloadFile() de la clase My, en un "envoltorio" de la función URLDownloadToFile() de la API de Windows.

Opción 3: Con la libreria VFPConnection.FLL de Craig Boyd que la pueden descargar de aquí:
? IpInternet()

FUNCTION IpInternet()
  SET LIBRARY TO (LOCFILE("vfpconnection.fll","FLL")) ADDITIVE
  lcIP = HTTPToStr("http://www.whatismyip.org")
  RELEASE LIBRARY "vfpconnection.fll"
  RETURN lcIP
ENDPROC
La función HTTPToStr() no realiza lectura/escritura de disco, con lo cual se evita que la página descargada quede en la cache.

7 de febrero de 2008

El namespace My en Sedna

Introducción

El namespace My, igual al introducido en Visual Studio 2005, está ahora disponible en Sedna. Las clases My crean un envoltorio a algunas funciones SYS(), funciones de la API de Windows, y métodos y propiedades de Windows Script Host, haciendo que sean mas fáciles de entender y poder escribir menos líneas de código. Todo esto ayudado por IntelliSense incluido en el namespace My.

Un buen ejemplo de esto, es el método Play que ejecuta un archivo de audio, que de la forma tradicional, con la API de Windows debíamos declarar la función y luego ejecutarla:

declare integer sndPlaySound in WinMM.dll ;
  string lpszSoundName, integer uFlags

sndPlaySound('Ding.wav', 0)

Ahora con Sedna podemos escribir solamente:

My.Computer.Audio.Play('Ding.wav')

Esta nueva clase está muy bien documentada en el archivo de ayuda My.chm incluido en la descarga de Sedna. Obviamente esta ayuda está en inglés, por lo que este artículo intentará ser una breve ayuda para la comunidad de habla hispana.

¿Cómo empezar?

Una vez descargado e instalado el complemento Sedna (ver los artículos anteriores "Sedna disponible para descarga" y "Sedna ya esta oficialmente en VFPx"), se debe registrar My con IntelliSense ejecutando la aplicación My.app, que se encuentra en la carpeta Sedna\My en el directorio de instalación de Visual FoxPro 9.0.

En el editor de código escribimos LOCAL My AS y seleccionamos el tipo My de la lista de tipos como se muestra a continuación:



Automáticamente se completará con el siguiente código:



Ahora escribiendo My. aparecerá la lista de los cinco namespaces disponibles en My:



My.App

Este namespace proporciona métodos y propiedades de la aplicación.

Por ejemplo para ejecutar un archivo específico con la aplicación asociada, utilizamos el método Execute:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
lcArchivo = GETFILE('HTM')
My.App.Execute(lcArchivo)

My.App.Info contiene métodos y propiedades de una aplicación específica o de la aplicación actual.

El siguiente ejemplo muestra información de la aplicación VFP9.EXE utilizando el método GetApplicationInformation:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
lcArchivo = HOME() + 'vfp9.exe'
My.App.Info.GetApplicationInformation(lcArchivo)
MESSAGEBOX( ;
  My.App.Info.ProductName + CHR(13) + ;
  My.App.Info.Version + CHR(13) + ;
  My.App.Info.Copyright, ;
  64, My.App.Info.CompanyName )

My.Computer

Proporciona acceso a varios componentes de la computadora.

La propiedad ComputerName nos muestra el nombre de la computadora
? My.Computer.ComputerName

Con My.Computer.Audio podemos ejecutar los sonidos del sistema con el método PlaySystemSound, o ejecutar un archivo de sonido específico con el método Play:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
My.Computer.Audio.PlaySystemSound('Stop')
My.Computer.Audio.Play('C:\Windows\Media\Ringout.wav')

Con My.Computer.Time podemos tomar la fecha y hora local, su descripción, la fecha y hora GMT (Greenwich Mean Time), o convertir de Local a GMT y viceversa:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
? My.Computer.Clock.LocalTime
? My.Computer.Clock.TimeZoneDescription
? My.Computer.Clock.GMTTime
? My.Computer.Cloc? My.Computer.Clock.ConvertLocalToGMT(DATETIME())

Con MyComputer.FileSystem podemos tener acceso a los atributos y métodos del sistema de archivos:

Con My.Computer.FileSystem.SpecialDirectories obtenemos las rutas de las carpetas especiales del usuario actual:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
lcArchivo = HOME() + 'vfp9.exe'
WITH My.Computer.FileSystem.SpecialDirectories
  ? .Desktop      && Escritorio
  ? .Favorites    && Favoritos
  ? .MyDocuments  && Mis Documentos
  ? .NetHood      && Entorno de red
  ? .PrintHood    && Impresoras
  ? .Programs     && Programas
  ? .StartMenu    && Menú inicio
  ? .Temp         && Carpeta temporal
ENDWITH
Podemos copiar un archivo con el método CopyFile:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
lcFile = GETFILE()
lcCopy = ADDBS(JUSTPATH(lcFile)) + 'Copia de ' + JUSTFNAME(lcFile)
My.Computer.FileSystem.CopyFile(lcFile, lcCopy)
Podemos mover un archivo con el método MoveFile:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
lcFile = GETFILE()
lcCopy = ADDBS(JUSTPATH(lcFile)) + 'Copia de ' + JUSTFNAME(lcFile)
My.Computer.FileSystem.MoveFile(lcFile, lcCopy)
Podemos copiar una carpeta completa con el método CopyDirectory:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
lcDir = GETDIR()
lcDir = LEFT(lcDir, LEN(lcDir)-1)
lcCopy = 'C:\Copia de ejemplo'
My.Computer.FileSystem.CopyDirectory(lcDir, lcCopy)
Podemos mover una carpeta completa con el método MoveDirectory:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
lcDir = GETDIR()
lcDir = LEFT(lcDir, LEN(lcDir)-1)
lcCopy = 'C:\Copia de ejemplo'
My.Computer.FileSystem.MoveDirectory(lcDir, lcCopy)
Con el método GetFileInfo podemos acceder a distintas propiedades de un archivo especificado:
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
lcFile = GETFILE()
WITH My.Computer.FileSystem.GetFileInfo(lcFile)
  ? 'Nombre: ' + .NAME
  ? 'Carpeta: ' + .PATH
  ? 'Tipo: ' + .TYPE
  ? 'Tamaño: ' + TRANSFORM(.SIZE)
  ? 'Creado: ' + TRANSFORM(.DateCreated)
  ? 'Accedido: ' + TRANSFORM(.DateLastAccessed)
  ? 'Modificado: ' + TRANSFORM(.DateLastModified)
ENDWITH
Con el método GetDirectoryInfo podemos acceder a distintas propiedades de una carpeta especificada:
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
lcDir = GETDIR()
WITH My.Computer.FileSystem.GetDirectoryInfo(lcDir)
  ? 'Nombre: ' + .NAME
  ? 'Carpeta: ' + .PATH
  ? 'Archivos: ' + TRANSFORM(.Files.Count)
  ? 'Creado: ' + TRANSFORM(.DateCreated)
  ? 'Accedido: ' + TRANSFORM(.DateLastAccessed)
  ? 'Modificado: ' + TRANSFORM(.DateLastModified)
ENDWITH
Con el método GetDriveInfo podemos acceder a distintas propiedades de la unidad de disco especificada:
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
WITH My.Computer.FileSystem.GetDriveInfo("C")
? 'Unidad: ' + .DriveLetter
? 'Volumen: ' + .VolumeName
? 'Sistema: ' + .FileSystem
? 'Tamaño: ' + TRANSFORM(.TotalSize / 1024) + ' KB'
? 'Libre: ' + TRANSFORM(.FreeSpace / 1024) + ' KB'
? 'Nro.Serie: ' + RIGHT(TRANSFORM(.SerialNumber, '@0'),8)
ENDWITH
Con los métodos GetShortFileName y GetLongFileName podemos obtener el nombre corto de archivo (8.3), desde un nombre largo y viceversa respectivamente:
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
lcFile = GETFILE()
lcCorto = My.Computer.FileSystem.GetShortFileName(lcFile)
lcLargo = My.Computer.FileSystem.GetLongFileName(lcCorto)
? lcCorto
? lcLargo

My.Computer.Network nos proporciona las propiedades y métodos para tratar con redes:

Podemos descargar una página web con el método DownloadFile:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
IF 0 = My.Computer.Network.DownloadFile('http://www.portalfox.com/backend.php','My.xml')
  My.App.Execute('My.xml')
ELSE
  MESSAGEBOX('Error al descargar archivo,16,'Error'))
ENDIF
Podemos conectarnos a un recurso compartido con el método MapNetworkDrive:
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
My.Computer.Network.MapNetworkDrive('Z:','\\MiServidor\MiRecursoCompartido')
Y desconectarnos con el método RemoveNetworkDrive:
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
My.Computer.Network.RemoveNetworkDrive('Z:')

My.Computer.Printer nos proporciona información de las impresoras:

El método AvailablePrinters nos retorna una colección de objetos con todas las impresoras disponibles:
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
FOR EACH lo IN My.Computer.Printer.AvailablePrinters
  ? lo.PrinterName
ENDFOR
Las propiedades DefaultVFPPrinter y DefaultWindowsPrinter nos muestran las impresoras por omisión de Visual FoxPro y de Windows respectivamente:
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
? My.Computer.Printer.DefaultVFPPrinter
? My.Computer.Printer.DefaultWindowsPrinter
EL método PageSetup nos muestra el cuadro de diálogo de configuración de página:
My = NEWOBJECT('My', 'My.vcx')
IF My.Computer.Printer.PageSetup()
  REPORT FORM MiInforme TO PRINTER
ENDIF

My.Computer.Registry proporciona acceso al registro de Windows:

Podemos crear y leer un valor del registro de Windows con los métodos SetValue y GetValue:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
IF My.Computer.Registry.SetValue('HKEY_LOCAL_MACHINE\Software\PortalFox\Ejemplo', 'Version', '1.0.0')
  MESSAGEBOX(My.Computer.Registry.GetValue('HKEY_LOCAL_MACHINE\Software\PortalFox\Ejemplo','Version'),64,'Version')
ENDIF
Podemos borrar un valor o una clave completa del registro de Windows con los métodos DeleteKeyValue y DeleteKey:
LOCAL My AS My
MMy = NEWOBJECT('My', 'my.vcx')
*-- Borrar un valor de la clave
My.Computer.Registry.DeleteKeyValue('HKEY_LOCAL_MACHINE\Software\PortalFox\Ejemplo', 'Version')
*-- Borrar la clave completa
My.Computer.Registry.DeleteKey('HKEY_LOCAL_MACHINE\Software\PortalFox\Ejemplo')
Podemos enumerar todas las claves bajo una clave específica con el método EnumetateKeys.
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
lo = My.Computer.Registry.EnumerateKeys('HKEY_LOCAL_MACHINE\Software\Microsoft\Windows')
FOR EACH lc IN lo
  ? lc
NEXT
Podemos enumerar todas los valores de una clave específica con el método EnumetateValueKeys.
LOCAL My AS My
My = NEWOBJECT('My', 'My.vcx')
lo = My.Computer.Registry.EnumerateKeyValues('HKEY_LOCAL_MACHINE\Software\Microsoft\VisualFoxPro\9.0\Registration')
FOR ln = 1 TO lo.Count
  ? lo.GetKey(ln) + ' = ' + lo.Item(ln)
NEXT

My.Data

Proporciona características para el manejo de datos.

El método CloseAllInstances cierra todas las copias abiertas de una tabla pasada como parámetro en todas las sesiones de datos. Esto es útil si se necesita acceso exclusivo a la tabla, como por ejemplo para modificar su estructura.
 LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
My.Data.CloseAllInstances('MiTabla')
USE MiTabla EXCLUSIVE
El método OpenCursorSnapshot toma una instantánea de todos los cursores abiertos, de manera que luego el método CloseOpenedCursors solo cierra los cursores abiertos entre la llamada de ambos métodos.
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
My.Data.OpenCursorSnapshot()
USE MiVista1 IN 0
USE MiVista2 IN 0
&& ...
My.Data.CloseOpenedCursors()
El método Goto realiza un GOTO seguro, que nos asegura que el puntero ira al registro especificado, y si el número de registro no es válido, el puntero de registro se posicionará al final del archivo EOF().
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
USE MiTabla
My.Data.GoTo(99)

My.Settings

Proporciona configuraciones específicas para nuestras aplicaciones. Estas configuraciones se guardan en un archivo .XML con un esquema igual que los archivos de configuraciones de .NET. Cuando una configuración se carga con el método Load, o se agrega con el método Add; se convierte en una propiedad dinámica del objeto My, y se puede hacer referencia a esta propiedad como es muestra a continuación:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
My.Settings.Add('DirApp',FULLPATH(''))
? My.Settings.DirApp
Advierta que IntelliSense no esta disponible para las propiedades dinámicas, ya que estas se crean en tiempo de ejecución.

El namespace My.Setting contiene cuatro métodos que nos permiten agregar configuraciones, grabar configuraciones en un archivo, comprobar su existencia y cargar las configuraciones desde un archivo.

En el siguiente ejemplo, vamos a grabar/cargar la última posición y tamaño de un formulario cuando éste fue cerrado. Ejecute el fragmento de código de abajo, cambie la posición y tamaño del formulario, ciérrelo, y vuelva a ejecutar el código.
PUBLIC goForm AS MiForm
goForm = NEWOBJECT('MiForm')
goForm.SHOW(1)
RETURN

DEFINE CLASS MiForm AS FORM
  CAPTION = 'Mueva y cambie el tamaño del formulario'
  My = NULL
  PROCEDURE Init
    THIS.My =  NEWOBJECT('My', 'my.vcx')
    WITH THIS.My
      IF FILE(FULLPATH('MiConfig.xml'))
        .Settings.Load(FULLPATH('MiConfig.xml'))
      ENDIF
      IF .Settings.EXISTS('FormTop')
        THIS.TOP    = .Settings.FormTop
        THIS.LEFT   = .Settings.FormLeft
        THIS.HEIGHT = .Settings.FormHeight
        THIS.WIDTH  = .Settings.FormWidth
      ENDIF
    ENDWITH
  ENDPROC
  PROCEDURE Destroy
    WITH THIS.My
      .Settings.Add('FormTop', THIS.TOP)
      .Settings.Add('FormLeft', THIS.LEFT)
      .Settings.Add('FormHeight', THIS.HEIGHT)
      .Settings.Add('FormWidth', THIS.WIDTH)
      .Settings.Save(FULLPATH('MiConfig.xml'))
    ENDWITH
  ENDPROC
ENDDEFINE

My.User

Proporciona información del usuario actual con las siguientes propiedades:
LOCAL My AS My
My = NEWOBJECT('My', 'my.vcx')
? My.User.DisplayName
? My.User.UserDomain
? My.User.UserName

Para tener en cuenta

Si usa My en una aplicación, asegúrese de incluir My.vcx y My.dbf en su proyecto. Se recomienda marcar como incluida a la tabla My.dbf para que también queden incluidos los archivos My.cdx y My.fpt. Si usa el namespace My.Settings asegúrese de distribuir el archivo de configuración .XML.

Ninguna de las clases My tienen código en su método Error, con lo cual si ocurre un error en un método de My, lo atrapará el controlador de error global de su aplicación, a menos que encierre las llamadas a los métodos de My entre una estructura TRY ... CATCH ... ENDTRY.

Mejorar My

El acuerdo de licencia incluido en la descarga de Sedna, nos permite la distribución y la modificación del código fuente incluido para todos los componentes de Sedna. Nosotros podemos añadir mas funcionalidad a My, como así también crear nuestros propios namespaces o subclasear la clase My.
El Equipo Visual FoxPro de Microsoft lanzó el complemento Sedna como un proyecto de código compartido en VFPx. Este se dividió en 6 proyectos distintos. Para el caso de la librería My, la podemos encontrar en "My for VFP". Allí todos podemos colaborar para mejorar Sedna, como así también todas las clases disponibles en VFPx o VFPy. Quedan todos invitados a participar.

Hasta la próxima.

Luis María Guayán