29 de junio de 2016

Utilizar FileMon

Artículo original: Using FileMon 
http://www.foxpert.com/knowlbits_200703_1.htm
Autor: Christof Wollenhaupt
Traducido por: Ana María Bisbé York


FileMon es una gran utilidad si necesita depurar problemas de rendimiento en una aplicación Visual FoxPro. Luego de lanzar FileMon.EXE como un administrador, cambie el filtro a "VFP9.EXE" o al nombre de su aplicación. Ahora, cuando ejecuta su aplicación, puede ver toda la actividad del disco en su aplicación.

Uno de los patrones principales a observar es una larga lista de accesos de lectura en un único archivo DBF. Estos son usualmente búsquedas de tabla que son el resultado de consultas no optimizadas o uso frecuente de agregados como calcular sumas o contar. Cuando verifica en una máquina local, raramente encontrará demora en estas operaciones ya que su disco duro es suficientemente rápido como para leer docenas de MB en apenas un segundo. En una red compartida, sin embargo, el ancho de banda es realmente crítico.

FileMon es muy bueno ya que dice qué es lo que está mal. Sin embargo, no ayuda a relacionarlo con la línea real de código. Para lograr esto, empleé marcadores en mi aplicación Visual FoxPro. Un marcador tiene la siguiente apariencia.

=FILE("MyClass.MyMethod.BeforeScan")

Es decir, yo verifico la existencia de un archivo no existente. En FileMon esta línea produce una salida similar a la siguiente:

11:14:08.182 vfp9.exe:2776 FASTIO_QUERY_OPEN
C:\DOCUMENTS AND SETTINGS\CHRISTOF\MY
DOCUMENTS\PROJECTS\lib\MyClass.MyMethod.BeforeScan
FILE NOT FOUND Attributes: Error

Ahora yo puedo buscar mis marcadores en FileMon. Puedo confiar que todas las actividades entre dos marcadores han sido causadas por el código que hay entre los dos marcadores. Al agregar y mover marcadores puedo identificar rápidamente las líneas que provocan mayor tráfico en una aplicación.

26 de junio de 2016

Añadir codigo a un evento en tiempo de ejecucion

Esto lo pense porque en el Grupo de Noticias de Visual FoxPro vi que muchos usuarios de nuestro amado Fox agregan objetos nuevos en tiempo de ejecucion pero desean tambien agregar codigo nuevo o personalizado a ese nuevo objeto y todo en tiempo de ejecucion.

Tienen que hacer lo siguiente: lo primero es crear una clase con el objeto al que quieran añadir codigo en tiempo de ejecucion, debe crear una propiedad con el nombre pc_shpname (o el que gusten). Yo uso este porque es un ejemplo sencillo para agregar codigo a un control Shape en el método Click.

Y en el método Click (o en el que necesiten) agregan este codigo:

SELECT tbremito
LOCATE FOR sname == this.pc_shpname
DO (scodigo)

En el Load (preferentemente) del formulario o prg donde estan trabajando hacer lo siguiente:

Crear un cursor tbremito, con los campos sname n(5), scodigo c(100)

lcx = 1
lCuenta = 0
** esta es una tabla mia ... es para ser claro con el ejemplo 
SELECT emn_oilcod   
SCAN ALL
  ** agregan el objeto, shape_ es el objeto instanciado en un clase ...
  lcmacro1 = "thisformset.frm_estadoInsumos.AddObject('Shape"+ALLTRIM(STR(lcx))+"','shape_')"  
  ** a la propiedad le agrego lcx para despues buscarla desde la clase &lcmacro1
  INSERT INTO tbremito (sname,scodigo) VALUES ((lcx),"sprshp"+ALLTRIM(STR(lcx)))
    lcmacrox1="thisformset.frm_estadoInsumos.shape"+ALLTRIM(STR(lcx))+".pc_shpname=lcx" 
  &lcmacrox1

  ***** aca agregan el codigo que necesitan ******
  lcfile2="sprshp"+ALLTRIM(STR(lcx))+".prg"
  SET TEXTMERGE ON
  SET TEXTMERGE TO (lcfile2) NOSHOW
  \wait windows '<<"shape"+ALLTRIM(STR(lcx))>>'
  SET TEXTMERGE OFF
  SET TEXTMERGE TO
  COMPILE (lcfile2)  
  ************ fin ***************
