Uso de Excel VBA para enviar contenido a OneNote - Artículos de TechTV

En agosto, Microsoft lanzó la versión SP1 de OneNote. Esta es una actualización imprescindible. Agregaron muchas características increíbles, incluyen una interfaz de programación de aplicaciones que permite que otras aplicaciones envíen datos a OneNote.

Microsoft ofrece varios sitios web excelentes que le enseñarán cómo usar VB.Net para enviar datos a OneNote. Pero, dado que este es el sitio, usted, yo y los otros 200 millones de usuarios de Office estamos más preocupados por cómo enviar datos a OneNote mediante Office VBA. Me complace decir que esto PUEDE hacerse. Esta página lo guiará a través de todo lo que necesita para hacerlo.

Asumiré que está bastante familiarizado con VBA. Si no es así, recomiendo VBA y Macros para Microsoft Excel, el libro diseñado para llevar a alguien en la curva de aprendizaje de VBA.

Visión general

Puede enviar datos a OneNote formateando los datos como datos XML. XML es un concepto bastante nuevo. Es algo así como HTML. Piense en ello como un archivo CSV con esteroides. Puede leer mi Introducción a XML.

Básicamente, su programa VBA necesita escribir un archivo XML y luego pasar el contenido del archivo XML a OneNote usando el método .Import. El archivo XML debe contener estos elementos:

  • Un elemento SecurePage para cada página en la que desea escribir. Si la página no existe, OneNote creará la página por usted. En teoría, se supone que debe tener el control y colocar la página después de una página existente específica. Sin embargo, en la práctica, esto no parece funcionar.
  • Un elemento PlaceObject para cada elemento que desee agregar a la página. Usted especifica la ubicación X e Y del artículo y la fuente del artículo. Un elemento puede ser una imagen, un objeto Ink o texto en formato HTML. Pensaría que, dado que OneNote lee HTML, podría pasar una tabla con etiquetas TR y TD, pero esto no funciona. Está limitado a pasar texto con etiquetas BR y P para agregar avances de línea. Las etiquetas UL y LI parecen funcionar. Las etiquetas de fuente funcionan.

El gotcha

Para actualizar una página existente, debe conocer el Identificador único global (GUID) de esa página. No parece haber una forma de encontrar el GUID para una página existente en OneNote. Esto significa que solo puede actualizar o eliminar elementos en una página existente si creó la página mediante programación y almacenó el GUID utilizado para crear esa página en su libro de trabajo. El siguiente ejemplo utiliza un lugar apartado en la hoja de trabajo para guardar el GUID de la página, la tabla de datos y el gráfico.

GUID

Cada nueva página en OneNote necesita un GUID. Cada nuevo objeto colocado en una página necesita un GUID. Si bien es fácil generar GUID desde VB.Net, ha sido difícil encontrar una forma de generar GUID desde VBA. Todos los 200 millones de usuarios de Office VBA deben darle una punta del límite a Michael Kaplan de Trigeminal Software. Michael parece ser el único tipo en el mundo que rompe el código sobre cómo generar un GUID desde VBA. Amablemente ha compartido este código con el mundo. Consulte el código completo en su sitio web. Con el permiso de Michael, he copiado solo las funciones necesarias para generar un nuevo GUID en VBA aquí. Inserte un módulo en su proyecto e incluya el siguiente código en ese módulo.

