22 de febrero de 2020

Instalar versiones nuevas de ejecutables de VFP

Instalar versiones nuevas de ejecutables de VFP.

Autor: Mike Lewis
Texto original:
-- Installing new copies of VFP executables --
http://www.ml-consult.co.uk/foxst-30.htm
Traducido por: Ana María Bisbé York


¿Cómo instalar el archivo EXE actualizado sin forzar a los usuarios a cerrar su aplicación?

¿Alguna vez ha necesitado instalar una copia nueva de un archivo .EXE después que la aplicación empezó a funcionar? Si le ha ocurrido, sabrá que no puede simplemente copiar el nuevo archivo sobre el existente. Si trata de hacerlo mientras los usuarios están corriendo la aplicación, Windows reportará “Violación de archivos compartidos”. Su única solución es esperar a que todos hayan finalizado su sesión, lo cual puede ser inconveniente.

Andew Connor, el IT Manager en Mids & Horsey Ltd en el Reino Unido, ha llegado a una simple solución a este problema. Andrew sugiere que suministre un pequeño lanzador de programa el que busca el EXE con la versión más reciente. Una vez encontrado, toma el control del fichero que hasta ahora ejecuta la aplicación.

El programa lanzador es un sencillo programa de VFP. Es completamente genérico, no necesita saber el nombre del archivo EXE o del directorio que lo contiene. Sin embargo, es necesario seguir normas sencillas para nombrar los archivos.

Nombrar los archivos

El programa lanzador debe ser compilado a un archivo EXE, su nombre debe ser igual al de la aplicación principal. Este es el archivo que los usuarios van a lanzar cuando deseen correr la aplicación.

El nombre del archivo EXE actual de la aplicación debe contener además dos dígitos numéricos para la versión. Es decir, si la aplicación se llama Ventas, el programa lanzador se llamará Ventas.EXE. El archivo EXE principal de la aplicación puede llamarse entonces Ventas01.EXE, Ventas02.EXE, y así sucesivamente. Cada vez que desee distribuir una nueva versión del EXE principal, solo necesita cambiar el número de la versión.

Sus números de versión pueden ser cualquiera que decida, no es necesario que sean consecutivos o en orden ascendente. Pero deben tener exactamente dos dígitos.

Asegúrese de colocar el lanzador en el mismo directorio que el archivo ejecutable principal. Luego configúrelo para que los usuarios ejecuten el lanzador cuando deseen correr la aplicación.

El código

Aquí está el código para el programa lanzador. Puede pegarlo en un archivo de programa PRG y luego compilarlo y generar un .EXE

* Programa Lanzador (genérico).
LOCAL lcExecPath, lcFileName, lcSkeleton, lnFileCount
LOCAL lcExe, ltLatest, lnI
LOCAL ARRAY laFiles(1)
* Toma la ruta del directorio del archivo ejecutable
lcExecPath = JUSTPATH(SYS(16))
* Establece este directorio como predeterminado (Default)
SET DEFAULT TO (lcExecPath)
* Toma la raíz del nombre del archivo ejecutable
lcFileName = JUSTSTEM(SYS(16))
* Crea una matriz con los nombres de los EXEs posibles
lcSkeleton = lcFileName+"??.EXE"
&& lcSkeleton es un archivo comodín
&& para ADIR()
lnFileCount = ADIR(laFiles,lcSkeleton)
* Busca el archive EXE más reciente
lcEXE = ""
ltLatest = {}
FOR lnI = 1 TO lnFileCount
  IF FDATE(laFiles(lnI,1),1) > ltLatest
    ltLatest = FDATE(laFiles(lnI,1),1)
    lcExe = laFiles(lnI,1)
  ENDIF
ENDFOR
* Lanza la ejecución del EXE más reciente.
IF NOT EMPTY(lcExe)
  DO (lcEXE)
ENDIF

Como puede ver, el programa lanzador crea un arreglo que contiene los nombres de todos los archivos EXE que cumplan con la convención de nombre. Luego toma el control del más reciente de estos archivos.

Actualizar la aplicación

A partir de ahora, cuanto desee distribuir una nueva versión de su aplicación, puede copiar el EXE actualizado dentro del directorio donde están los ejecutables. Esto se puede hacer incluso si hay usuarios trabajando en la aplicación debido a que tendrá diferente número de versión que el archivo existente. La próxima vez que el usuario llame la aplicación, el lanzador encontrará automáticamente la versión correcta. En caso necesario, puede borrar la versión anterior.