lcx = lcx + 1
lCuenta = lCuenta + 1
ENDSCAN

Tan simple como eso...!!! En este caso uso macrosusticion porque ahora mismo no se me ocurre otra forma pero si la encuentran.. usenlan!!

Bueno espero que la disfruten... todos los comentarios para mejorar son bienvenidos.

Saludos

Carlos Emilio

22 de junio de 2016

Tipo de dato VarChar en VFP9

La última versión de Visual FoxPro (VFP9) incluye tres tipos de datos nuevos: VarBinary, VarChar y Blob. Este artículo comenta alguna de las peculiaridades del nuevo dato VarChar.

*---------------------------------------------------------
* Método:
*  DATOVARCHAR.PRG
* Programador:
*  Ana María Bisbé York
* Fecha de Terminación:
*  07/02/05 11:09:49 AM
* Comentarios:
*       Este ejemplo fue mostrado en el IV Encuentro de Desarrolladores realizado por
*   Danysoft Internacional www.danysoft.com en Febrero 2005 en Microsoft Ibérica.
*  en la sesión Novedades de Visual FoxPro 9.0
*
*  En VFP 9.0 uno de los nuevos tipos de datos es VARCHAR, que contiene valores de caracteres
*  Se incluye por compatibilidad con SQL Server donde ya existe.
*  Es un dato de caracteres; pero en el que no hay los espacios en blanco sobrantes.
*  Se puede emplear en tablas nativas; pero no tiene compatibilidad hacia atrás.
*  Como los campos de tipo carácter, se pueden emplear en índices y su límite es 254 caracteres
*   Acepta valores nulos
*  Las funciones TYPE() y VARTYPE() devuelven "C"
*  DISPLAY/LIST STRU y AFIELDS() devuelven "V".
*  Cuando se combinan C+V = V
*  En los cuadros de textos, de forma predeterminada el valor incluye los espacios sobrantes
*  Si colocamos Format = F no los incluirá.
*
*  El siguiente código tiene como objetivo mostrar algunos aspectos relacionados:
*
*   Este código crea un cursor con dos campos cCampo de caracteres y vCampo tipo VarChar
*   Muestra el valor que devuelven las funciones VARTYPE() y LEN()
*   Muestra el resultado de realizar combinaciones con campos de caracteres
*---------------------------------------------------------
LOCAL lnCampos AS NUMBER, lnLongitudCombinacion AS NUMBER
STORE 0 TO lnCampos, lnLongitudCombinacion
CLEAR

CREATE CURSOR curVarChar(cCampo C(20), vCampo V(20))
INSERT INTO curVarChar VALUES ('Contenido campo Car', 'VarChar')
INSERT INTO curVarChar VALUES ('Campo caracteres', 'VarChar    ')
BROWSE

GO TOP
? ''
? 'Longitud de los campos'
? LEN(CCampo), LEN(VCampo)                    && Muestra 20 y 7
SKIP
? LEN(CCampo), LEN(VCampo)                    && Muestra 20 y 11

* LAs funciones TYPE y VARTYPE devuelven C
? ''
? 'VarType = ' + VARTYPE(VCampo)              && Muestra VarType = C

* La función AFIELDS devuelve V
lnCampos = AFIELDS(aCampos,'curVarChar')
? ''
? 'aCampos(2,2) = ' + aCampos(2,2)            && Muestra aCampos(2,2)= V

* Combinación C + V = V
lnLongitudCombinacion = LEN(CCampo + VCampo)
? ''
? 'Longitud combinación '+ STR(lnLongitudCombinacion) && Muestra 31 que son 20+11

Saludos,

Ana María Bisbé York

19 de junio de 2016

Tipo de dato VarBinary en VFP9

La última versión de Visual FoxPro (VFP9) incluye tres tipos de datos nuevos: VarBinary, VarChar y Blob. Este artículo comenta alguna de las peculiaridades del tipo de dato VarBinary.