'------------------------------------------ ' basGuid from http://www.trigeminal.com/code/guids.bas ' You may use this code in your applications, just make ' sure you keep the (c) notice and don't publish it anywhere ' as your own ' Copyright (c) 1999 Trigeminal Software, Inc. All Rights Reserved '------------------------------------------ Option Compare Binary ' Note that although Variants now have ' a VT_GUID type, this type is unsupported in VBA, ' so we must define our own here that will have the same ' binary layout as all GUIDs are expected by COM to ' have. Public Type GUID Data1 As Long Data2 As Integer Data3 As Integer Data4(7) As Byte End Type Public Declare Function StringFromGUID2 Lib "ole32.dll" _ (rclsid As GUID, ByVal lpsz As Long, ByVal cbMax As Long) As Long Public Declare Function CoCreateGuid Lib "ole32.dll" _ (rclsid As GUID) As Long '------------------------------------------------------------ ' StGuidGen ' ' Generates a new GUID, returning it in canonical ' (string) format '------------------------------------------------------------ Public Function StGuidGen() As String Dim rclsid As GUID If CoCreateGuid(rclsid) = 0 Then StGuidGen = StGuidFromGuid(rclsid) End If End Function '------------------------------------------------------------ ' StGuidFromGuid ' ' Converts a binary GUID to a canonical (string) GUID. '------------------------------------------------------------ Public Function StGuidFromGuid(rclsid As GUID) As String Dim rc As Long Dim stGuid As String ' 39 chars for the GUID plus room for the Null char stGuid = String$(40, vbNullChar) rc = StringFromGUID2(rclsid, StrPtr(stGuid), Len(stGuid) - 1) StGuidFromGuid = Left$(stGuid, rc - 1) End Function

Agregar una referencia

En VBA, use Herramientas - Referencias para agregar una referencia a la Biblioteca de objetos de OneNote 1.1. Esto le permitirá declarar un nuevo objeto CSimpleImporter y luego usar los métodos .Import y .NavigateToPage en el objeto.

Caso de estudio

Este libro de Excel contiene un sistema de informes diarios. Hay una hoja de trabajo para cada tienda en una cadena de tiendas local. Cada página contiene una tabla que muestra las ventas diarias y un gráfico que muestra el progreso hacia la meta mensual.

El código VBA agregará una nueva sección llamada DailySales. Se agregará una nueva página para cada tienda. El gráfico de la hoja de trabajo se exporta como un archivo GIF y se importa a OneNote. Los datos de la hoja de trabajo se agregan a OneNote como una columna HTML.

Ventas diarias

El siguiente código se usa en Excel.

Sub CreateUpdateOneNoteReport() ' Requires basGuid module from above Dim Cht As Chart fname = "C:OneNoteImport.xml" On Error Resume Next Kill (fname) On Error GoTo 0 ' Do we need new GUID's? For Each ws In ThisWorkbook.Worksheets If Not ws.Range("J22").Value> "" Then ws.Range("J22").Value = StGuidGen() End If If Not ws.Range("J23").Value> "" Then ws.Range("J23").Value = StGuidGen() End If If Not ws.Range("J24").Value> "" Then ws.Range("J24").Value = StGuidGen() End If Next ws ' Build a temporary XML file fname = "C:OneNoteImport.xml" On Error Resume Next Kill (fname) On Error GoTo 0 Open fname For Output As #1 Print #1, " " Print #1, " " ' Make sure that for each page, we have a page FirstPage = True DateStr = Format(Date - 1, "yyyy-mm-dd") & "T21:00:00-06:00" For Each ws In ThisWorkbook.Worksheets ThisTitle = ws.Name ThisGuid = ws.Range("J22").Value Print #1, " " FirstPage = False LastGuid = ThisGuid Next ws For Each ws In ThisWorkbook.Worksheets ThisTitle = ws.Name ThisImage = "C: " & ThisTitle & ".gif" ThisGuid = ws.Range("J22").Value ChartGuid = ws.Range("J24").Value TableGuid = ws.Range("J23").Value ' Export the Chart Set Cht = ws.ChartObjects(1).Chart Cht.Export Filename:=ThisImage, FilterName:="GIF" ' Place the Chart on the top, right side Print #1, "" Print #1, " " Print #1, "" Print #1, " " Print #1, " " Print #1, "  
Resulting OneNote Notebook

Apparent Bugs

In the book, I mentioned an apparent bug with "insertafter". I forgot that XML is case sensitive. If you use "insertAfter", then everything works fine. Thanks to Donovan Lange at Microsoft for pointing this out.

I am guessing that the next issue is not a bug - the code is probably working like Microsoft intended, but they missed an opportunity to do something the right way. You are allowed to specify a date and time in the EnsurePage section of the XML. This date and time is only used if the page does not exist. Given that Microsoft later allows us to update the page by remembering the GUID, they really should have allowed us to update the date and time on the page. In the example here, we are pushing new data each day, yet the date is always going to show that it is as of the first time that the program was run. This is disappointing.

Articulos interesantes...