30 de octubre de 2015

Insertar una imagen en Excel

Desde VFP y con Automation, insertamos una imagen en Excel y le configuramos su tamaño.

LOCAL lcImagen, lcPlanilla, lo
*-- Selecciono imagen y nombre de planilla (xls)
lcImagen = GETPICT()
lcPlanilla = PUTFILE("Nombre","MiPlanilla","xls")
*-- Creo objeto Excel
lo = CREATEOBJECT("Excel.Application")
*-- Añado un libro nuevo
lo.Workbooks.Add
*-- Selecciono la celda donde estará la posición de la imagen
lo.Cells(3,3).Select
lo.ActiveSheet.Pictures.Insert(lcImagen).Select
lo.Selection.ShapeRange.LockAspectRatio = 0
lo.Selection.ShapeRange.Height = 320 && pixeles
lo.Selection.ShapeRange.Width = 240 && pixeles
*-- Guardo planilla
lo.ActiveWorkbook.SaveAs(lcPlanilla)
lo.Quit
lo = .Null.

Luis María Guayán

28 de octubre de 2015

MS-Excel Automation y OLEDB a través de Visual FoxPro

Una manera más de llevar registros hacia Excel, esta vez usando OLEDB. Cortesía de Çetin Basöz, MVP de VFP.

Local oRS as AdoDB.Recordset,oRS2 as AdoDB.Recordset,oCon as AdoDB.Connection
oCon = CreateObject('ADODB.connection')
oCon.ConnectionString = "Provider=VFPOLEDB;Data Source="+_samples+"data\testdata.dbc"
oCon.Open
oRS = oCon.Execute('select * from employee')
oRs.Save('disconnectme.rst')

oRS2 = CreateObject('ADODB.Recordset')
oRs2.Open('disconnectme.rst')

oExcel = Createobject('Excel.Application')
With oExcel
  .Workbooks.Add
  .Visible = .T.
  .ActiveWorkbook.ActiveSheet.QueryTables.Add( oRS2, .Range("A1")).Refresh
Endwith
Erase 'disconnectme.rst'

Nota del editor: Lo anterior no se limita a extracción de datos de Visual FoxPro, puede ser para cualquier otro manejador de base de datos del cual se tenga un OLEDB Provider instalado (MS-SQLServer, MySQL, PostgreSQL, Oracle, etc).

Çetin Basöz
MS Foxpro MVP, MCP

18 de octubre de 2015

Ventana de Word y Excel en primer plano

Si necesitamos poner una ventana de Microsoft Excel en primer plano mediante Automation podemos utilizar el siguiente código VFP:

lcXls = GETFILE("XLS")
IF NOT EMPTY(lcXls) AND FILE(lcXls)
  loExcel = CREATEOBJECT("Excel.Application")
  loExcel.Workbooks.OPEN(lcXls)
  loExcel.VISIBLE = .T.
  DECLARE LONG BringWindowToTop IN "user32" LONG HWND
  BringWindowToTop(loExcel.HWND)
ELSE
  MESSAGEBOX("El archivo " + lcXls + " no existe", 0+16, "Aviso")
ENDIF

Para el caso de Microsoft Word que no tiene la propiedad hWnd (window handle -identificador de ventana-), primeramente debemos buscar ese handle:

lcDoc = GETFILE("Doc")
IF NOT EMPTY(lcDoc) AND FILE(lcDoc)
  loWord = CREATEOBJECT("Word.Application")
  loWord.Documents.OPEN(lcDoc)
  loWord.VISIBLE = .T.
  lcCaption = loWord.ActiveDocument.ActiveWindow.Caption + [ - Microsoft Word]
 DECLARE integer FindWindow IN "user32" String, String
  lnHWnd = FindWindow(Null , lcCaption)
  DECLARE LONG BringWindowToTop IN "user32" LONG HWND
  BringWindowToTop(lnHWND)
ELSE
  MESSAGEBOX("El archivo " + lcDoc + " no existe", 0+16, "Aviso")
ENDIF

Luis Maria Guayan

13 de octubre de 2015

Ctrl+C para capturar Cuadros de Diálogos y MessageBox

Este es un "tip" que se mostró en la última Conferencia SouthWest Fox y es atribuido al inolvidable Drew Speedie.

La publicación original de este tip está en el Blog de Calvin Hsia:

-- Ctrl-C to capture MessageBox and dialogs --
http://blogs.msdn.com/calvin_hsia/archive/2005/10/16/481713.aspx

Por ejemplo, si en la ventana de comandos escribimos un comando que muestre un cuadro de diálogo de error, con Ctrl+C capturamos el contenido del diálogo en el portapapeles:

USE MiTablaQueNoExiste

Si copiamos el contenido del portapapeles (Ctrl+V) veremos:

Microsoft Visual FoxPro
Aceptar
Ayuda
El archivo 'c:\...\mitablaquenoexiste.dbf' no existe.

Otro intento es ejecutar el siguiente comando que no es válido:

_VFP.DoCmd("Examinar")