*---------------------------------------------------------
* Método:
*  DATOVARBINARY.PRG
* Programador:
*  Ana María Bisbé York
* Fecha de Terminación:
*  07/02/05 10:39:59 AM
* Comentarios:
*       Este ejemplo fue mostrado en el IV Encuentro de Desarrolladores realizado por
*   Danysoft Internacional www.danysoft.com en Febrero 2005 en Microsoft Ibérica.
*  en la sesión Novedades de Visual FoxPro 9.0
*
*  En VFP 9.0 uno de los nuevos tipos de datos es VARBINARY, que contiene valores binarios
*   Se incluye por compatibilidad; pero se puede utilizar para valores binarios en tablas nativas VFP.
*   Su longitud no coincide con la del campo, sino con la del dato que es almacenado.
*  El valor se guarda como 0h y luego una serie de valores hexadecimales, no se guarda entre comillas
*  Se puede emplear en índices, acepta NULL y su longitud máxima es 254 caracteres.
*  Solo admite MACHINE como secuencia Collate para índices sobre campos Varbinary.
*  No se puede emplear en SQL LIKE, LIKE(), LIKE(), BINTOC(), CTOBIN().
*  Se puede buscar SEEK() por la representación binaria o de caracteres del dato.
*  TYPE() y VARTYPE() devuelven "Q" 
*  La combinación C + Q = C; pero Q + C = Q, depende del primero en la expresión 
*  Las comparaciones entre Q y C ó V depende del orden de los valores
*  Para los cuadros de textos se cumple Format = F, además Format = H para evitar que
*               se introduzcan datos no binarios. 
*
*  El siguiente código tiene como objetivo mostrar algunos aspectos relacionados:
*
*   Este código crea un cursor con un único campo VarBinary al que llamamos qCampo
*   Llenamos el campo con 0h466F78 que es el dato correspondiente a Fox 
*   Muestra el valor que devuelven las funciones VARTYPE() y LEN()
*   Muestra el resultado de realizar combinaciones con campos de caracteres
*   Muestra el resultado de comparaciones.
*---------------------------------------------------------
CLEAR
CREATE CURSOR curVarBinary (qCampo Q(20))
INSERT INTO curVarBinary VALUES (0h466F78) && Se corresponde con la cadena Fox
BROWSE
? 'Vartype devuelve ' + VARTYPE(qCampo)    && Muestra Vartype devuelve Q
? 'Len devuelve '+ STR(LEN(qCampo))        && Muestra Len devuelve 3
? 'qCampo devuelve ' + qCampo              && Muestra qCampo devuelve Fox

* Combinación C + Q = C
? ''
? 'Combinación C + Q = C'
? 'Me gusta mucho programar en ' + qCampo  && Muestra Me gusta programar en Fox

* Combinación Q + C = Q
? ''
? 'Combinación Q + C = Q'
? qCampo + '.NET dos herramientas para desarrollar aplicaciones'
* Devuelve 0h466F782E4E455420646F732068657272616D69656E7461732070617261206465736172726F6C6C61722061706C69636163696F6E6573

* Para convertir un tipo de dato en otro, a pesar de que no hay una función nativa,
* se realiza de la siguiente forma: concatenando con una cadena de caracteres vacía
? ''
? 'Convierto cadena hexadecimal en caracteres'
? ''+ 0h466F78      && Muestra Fox

* Comparaciones
? ''
? 'Comparo: qCampo = "Fox"'
? qCampo = 'Fox'    && Muestra .T.

? ''
? 'Comparo: qCampo = "Fox "'
? qCampo = 'Fox '   && Muestra .F.

Saludos,

Ana María Bisbé York

14 de junio de 2016

Buscar y Reemplazar en un documento Word

Ejemplo de buscar y reemplazar en un documento Word

wordFindAndreplace("foxpro","FoxPro","c:\informe.doc")

FUNCTION wordFindAndReplace
  LPARAMETERS cValueTofind,cValueToreplace,cDocument
  LOCAL lValue
  oWord = CREATEOBJECT("word.application")
  oDocument = oWord.Documents.OPEN(cDocument)
  loSelection = oWord.SELECTION
  WITH loSelection.FIND
    .TEXT = cValueToFind
    .Forward = .T.
    .WRAP= 1
  ENDWITH
  DO WHILE .T.
    lValue = loSelection.FIND.Execute
    IF lValue
      loSelection.Cut
      loSelection.InsertBefore(cValueToReplace)
      loselection.MoveRight
    ELSE
      EXIT
    ENDIF
  ENDDO
  oWord.VISIBLE =.T.