Mike Lewis Consultants Ltd. Mayo 2003

18 de febrero de 2020

Obtener configuracion regional mediante API

Rutina para obtener la configuracion regional de Windows mediante API.

DIMENSION aDatos(1)
? GetConfiRegi( @aDatos )
DISPLAY MEMORY LIKE aDatos

*-------------------------------------------------------
* Retorna en una array pasado por referencia, algunos
* valores de la configuración regional
* PARAMETROS: aDatos
* USO:  DIMENSION aDatos(1)
*       GetConfiRegi( @aDatos )
* DEVUELVE: aDatos(1) = Símbolo decimal
*    aDatos(2) = Símbolo separador de miles
*    aDatos(3) = Número de dígitos decimales
*    aDatos(4) = Símbolo de signo negativo
*    aDatos(5) = Formato de números negativos
*-------------------------------------------------------
FUNCTION GetConfiRegi(aDatos)
  #DEFINE LOCALE_USER_DEFAULT  0x400 && 1024
  #DEFINE LOCALE_SDECIMAL  0xE
  #DEFINE LOCALE_STHOUSAND  0xF
  #DEFINE LOCALE_IDIGITS 0x11
  #DEFINE LOCALE_SNEGATIVESIGN  0x51
  #DEFINE LOCALE_INEGNUMBER  0x1010
  LOCAL sRetval AS STRING, nRET AS LONG
  IF PCOUNT() < 1 THEN
    RETURN .F.
  ENDIF
  DECLARE LONG GetLocaleInfo IN WIN32API  LONG LOCALE, ;
    LONG LCTYPE, STRING LPLCDATA, LONG CCHDATA
  DIMENSION aDatos(5)
  FOR nRET = 1 TO 5
    m.aDatos(nRET) = ""
  NEXT
  m.sRetval = REPLICATE(CHR(0),256)
  * Símbolo decimal
  m.nRET = GetLocaleInfo(LOCALE_USER_DEFAULT, ;
    LOCALE_SDECIMAL, @sRetval, LEN(m.sRetval))
  IF m.nRET > 0 THEN
    m.aDatos(1) = LEFT(m.sRetval,m.nRET-1)
  ENDIF
  m.sRetval = REPLICATE(CHR(0),256)
  * Símbolo separador de miles
  m.nRET = GetLocaleInfo(LOCALE_USER_DEFAULT, ;
    LOCALE_STHOUSAND, @sRetval,LEN(m.sRetval))
  IF m.nRET > 0 THEN
    m.aDatos(2) = LEFT(m.sRetval,m.nRET-1)
  ENDIF
  m.sRetval = REPLICATE(CHR(0),256)
  * Número de dígitos decimales
  m.nRET = GetLocaleInfo(LOCALE_USER_DEFAULT, ;
    LOCALE_IDIGITS, @sRetval,LEN(m.sRetval))
  IF m.nRET > 0 THEN
    m.aDatos(3) = LEFT(m.sRetval,m.nRET-1)
  ENDIF
  m.sRetval = REPLICATE(CHR(0),256)
  * Símbolo de signo negativo
  m.nRET = GetLocaleInfo(LOCALE_USER_DEFAULT, ;
    LOCALE_SNEGATIVESIGN, @sRetval,LEN(m.sRetval))
  IF m.nRET > 0 THEN
    m.aDatos(4) = LEFT(m.sRetval,m.nRET-1)
  ENDIF
  m.sRetval = REPLICATE(CHR(0),256)
  * Formato de números negativos
  m.nRET = GetLocaleInfo(LOCALE_USER_DEFAULT, ;
    LOCALE_SNEGATIVESIGN, @sRetval,LEN(m.sRetval))
  IF m.nRET > 0 THEN
    m.aDatos(5) = LEFT(m.sRetval,m.nRET-1)
    DO CASE
      CASE m.aDatos(5) = "0"
        m.aDatos(5) = "(1.1)"
      CASE m.aDatos(5) = "1"
        m.aDatos(5)= " -1.1"
      CASE m.aDatos(5) = "2"
        m.aDatos(5) = "- 1.1"
      CASE m.aDatos(5) = "3"
        m.aDatos(5) = "1.1-"
      CASE m.aDatos(5) = "4"
        m.aDatos(5) = "1.1 -"
    ENDCASE
  ENDIF
ENDFUNC
*-------------------------------------------------------