Y presionando Ctrl+C cuando aparece el cuadro de diálogo tendremos en el portapapeles:

Microsoft Visual FoxPro
Aceptar
Ayuda
Código de excepción OLE IDispatch 0 de Visual FoxPro para Windows: 16 :No se reconoce el verbo de comando..

También podemos copiar el contenido de un MessageBox, como por ejemplo:

MESSAGEBOX("Presione Ctrl+C para copiar el texto al portapapeles")

En el portapapeles tendremos:

---------------------------
Microsoft Visual FoxPro
---------------------------
Presione Ctrl+C para copiar el texto al portapapeles
---------------------------
Aceptar
---------------------------

10 de octubre de 2015

Use ASSERT en lugar de SET STEP ON

Es común para depurar problemas insertar un SET STEP ON antes de la porción de código con problemas, de esta manera puede ver lo que sucede en el Depurador.

Sin embargo, todos hemos experimentado el gran sentimiento de ser un verdadero profesional en nuestro arte cuando dejamos un SET STEP ON en el código de producción, sólo para tener nuestro fallo de la aplicación ("Caracteristica no disponible") durante una demostración o el producto final.

Algunos desarrolladores recurren a reemplazar el SET STEP ON puro por otro SET STEP ON diseñado para ser inofensivo en el código de producción. Un ejemplo es crear un archivo ficticio que sólo existe en la máquina local, quizás algo como este:

IF FILE("Debug.Txt") *** archivo ficticio no disponible en producción
  SET STEP ON
ENDIF

Aquí está una idea que es más sencilla. Sólo sustituya el SET STEP ON por ASSERT .F. (incluya la cláusula MESSAGE si quiere):

ASSERT .F.

Cuando VFP encuentra un ASSERT .F. (asumo que SET ASSERT es ON, algo que es típicamente verdadero durante el desarrollo), esto da el diálogo ASSERT con la posibilidad de [Depuración], con la cual nos lleva al depurador.

La gran ventaja consiste en que VFP "automáticamente" ignora los ASSERTs en el código de producción compilado en un .EXE y también en un .DLL, donde sería aún más desastroso dejar un SET STEP ON. Por supuesto, en el código de producción también generalmente se emite un SET ASSERTS OFF, obteniendo una protección adicional incluida en el código fuente distribuido como .APPs y .FXPs.

Como se demuestra ejecutando el siguiente PRG, también puede usar esta técnica donde tiene el código que espera un potencial problema y atrapa los errores conocidos. ASSERTS da la oportunidad al desarrollador para ir inmediatamente a la Depuración en vez sólo darse cuenta que el código no se ejecutó como se esperaba.

Advierta que en VFP 7.0 SET STEP ON es ignorado en un .APP, .EXE ó .DLL - ningún error "Caracteristica no disponible" será generado, de esta manera activando en VFP 7.0 SET STEP ON, este es omitido en una aplicación distribuida, de la misma forma que ASSERT .F.

*  
SET ASSERTS OFF
*  para producción
SET ASSERTS ON
*  para desarrollo
*
*  Aquí va código ...
*
LOCAL lnJunk 
lnJunk = 100
IF !OpenTable("AlgunaTablaQueNoExiste")
  MESSAGEBOX("No se puede abrir AlgunaTablaQueNoExiste",16, ;
    "Por favor informe este problema")
  RETURN .f.
ENDIF             
SELECT AlgunaTablaQueNoExiste
LOCATE FOR AlgunCampo = 100
*
*  etc.
*
RETURN
*
PROCEDURE OpenTable
*
*  pretendo que esto sea una utilidad separada
*
LPARAMETERS tcTable
LOCAL llError, lcOnError
lcOnError = ON("ERROR")
llError = .f.
ON ERROR llError = .t.
USE (tcTable) IN 0 SHARED
ON ERROR &lcOnError
IF llError
  *
  *  asigne la posibilidad al desarrollador de ir directamente
  *  a la escena del crimen, en vez de solo un mensaje al 
  *  usuario recibido en producción
  *
  ASSERT .F. MESSAGE "No se puede USAR " + tcTable
  *
  *  Recuerde que ASSERT es omitido en un .EXE, .DLL,
  *  y/o cuando SET ASSERTS OFF
  *
ENDIF
RETURN !llError

VFP Tips & Tricks - Drew Speedie

7 de octubre de 2015

Determinar el contenido del CLIPBOARD

Por medio de las API de Windows podemos determinar el tipo de objeto que contiene el Clipboard (BMP, TIFF, Texto, etc) . Cortesía de Çetin Basöz MVP de VFP.

*
* Predefined Clipboard Formats - winuser.h
* Formatos predefinidos en winuser.h
*
#define CF_TEXT             1 
#define CF_BITMAP           2 
#define CF_METAFILEPICT     3
#define CF_SYLK             4
#define CF_DIF              5
#define CF_TIFF             6
#define CF_OEMTEXT          7
#define CF_DIB              8
#define CF_PALETTE          9
#define CF_PENDATA          10
#define CF_RIFF             11
#define CF_WAVE             12
#define CF_UNICODETEXT      13
#define CF_ENHMETAFILE      14
#define CF_HDROP            15
#define CF_LOCALE           16
#define CF_MAX              17
#define CF_OWNERDISPLAY     0x0080
#define CF_DSPTEXT          0x0081
#define CF_DSPBITMAP        0x0082
#define CF_DSPMETAFILEPICT  0x0083
#define CF_DSPENHMETAFILE   0x008E