ENDFUNC

Mauricio Henao Romero

6 de junio de 2016

Como saber las aplicaciones abiertas mediante API

Como saber las aplicaciones abiertas mediante API.

#DEFINE GW_HWNDNEXT         2
#DEFINE GW_CHILD            5
#DEFINE GWL_STYLE           -16
#DEFINE WS_VISIBLE          0x10000000
#DEFINE WS_POPUP            0x80000000

DECLARE LONG GetWindow IN WIN32API LONG HWND, LONG uCmd
DECLARE LONG GetWindowText IN WIN32API LONG HWND, STRING @lpString, LONG nMaxCount
DECLARE INTEGER GetDesktopWindow IN Win32API
DECLARE LONG GetWindowLong IN WIN32API LONG HWND, LONG nIndex
DECLARE INTEGER IsIconic IN user32 INTEGER HWND
CREATE CURSOR crsWindows ( ;
  HWND I, WindTitle C(50),isIconic L)

lhWnd = GetDesktopWindow()
lhWnd = GetWindow(lhWnd, GW_CHILD)
DO WHILE lhWnd > 0
  m.WindTitle = GetTitle(lhWnd)
  IF NOT EMPTY(m.WindTitle)
    m.hwnd     = lhWnd
    m.Style = GetWindowLong(lhWnd, GWL_STYLE)
    m.hex     = TRANSFORM(m.Style, ";@0")
    m.isiconic = IIF(IsIconic(lhWnd)=0,.F.,.T.)
    IF  BITAND(m.Style, WS_VISIBLE) > 0 ;
        AND BITAND(m.Style, WS_POPUP) = 0
      INSERT INTO crsWindows FROM MEMVAR
    ENDIF
  ENDIF
  lhWnd = GetWindow(lhWnd, GW_HWNDNEXT )
ENDDO
SELECT crsWindows
LOCATE
BROWSE NOWAIT
RETURN

FUNCTION GetTitle(lhWnd)
  LOCAL lcTitle
  lcTitle = SPACE(512)
  lnTitle = GetWindowText(lhWnd , @lcTitle, 256)
  IF lnTitle > 0
    lcTitle = LEFT(lcTitle, lnTitle )
  ELSE
    lcTitle = ""
  ENDIF
  RETURN lcTitle
ENDFUNC

Mauricio Henao Romero

3 de junio de 2016

Medidor (gauge) 100% en VFP 9.0

Clase con un medidor circular (gauge) que grafica el porcentaje de un procedimiento con un objeto Shape y la nueva propiedad PolyPoint de Visual FoxPro 9.0.

El siguiente es el código 100% VFP9 para graficar un medidor circular. En el ejemplo se utiliza la imagen "lmGauge.gif" como fondo del medidor. Puede descargar la imagen, la clase y un formulario de ejemplo haciendo clic en el siguiente enlace: lmGauge.zip (14,9 KB)

Imagen del formulario de ejemplo conteniendo la clase lmGauge

PUBLIC goMiForm
goMiForm = CREATEOBJECT("MiForm")
goMiForm.SHOW(1)
RETURN

DEFINE CLASS MiForm AS FORM
  HEIGHT = 250
  WIDTH = 350
  AUTOCENTER = .T.
  CAPTION = "Gauge"
  NAME = "MiForm"
  ADD OBJECT Gauge1 AS lmGauge WITH ;
    TOP = 8, ;
    LEFT = 16, ;
    WIDTH = 220, ;
    NAME = "Gauge1"
  ADD OBJECT cmdGraficar AS COMMANDBUTTON WITH ;
    TOP = 8, ;
    LEFT = 248, ;
    HEIGHT = 32, ;
    WIDTH = 84, ;
    CAPTION = "Graficar", ;
    NAME = "cmdGraficar"
  ADD OBJECT cmdColor AS COMMANDBUTTON WITH ;
    TOP = 48, ;
    LEFT = 248, ;
    HEIGHT = 32, ;
    WIDTH = 84, ;
    CAPTION = "Color", ;
    NAME = "cmdColor"
  PROCEDURE cmdGraficar.CLICK
    LOCAL ln
    THISFORM.SETALL("Enabled",.F.,"CommandButton")
    *-- Simulo un proceso del 0 al 100%
    FOR ln = 0 TO 100
      THISFORM.Gauge1.Grafica(ln)
      INKEY(.001,"MH")
    ENDFOR
    THISFORM.SETALL("Enabled",.T.,"CommandButton")
  ENDPROC
  PROCEDURE cmdColor.CLICK
    THISFORM.Gauge1.shpGauge.BACKCOLOR = ;
      GETCOLOR(THISFORM.Gauge1.shpGauge.BACKCOLOR)
  ENDPROC
