sábado, 31 de marzo de 2018

¿El final de Excel está cerca? Para nada.

Fue aproximadamente el año 2007 cuando empecé a escuchar los primero rumores, en redes, acerca de la desaparición de Microsoft Excel. Para muchas personas el cambio radical que hubo entre las versiones de Excel 2003 y Excel 2007 era ya de por sí un indicio a pesar de la ventaja que fue para muchos el incremento en el número de filas y columnas. Lo mismo se dijo del VBA pues Microsoft había anunciado ya años antes que la versión 6.3 (la de Excel 2003 y 2007) no sería renovada/actualizada es decir, sería la última. Un hecho que “alertó” más a los usuarios de Excel sobre lo que creían sería el final del Visual Basic For Application (VBA) y de forma posterior del Excel es que Microsoft decide no incluir VBA en la versión de su suite 2008 para Mac.

Otro hecho que no pasaba desapercibió para los usuarios de Excel y su VBA es la aparición de Visual Studio Tools For Office (VSTO) en el año 2003. Si bien desde Microsoft se comentaba que VSTO no había sido desarrollado como sustituto de VBA ,sino como un conjunto de herramientas de desarrollo disponibles en forma de complemento de Visual Studio que permiten crear aplicaciones de Office que se alojen en .NET Framework Common Language Runtime (CLR) para exponer su funcionalidad a través de .NET; para muchos el “marketing” aplicado por Microsoft sobre dicho paquete, era otro indicio de que VSTO era el reemplazo de VBA tal como Visual Basic Net lo fue de Visual Basic “clásico”.

A pesar de todo Office trajo la novedad, entre otras, de que la versión de VBA que incluía era la 7.1, es decir, a pesar del anuncio de años atrás, Microsoft había decidido renovar dicho entorno de programación. A esto se le sumó que la versión de Office 2011 para Mac volvió a incluir VBA.

Con los años Office ha ido incluyendo nuevas funciones y herramientas como Power Query, Power Pivot y Power Viewer que maximizan, por ejemplo, el trabajo con datos a través de Excel. Asimismo, se calcula que para el año 2017, a nivel mundial Excel contaba con entre 750 y 1000 millones de usuarios, lo que lo deja muy lejos de ser un programa que va camino al olvido. Es más, incluso a nivel de celulares/móviles se calcula que ese mismo año ya existían 120 millones de usuarios. Y si mencionamos los foros de Excel, definitivamente siguen siendo de los más visitados y activos que hay en el mundo virtual.

Bueno, después de todo esto yo considero que Excel no está ni medianamente cerca de su fin, así como tampoco el VBA tampoco; Microsoft, a pesar de los antiguos rumores, no parece estar interesado en desaparecer dicho programa, o no aún al menos. Solo un último comentario, si bien VSTO no debe ser visto como el reemplazo de VBA, si considero que podría usarse más y justamente ayudaría a que el desarrollo de aplicaciones de Excel con programación “protegida”, como siempre se expresan desean muchos, sea más distribuido.

Hasta la próxima.


Abraham Valencia

lunes, 26 de marzo de 2018

Exportando archivos Excel a PDF

A pesar que desde Office 2007 (como complemento en dicha versión), Microsoft ha incluido la posibilidad de exportar en formato PDF sus archivos, es una pregunta muy frecuente en los foros de Excel la forma en la cuál se puede hacer mediante macros (VBA). Quizá la lógica nos diga a algunos/as que bastaría obtener dicho código usando la grabadora de macros con lo que tendríamos algo así:

Sub Macro1() 
'
' Macro1 Macro
' 
'
ActiveSheet.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _       
  "C:\Users\Abraham\Desktop\Libro1.pdf", Quality:=xlQualityStandard, _
  IncludeDocProperties:=True, IgnorePrintAreas:=False, OpenAfterPublish:= _ 
  False 
End Sub 

Como se puede ver lo que se ha hecho es exportar la hoja activa (ActiveSheet) haciendo uso del método “ExportAsFixedFormat” y después vemos una serie de parámetros que la grabadora no nos explicará y que justamente ayudaremos a entender.

La web MSDN nos muestra la siguiente sintaxis para el método:

Expresión.ExportAsFixedFormat (Type, Filename, Quality, IncludeDocProperties, IgnorePrintAreas, From, To, OpenAfterPublish, FixedFormatExtClassPtr)

Para usar dicho método es obligatorio incluir la “Expresión” que puede ser cualquiera de estos tipos de objeto: Workbook , Sheet , Chart o Range. Entonces, podemos mandar a exportar en pdf el libro completo, hojas, gráficos e incluso solo un rango especifico. Ejemplos:

ActiveWorkbook.ExportAsFixedFormat Type:=xlTypePDF, Filename:= _ 
  "C:\Users\Abraham\Desktop\Libro1.pdf" 
Range("A1:C2").ExportAsFixedFormat Type:=xlTypePDF, Filename:= _
  "C:\Users\Abraham\Desktop\Libro1.pdf" 
Sheets("Hoja2").ExportAsFixedFormat Type:=xlTypePDF, Filename:= _      
  "C:\Users\Abraham\Desktop\Libro1.pdf" 

Los otros parámetros del método trabajan y/o se usan del siguiente modo:

Nombre

Descripción

Type

Es el parámetro que define el tipo de archivo en que se exportará. Puede ser de dos tipos: xlTypePDF (pdf)  o xlTypeXPS (xps). Su uso es obligatorio.

Filename

Es la cadena que indica la ruta y/o el nombre del archivo que se guardará. Su uso es opcional. De no llenarse por defecto se guarda en la misma carpeta que el archivo Excel y con el mismo nombre.

Quality

Es opcional. Define la calidad del archivo que se exportara, puede ser xlQualityStandard (normal) o xlQualityMinimum (mínima).

IncludeDocProperties

Establece si las propiedades del documento deben incluirse o no. Sus valores son True (para incluir) o False (no las incluye). Es opcional.

IgnorePrintAreas

Es opcional. Establece si se ignora las áreas de impresión establecidas al publicar. Puede ser True para dicho efecto o False para que use las áreas de impresión establecidas al momento de la publicación.

From

Establece el número de página desde donde se comenzará a publicar/exportar. Si se omite el parámetro, comienza desde la primera página. No confundir página con hoja.

To

Establece el número de la última página que se publicará/exportará. Si se omite el parámetro, se publica/exporta hasta la última página. No confundir página con hoja.

OpenAfterPublish

Establece si el archivo se abrirá después de ser publicado/exportado. Sus valores pueden ser True o False. Es opcional.

FixedFormatExtClassPtr

Es opcional. Representa un puntero de la clase personalizada en un complemento que implementa la interfaz IMsoDocExporter COM que permite llamadas a una implementación alternativa de código para el formato del documento. El valor predeterminado es un puntero nulo.

Siguiendo con los ejemplos, en éste solo se exporta a PDF desde la página 3 a la 6 de la “Hoja2”:

Sheets("Hoja2").ExportAsFixedFormat Type:=xlTypePDF, Filename:= _  
  "C:\Users\Abraham\Desktop\Libro1.pdf", From:= 3, To:= 6 

En este otro ejemplo, se exporta un rango en calidad “Standard” y se abre el documento posterior a ser exportado:

Range("A1:C2").ExportAsFixedFormat Type:=xlTypePDF, Filename:= _   
  "C:\Users\Abraham\Desktop\Libro1.pdf", Quality:= xlQualityStandard, OpenAfterPublish:=True 

No olvidemos que los valores de parámetros como “Filename”, “From”, “To”, etc., pueden ser tomados de celdas o desde variables sin ningún problema si los valores ha sido bien establecidos:

Sheets("Hoja2").ExportAsFixedFormat Type:=xlTypePDF, Filename:=  Range("C12").Value , From:= Range("R3").Value, To:= Range("R4").Value
Dim PrimeraPagina As Long, UltimaPagina As Long 
Dim RutayNombre as String
Let PrimeraPagina =  Range("R3").Value 
Let UltimaPagina =  Range("R4").Value 
Let RutayNombre= Range("C12").Value 
Sheets("Hoja2").ExportAsFixedFormat Type:=xlTypePDF, Filename:= RutayNombre, From:= PrimeraPagina, To:= UltimaPagina 

Y esas son algunas cosas que es importante concoer para exportar a PDF (o XPS) nuestros archivos de Excel.

Hasta la próxima.

Abraham Valencia

jueves, 22 de febrero de 2018

Las colecciones "Worksheets" y "Sheets"

En innumerables ocasiones, cuando de manejar las hojas de Excel como objetos en VBA se trata, he visto que se hace de manera indiferente tanto usando “Sheets” como usando “Worksheets” pero ¿son ambas lo mismo?

Según las definiciones que hay en el “Microsoft Developer Network” (MSDN), “Sheets” hace referencia a “la colección de hojas que puede contener objetos gráfico y hojas de trabajo” y “Worksheets” es “la colección que contiene todas las hojas de trabajo en un libro”.

Entonces:

- Worsheets: Solo hojas de trabajo (u hojas de cálculo como normalmente las llamamos u hojas a secas)

- Sheets: Hojas de trabajo y hojas tipo gráfico (no confundir con los gráficos insertados en hojas)

 

Para que se entienda mejor, vamos a suponer que tenemos un archivo con tres hojas así:

 