Declare short IsClipboardFormatAvailable in win32api integer cbformat
*** El contenido es una imagen BMP?
? ( IsClipboardFormatAvailable(CF_BITMAP) # 0 )

Çetin Basöz
MS Foxpro MVP, MCP

2 de octubre de 2015

Pantalla de bienvenida (splash screen)

El código de este ejemplo fue ligeramente modificado del Artículo 190350 de la Base de Conocimientos de Microsoft:

-- How To Create Top-Level Splash Screen with No TaskBar Icon --
--[Cómo crear una pantalla de nivel superior sin icono en la barra de tareas]--
https://support.microsoft.com/es-es/kb/190350

El siguiente código genera automaticamente el archivo ejecutable "C:\MiApp\MiApp.exe"

LOCAL lc
SET SAFETY OFF
*-- Creo una carpeta para MiApp
IF NOT DIRECTORY("C:\MiApp")
  MD "C:\MiApp"
ENDIF
*-- Creo el archivo MiApp.PRG
TEXT TO lc NOSHOW
*-- Inicio del programa MiApp.prg
LOCAL loPresenta, loPrincipal
loPresenta = NEWOBJECT("FormPresenta")
loPresenta.SHOW()
*-- Demora para mostrar el formulario Presenta
*-- En este lugar preparo mi aplicación,
*-- configuro lo necesario, etc.
FOR ln = 1 TO 30
  INKEY(.1)
ENDFOR
loPrincipal = NEWOBJECT("FormPrincipal")
loPrincipal.SHOW()
RELEASE loPresenta
loPresenta = NULL
READ EVENTS
loPrincipal = NULL
CLOSE ALL
CLEAR ALL
QUIT
*-- Formulario Presenta
DEFINE CLASS FormPresenta AS FORM
  ALWAYSONTOP = .T.
  AUTOCENTER = .T.
  WIDTH = 468
  HEIGHT = 319
  NAME = "Presenta"
  SHOWWINDOW = 2
  DESKTOP = .T.
  TITLEBAR = 0
  BORDERSTYLE = 1
  MOUSEPOINTER = 11
  ADD OBJECT imgLogo AS IMAGE WITH ;
    PICTURE = HOME(2)+"Tastrade\Bitmaps\splash.bmp", ;
    TOP = 0, ;
    LEFT = 0
  ADD OBJECT lblEspere AS LABEL WITH ;
    TOP = 250, ;
    LEFT = 10, ;
    CAPTION = "Espere un momento...", ;
    FONTSIZE = 14, ;
    FONTBOLD = .T., ;
    FONTNAME = "Arial", ;
    AUTOSIZE = .T., ;
    BACKSTYLE = 0
  PROCEDURE INIT
    SET CURSOR OFF
    THIS.SETALL("MOUSEPOINTER", THIS.MOUSEPOINTER)
  ENDPROC
  PROCEDURE DESTROY
    SET CURSOR ON
  ENDPROC
ENDDEFINE
*-- Formulario Principal
DEFINE CLASS FormPrincipal AS FORM
  CAPTION = "Formulario Principal"
  SHOWWINDOW = 2
  AUTOCENTER = .T.
  WIDTH = 640
  HEIGHT = 480
  ADD OBJECT cmdSalir AS BotonSalir WITH ;
    TOP = 10, ;
    LEFT = 500
  PROCEDURE DESTROY
    CLEAR EVENTS
  ENDPROC
ENDDEFINE
*-- Boton Salir
DEFINE CLASS BotonSalir AS COMMANDBUTTON
  HEIGHT = 30
  WIDTH = 130
  CAPTION = "Salir"
  PROCEDURE CLICK
    THISFORM.RELEASE
  ENDPROC
ENDDEFINE
*-- Fin de MiApp.prg
ENDTEXT
STRTOFILE(lc,"C:\MiApp\MiApp.prg")
*-- Creo el archivo Config.fpw
TEXT TO lc NOSHOW
SCREEN = OFF
RESOURCE = OFF
ENDTEXT
STRTOFILE(lc,"C:\MiApp\Config.fpw")
*-- Genero el PJX y EXE
BUILD PROJECT "C:\MiApp\MiApp.pjx" FROM "C:\MiApp\MiApp.prg", "C:\MiApp\Config.fpw"
BUILD EXE "C:\MiApp\MiApp.EXE" FROM "C:\MiApp\MiApp.pjx"
MESSAGEBOX("Ahora ejecute C:\MiApp\MiApp.EXE",64,"Aviso")

NOTA: Generado para VFP7, VFP8 y VFP9. En otras versiones puede no encontrarse el archivo de imagen utilizado.

Luis María Guayán