ENDDEFINE

DEFINE CLASS lmGauge AS CONTAINER
  WIDTH = 220
  HEIGHT = 220
  BACKSTYLE = 0
  BORDERWIDTH = 0
  NAME = "lmGauge"
  ADD OBJECT shpGauge AS SHAPE WITH ;
    TOP = 0, ;
    LEFT = 0, ;
    HEIGHT = 220, ;
    WIDTH = 220, ;
    BORDERWIDTH = 1, ;
    BACKCOLOR = RGB(255,255,255), ;
    POLYPOINTS = "This.aPoly", ;
    NAME = "shpGauge"
  ADD OBJECT lblGauge AS LABEL WITH ;
    AUTOSIZE = .T., ;
    FONTBOLD = .T., ;
    FONTNAME = "Arial", ;
    FONTSIZE = 9, ;
    ALIGNMENT = 2, ;
    BACKSTYLE = 0, ;
    CAPTION = "100%", ;
    HEIGHT = 20, ;
    LEFT = 90, ;
    TOP = 140, ;
    WIDTH = 32, ;
    NAME = "lblGauge"
  *-- debe existir el archivo grafico "lmGauge.gif"
  ADD OBJECT imgGauge AS IMAGE WITH ;
    PICTURE = "lmGauge.gif", ;
    STRETCH = 2, ;
    BACKSTYLE = 0, ;
    HEIGHT = 220, ;
    LEFT = 0, ;
    TOP = 0, ;
    WIDTH = 220, ;
    NAME = "imgGauge", ;
    VISIBLE = FILE("lmGauge.gif")
  PROCEDURE Grafica
    LPARAMETERS tnGauge
    LOCAL lnGauge, lnAng, lnCos, lnSen
    lnAng = 0
    lnCos = COS(DTOR(lnAng + 135))
    lnSen = SIN(DTOR(lnAng + 135))
    THIS.shpGauge.aPoly(2,1) = 50 * lnCos + 50
    THIS.shpGauge.aPoly(2,2) = 50 * lnSen + 50
    lnGauge = MAX(0,MIN(tnGauge,100)) * 0.1
    FOR lnI = 3 TO 30
      lnAng = (lnGauge) * (lnI - 3)
      lnCos = COS(DTOR(lnAng + 135))
      lnSen = SIN(DTOR(lnAng + 135))
      THIS.shpGauge.aPoly(lnI,1) = 50 * lnCos + 50
      THIS.shpGauge.aPoly(lnI,2) = 50 * lnSen + 50
    ENDFOR
    THIS.lblGauge.CAPTION = TRANSFORM(tnGauge,"999%")
    THIS.shpGauge.REFRESH
  ENDPROC
  PROCEDURE INIT
    THIS.Grafica(0)
  ENDPROC
  PROCEDURE shpGauge.INIT
    LOCAL lnI
    THIS.HEIGHT = THIS.PARENT.HEIGHT
    THIS.WIDTH = THIS.PARENT.WIDTH
    THIS.ADDPROPERTY("aPoly[30,2]")
    FOR lnI = 1 TO 30
      STORE 50 TO ;
        THIS.aPoly[lnI,1], ;
        THIS.aPoly[lnI,2]
    ENDFOR
  ENDPROC
  PROCEDURE lblGauge.INIT
    THIS.TOP = THIS.PARENT.HEIGHT * .75
    THIS.LEFT = (THIS.PARENT.WIDTH / 2) - (THIS.WIDTH / 2)
  ENDPROC
  PROCEDURE imgGauge.INIT
    THIS.HEIGHT = THIS.PARENT.HEIGHT
    THIS.WIDTH = THIS.PARENT.WIDTH
    THIS.STRETCH = 2
  ENDPROC
ENDDEFINE

Luis María Guayán