Entonces usamos esta macro muy simple:

Sub ContarHojas()
MsgBox Worksheets.Count
End Sub   
Cuando ejecutamos la macro el “Msgbox” nos dará un resultado de “3”. Ahora hagamos un pequeño cambio y el resultado será el mismo:
Sub ContarHojas()
MsgBox Sheets.Count
End Sub 

La colección “Worksheets” nos da como resultado “3” y el resultado es el mismo cuando usamos “Sheets” porque dicha colección contiene, también, a las hojas en cuestión. Veamos ahora que ocurre en este otro caso:

 

Si aplicamos las macros del ejemplo anterior, con “Worksheets.Count” tenemos como resultado “2” pero en esta ocasión con “Sheets.Count” tendremos como resultado “4”. “Sheets” considera todas las hojas del libro (4 en total) y “Worksheets” solo las “hojas de trabajo” (hojas de cálculo).

Pero ¿son estos los únicos tipos de hojas que trae Excel? Vamos a recordar una imagen que vimos líneas arriba:

 

Hay tres objetos ahí que nos interesan: Macro de Microsoft Excel 4.0, Hoja internacional de macros y el Dialogo de Excel 5.0. Las dos primeras son herencia de las macros de Excel 4.0 y el tercero es herencia de Excel 5.0. En los tres casos las versiones posteriores de Excel las mantienen por una cuestión de compatibilidad (evidentemente no con todas las características de sus versiones iniciales).

En el MSDN nos dicen que hay cinco tipos de hojas:

Nombre

Constante

Descripción

xlChart

-4109

Hoja de Gráfico

xlDialogSheet

-4116

Hoja de Dialogo

xlExcel4IntlMacroSheet

4

Hoja Internacional de Macros

xlExcel4MacroSheet

3

Hoja Macro de Microsoft Excel 4.0

xlWorksheet

-4167

Hoja de trabajo

(Enumeración XlSheetType)

Entonces, si en nuestro archivo tenemos algo como esto:

Al usar “Worksheets.Count” el resultado será “2” pero con “Sheets.Count” será “6”, ya que la colección “Sheets” considera a todas las hojas sin excepción. Si bien en la definición del MSDN sobre la colección “Sheets” habla solo de dos tipos de hojas, al parecer podría deberse a lo ya mencionado: Que los otros tipos se mantienen solo por compatibilidad y por eso han obviado mencionarlo (O por lo menos eso es lo que yo, y otras personas, creemos).

Algo muy importante sobre todo a tomar en cuenta si trabajamos con los índices de las hojas, es que cada colección tiene su propio índice. Con el ejemplo anterior si colocamos “Worksheets(2).Name” nos devolverá “Hoja2” pero si colocamos “Sheets(2).Name” nos dará como resultado “Macro1”.

Hasta la próxima.

Abraham Valencia

domingo, 4 de febrero de 2018

Microsoft Outlook desde Excel (I)

Muchas veces deseamos que nuestros trabajos en Excel, o en otros programas de Office incluso, se puedan enviar a través de nuestro correo electrónico. Podríamos decir que si tenemos dicho correo configurado en nuestro Microsoft Outlook no será muy difícil lograrlo.

A través de VBA podemos manejar desde Excel nuestro Microsoft Outlook como un objeto y así enviar mensajes adjuntando incluso archivos o nuestra firma digital, si es que la tenemos.

Lo primero que recomiendo hacer es activar la referencia respectiva en el editor de VBA:

En mi caso dice 15.0 por la versión de Office que tengo en la respectiva PC pero se debe activar la que a cada uno le corresponda.

Para continuar, lo que vamos a hacer ahora es crear un objeto “Outlook” y también usaremos el método “CreateItem” con el parámetro del tipo “olMailItem” que creará un nuevo mensaje (objeto “MailItem”):

Dim OutlookApp As Outlook.Application
Dim objItem As MailItem 

Set OutlookApp = CreateObject("Outlook.Application") 
Set objItem = OutlookApp.CreateItem(olMailItem)  
Tal y como cuando enviamos un mensaje desde nuestro correo o desde el propio Microsfot Outlook, el objeto creado tiene propiedades que representan los campos “Para”, “Asunto”, “Cuerpo”, etc:
With objItem 
 .To = "destinatario@ejemplo.com" 'Para
 .CC = "segundodestinatario@ejemplo.com" 'Con copia
 .Subject = "Prueba" 'Asunto
 .Body = "Este es un mensaje de prueba" 'Cuerpo 
End With 

Lo único que faltaría es que usemos el método “Send” para enviar el mensaje:

.Send 

Toda nuestra macro junta podría quedar así:

Sub EnviarMensajeOutlook()
Dim OutlookApp As Outlook.Application
Dim objItem As MailItem

Set OutlookApp = CreateObject("Outlook.Application") 
Set objItem = OutlookApp.CreateItem(olMailItem)  

With objItem 
 .To = "destinatario@ejemplo.com" 'Para
 .CC = "segundodestinatario@ejemplo.com" 'Con copia
 .Subject = "Prueba" 'Asunto
 .Body = "Este es un mensaje de prueba" 'Cuerpo 
 .Send
End With

Set OutlookApp = Nothing 
Set objItem = Nothing 

End Sub 

Si deseamos poder ir cambiando el correo de destino o el texto del cuerpo del mensaje o etc., sin tener que modificar la macro, podemos colocar los datos en celdas o variables:

With objItem
 .To = Range("A1").Value     
 .CC = Range("A2").Value     
 .Subject = Range("A3").Value     
 .Body = Range("A4").Value     
 .Send 
End With 

En este momento ya se deben de haber dado cuenta (o ya sabían) que el cuerpo del mensaje se envía sin formato y quizá lo que queremos es más bien que dicho mensaje tenga formato como ya estamos, casi todos, acostumbrados hoy en día cuando usamos el correo electronico. Para lograr eso ya no debemos usar la propiedad “Body” sino que ahora usaremos la propiedad “HTMLBody” pero tendremos que aplicar algo de “HTML” en nuestro VBA:

.HTMLBody = "<html>" & _ 
"<body><font color=""#FF0000"" size=""6"" face=""Comic Sans MS, cursive""><strong>Hola mi querido y estimado amigo</strong></font>" & _ 
"</body></html>" 
En este caso el mensaje se envía en letra cursiva de color rojo usando “Comic Sans” como fuente. Para ayudarnos con el código "HTML", podemos usar un programa como el “DreamWeaver” o un editor de “HTML” en línea, solo hay que adaptar lo que obtengamos de él para agregarlo a nuestra macro.

Si lo que queremos, además, es adjuntar algún archivo a nuestro mensaje, debemos usar la propiedad “Attachments” y su método “Add”. Podemos agregar más de un archivo del siguiente modo:

.Attachments.Add "D:\Miarchivouno.xlsm" 
.Attachments.Add "D:\MiArchivoNuevo.xlsx" 

Es bueno recordar que también podemos usar un bucle y/o variables para agregar más archivos.

Siguiendo con los adjuntos, probablemente tengamos nuestra firma en formato “JPG” y queremos incluirla en el cuerpo del mensaje; de ser así, lo primero que debemos hacer es adjuntar el archivo:

.Attachments.Add “D:\MiFirma.jpg"

Después incluiremos dicha imagen en el cuerpo del mensaje del siguiente modo y/o similar:

.HTMLBody = "<html>" & _
        "<body>" & _
           "<p>Aqui tu mensaje</p>" & _
            "<br>" & _ 
            "<br>" & _
            "<img src='cid:'" & .Attachments.Item(1).Filename & "'' height=100 width=75>" & _
            "</body>" & _
            "</html>" 
Los archivos adjuntos tienen un índice, si se tiene más archivos adjuntos, considerar el índice adecuado. En este caso he usado el uno (1).

Hasta la próxima.

Abraham Valencia

PD: En realidad cuando se usa el objeto "Outlook", y sobre todo se nota cuando se hacen envíos masivos, lo que ocurre es que se van colocando los mensajes en la "Bandeja de salida" así que es recomendable que se tenga el Microsoft Outlook configurado para el envío automático al abrir/cerrar para que el proceso continúe el envío así se cierre el Excel. Igual si se desea que se haga casi al instante el envío desde la macro, se puede añadir un Application.Wait después del "Send" o tener el Outlook abierto.

Extras:

En ocasiones deseamos enviar un rango de nuestra hoja como parte del cuerpo del mensaje, hay algunas alternativas como convertir el rango en imagen y colocarla en el cuerpo del mensaje, similar a lo que se hace con las firmas pero la mejor alternativa que he visto es usar una “Función Definida por el Usuario” (UDF) que convierte el rango en lenguaje “HTML” y permite incluirlo en el cuerpo del mensaje a través de la propiedad “HTMLBody”. EL autor es Ron de Bruin y la UDF podemos encontrarla aquí:

http://www.rondebruin.nl/win/s1/outlook/bmail2.htm

Cuando tenemos más de un correo configurado en el Outlook, recomiendo usar una UDF (Autor: Antoni - Galicia, España) para poder elegir el correo que queremos usar:

https://ayudaexcel.com/foro/topic/32737-elegir-cuenta-de-correo-de-outlook/

De no elegir alguno de los correos con la UDF, se usará el correo configurado como predeterminado.