Codificación y descodificación de datos adjuntos de archivos mediante programación mediante Visual C# en InfoPath 2010 o en InfoPath 2007

Resumen

En Microsoft InfoPath 2010 o en Microsoft Office InfoPath 2007, puede usar un control Archivos adjuntos para adjuntar un archivo a la plantilla de formulario de InfoPath. En circunstancias específicas, es posible que desee codificar y, a continuación, descodificar el archivo que está asociado al control Archivos adjuntos. En este caso, puede usar Microsoft Visual C# para crear una clase Encoderclass y una clase Decoderclass. A continuación, puede usar Encoderclass y Decoderclass para codificar y descodificar los datos adjuntos del archivo. En este artículo se describe cómo diseñar una plantilla de formulario de InfoPath que codifica un archivo para los datos adjuntos al formulario y descodifica los datos adjuntos para guardarlos en el sistema de archivos.  

Para obtener más información sobre cómo hacerlo en InfoPath 2003, haga clic en el número de artículo siguiente para verlo en Microsoft Knowledge Base:

892730 Codificación y descodificación de datos adjuntos de un archivo mediante programación mediante Visual C# en InfoPath

Más información

Microsoft proporciona ejemplos de programación con fines ilustrativos únicamente, sin ninguna garantía tanto expresa como implícita, incluyendo, pero sin limitarse, a las garantías implícitas de comerciabilidad e idoneidad para un fin determinado. En este artículo se da por supuesto que ya conoce el lenguaje de programación que se muestra, así como las herramientas empleadas para crear y depurar procedimientos. Los profesionales de soporte técnico de Microsoft pueden explicarle la funcionalidad de un determinado procedimiento, pero no modificarán estos ejemplos para ofrecer mayor funcionalidad ni crearán procedimientos adaptados a sus necesidades específicas.

En el ejemplo siguiente, seguirá estos pasos:

  1. Cree un formulario que incluya un proyecto de Visual C#.
  2. Cree una clase Encoderclass.
  3. Cree una clase Decoderclass.
  4. Modifique el formulario para llamar al código.
  5. Pruebe las operaciones de código en el formulario.

Creación de un formulario que incluya un proyecto de Visual C#

Cree una plantilla de formulario y un proyecto mediante las instrucciones para la versión de InfoPath que está usando.

InfoPath 2010

  1. En el Diseñador de InfoPath, cree una plantilla de formulario en blanco y, a continuación, haga clic en el icono Guardar.
  2. Cuando se le solicite, escriba el nombre de archivo y, a continuación, haga clic en Guardar.
  3. Haga clic en la pestaña **Desarrollador **y, a continuación, haga clic en Idioma.
  4. En Lenguaje de código de plantilla de formulario, seleccione C# y, a continuación, haga clic en Aceptar.

InfoPath 2007

  1. En el menú **Archivo **, haga clic en Diseñar una plantilla de formulario.
  2. En el panel de tareas **Diseñar una plantilla de formulario **, haga clic en En blanco y, a continuación, haga clic en Aceptar.
  3. En el menú Archivo, haga clic en Guardar.
  4. Cuando se le solicite, escriba el nombre de archivo InfoPathAttachmentEncoding y, a continuación, haga clic en Guardar.
  5. En el menú Herramientas, haga clic en Opciones de formulario.
  6. En Categoría en el cuadro de diálogo **Opciones de formulario **, haga clic en Programación.
  7. En Lenguaje de programación, en la lista Lenguaje de código de plantilla de formulario , seleccione C# y haga clic en Aceptar.

Creación de una clase Encoder

Cree una clase Encoder mediante las instrucciones de la versión de InfoPath que está usando.

InfoPath 2010

  1. En la pestaña Desarrollador, haga clic en **Editor de código **para iniciar el editor de Visual Studio Tools for Applications (VSTA).
  2. En el menú Proyecto , haga clic en Agregar nuevo elemento.
  3. Haga clic para seleccionar Clase.
  4. En el campo Nombre , cambie el nombre a InfoPathAttachmentEncoder.cs y, a continuación, haga clic en Guardar.
  5. En la ventana de código, reemplace el código existente por el código de la siguiente sección "Código del codificador".

InfoPath 2007

  1. Inicie el editor de Visual Studio Tools for Applications (VSTA). 
  2. En el panel **Explorador de proyectos **, haga clic con el botón derecho en InfoPathAttachmentEncoding, haga clic en Agregary, a continuación, haga clic en Nuevo elemento.
  3. En la sección Plantillas , seleccione Clase, cambie el nombre a InfoPathAttachmentEncoder.cs y, a continuación, haga clic en Agregar.
  4. En la ventana de código, pegue el código de la siguiente sección "Código del codificador".

Código del codificador

Use el código siguiente en InfoPath 2010 o en InfoPath 2007:

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using InfoPathAttachmentEncoding;

namespace InfoPathAttachmentEncoding
{
/// <summary>
/// InfoPathAttachment encodes file data into the format expected by InfoPath for use in file attachment nodes.
/// </summary>
public class InfoPathAttachmentEncoder
{
private string base64EncodedFile = string.Empty;
private string fullyQualifiedFileName;

/// <summary>
/// Creates an encoder to create an InfoPath attachment string.
/// </summary>
/// <param name="fullyQualifiedFileName"></param>
public InfoPathAttachmentEncoder(string fullyQualifiedFileName)
{
if (fullyQualifiedFileName == string.Empty)
throw new ArgumentException("Must specify file name", "fullyQualifiedFileName");

if (!File.Exists(fullyQualifiedFileName))
throw new FileNotFoundException("File does not exist: " + fullyQualifiedFileName, fullyQualifiedFileName);

this.fullyQualifiedFileName = fullyQualifiedFileName;
}

/// <summary>
/// Returns a Base64 encoded string.
/// </summary>
/// <returns>String</returns>
public string ToBase64String()
{
if (base64EncodedFile != string.Empty)
return base64EncodedFile;

// This memory stream will hold the InfoPath file attachment buffer before Base64 encoding.
MemoryStream ms = new MemoryStream();

// Obtain the file information.
using (BinaryReader br = new BinaryReader(File.Open(fullyQualifiedFileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
string fileName = Path.GetFileName(fullyQualifiedFileName);

uint fileNameLength = (uint)fileName.Length + 1;

byte[] fileNameBytes = Encoding.Unicode.GetBytes(fileName);

using (BinaryWriter bw = new BinaryWriter(ms))
{
// Write the InfoPath attachment signature. 
bw.Write(new byte[] { 0xC7, 0x49, 0x46, 0x41 });

// Write the default header information.
bw.Write((uint)0x14);// size
bw.Write((uint)0x01);// version
bw.Write((uint)0x00);// reserved

// Write the file size.
bw.Write((uint)br.BaseStream.Length);

// Write the size of the file name.
bw.Write((uint)fileNameLength);

// Write the file name (Unicode encoded).
bw.Write(fileNameBytes);

// Write the file name terminator. This is two nulls in Unicode.
bw.Write(new byte[] {0,0});

// Iterate through the file reading data and writing it to the outbuffer.
byte[] data = new byte[64*1024];
int bytesRead = 1;

while (bytesRead > 0)
{
bytesRead = br.Read(data, 0, data.Length);
bw.Write(data, 0, bytesRead);
}
}
}

// This memorystream will hold the Base64 encoded InfoPath attachment.
MemoryStream msOut = new MemoryStream();

using (BinaryReader br = new BinaryReader(new MemoryStream(ms.ToArray())))
{
// Create a Base64 transform to do the encoding.
ToBase64Transform tf = new ToBase64Transform();

byte[] data = new byte[tf.InputBlockSize];
byte[] outData = new byte[tf.OutputBlockSize];

int bytesRead = 1;

while (bytesRead > 0)
{
bytesRead = br.Read(data, 0, data.Length);

if (bytesRead == data.Length)
tf.TransformBlock(data, 0, bytesRead, outData, 0);
else
outData = tf.TransformFinalBlock(data, 0, bytesRead);

msOut.Write(outData, 0, outData.Length);
}
}

msOut.Close();

return base64EncodedFile = Encoding.ASCII.GetString(msOut.ToArray());
}
}
}

Creación de una clase Decoder

Cree una clase Decoderclass mediante las instrucciones para la versión de InfoPath que está usando.

InfoPath 2010

  1. En el Editor de código, en el menú Proyecto , haga clic en Agregar nuevo elemento y, a continuación, haga clic en para seleccionar Clase.
  2. En el campo Nombre , cambie el nombre a InfoPathAttachmentDecoder.cs y, a continuación, haga clic en Guardar.
  3. En la ventana de código, reemplace el código existente por el código de la siguiente sección "Código descodificador". 

InfoPath 2007

  1. En VSTA, en el panel **Explorador de proyectos **, haga clic con el botón derecho en InfoPathAttachmentEncoding, haga clic en Agregary, a continuación, haga clic en Nuevo elemento.
  2. En la sección Plantillas , seleccione Clase, cambie el nombre a InfoPathAttachmentDecoder.cs y, a continuación, haga clic en Agregar.
  3. En la ventana de código, pegue el código de la siguiente sección "Código descodificador".

Código descodificador

Use el código siguiente en InfoPath 2010 o en InfoPath 2007:

using System;
using System.IO;
using System.Text;

namespace InfoPathAttachmentEncoding
{
/// <summary>
/// Decodes a file attachment and saves it to a specified path.
/// </summary>
public class InfoPathAttachmentDecoder
{
private const int SP1Header_Size = 20;
private const int FIXED_HEADER = 16;

private int fileSize;
private int attachmentNameLength;
private string attachmentName;
private byte[] decodedAttachment;

/// <summary>
/// Accepts the Base64 encoded string
/// that is the attachment.
/// </summary>
public InfoPathAttachmentDecoder(string theBase64EncodedString)
{
byte [] theData = Convert.FromBase64String(theBase64EncodedString);
using(MemoryStream ms = new MemoryStream(theData))
{
BinaryReader theReader = new BinaryReader(ms);
DecodeAttachment(theReader);
}
}

private void DecodeAttachment(BinaryReader theReader)
{
//Position the reader to obtain the file size.
byte[] headerData = new byte[FIXED_HEADER];
headerData = theReader.ReadBytes(headerData.Length);

fileSize = (int)theReader.ReadUInt32();
attachmentNameLength = (int)theReader.ReadUInt32() * 2;

byte[] fileNameBytes = theReader.ReadBytes(attachmentNameLength);
//InfoPath uses UTF8 encoding.
Encoding enc = Encoding.Unicode;
attachmentName = enc.GetString(fileNameBytes, 0, attachmentNameLength - 2);
decodedAttachment = theReader.ReadBytes(fileSize);
}

public void SaveAttachment(string saveLocation)
{
string fullFileName = saveLocation;
if (!fullFileName.EndsWith(Path.DirectorySeparatorChar.ToString())){
fullFileName += Path.DirectorySeparatorChar;
}

fullFileName += attachmentName;

if(File.Exists(fullFileName))
File.Delete(fullFileName);

FileStream fs = new FileStream(fullFileName, FileMode.CreateNew);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(decodedAttachment);

bw.Close();
fs.Close();
}

public string Filename
{
get{ return attachmentName; }
}

public byte[] DecodedAttachment
{
get{ return decodedAttachment; }
}
}
}

Modificación del formulario

Agregue un control Datos adjuntos de archivo, un control Cuadro de texto y un control Botón al formulario de InfoPath. Para ello, siga estos pasos:

  1. Abra el panel de tareas Controles mediante las instrucciones para la versión de InfoPath que está usando. 

    • InfoPath 2010:In the InfoPathAttachmentEncoding InfoPath form template, under the **Home **tab, expande la **Controls **gallery.
    • InfoPath 2007:In the InfoPathAttachmentEncoding InfoPath form template, click Controls in the **Design Tasks **task pane.
  2. Agregue un control Datos adjuntos de archivo al formulario de InfoPath mediante las instrucciones de la versión de InfoPath que usa:

    • InfoPath 2010:En el panel de tareas Controles , en Objetos, haga clic en Archivos adjuntos.
    • InfoPath 2007:En el panel de tareas Controles , en Archivo e imagen, haga clic en Archivos adjuntos.
  3. Haga clic con el botón derecho en el control **Archivos adjuntos **y, a continuación, haga clic en Propiedades de datos adjuntos de archivo.

  4. En el cuadro de diálogo **Propiedades de datos adjuntos de archivo **, escriba el campoAttachmentField en el cuadro **Nombre de campo **y, a continuación, haga clic en Aceptar.

  5. Agregue un control Cuadro de texto al formulario de InfoPath mediante las instrucciones de la versión de InfoPath que está usando:

    • InfoPath 2010: en el panel de tareas Controles , en Entrada, haga clic en Cuadro de texto.
    • InfoPath 2007: en el panel de tareas Controles , en Estándar, haga clic en Cuadro de texto.
  6. Haga clic con el botón derecho en el control Cuadro de texto y, a continuación, haga clic en Propiedades del cuadro de texto.

  7. En el cuadro de diálogo **Propiedades del cuadro de texto **, escriba el ValorAttachmentName en el cuadro **Nombre de campo **y, a continuación, haga clic en Aceptar.

  8. Agregue un botón Adjuntar al formulario de InfoPath mediante las instrucciones de la versión de InfoPath que usa:

    • InfoPath 2010: en el panel de tareas Controles , en Objetos, haga clic en Botón.
    • InfoPath 2007: en el panel de tareas Controles , en Estándar, haga clic en Botón.
  9. Haga clic con el botón derecho en el nuevo control Botón y, a continuación, haga clic en Propiedades del botón.

  10. En el cuadro de diálogo **Propiedades del botón **, escriba Asociar en el cuadro **Etiqueta **, escriba btnAttach en el cuadro Id . y, a continuación, haga clic en Editar código de formulario.

  11. Vaya a la parte superior de la ventana de código y agregue la siguiente línea de código:

    using InfoPathAttachmentEncoding;
    
  12. Vuelva a "escribir el código aquí" y agregue el código siguiente:

     //Create an XmlNamespaceManager
     XmlNamespaceManager ns = this.NamespaceManager;
    
    //Create an XPathNavigator object for the Main data source
     XPathNavigator xnMain = this.MainDataSource.CreateNavigator();
    
    //Create an XPathNavigator object for the attachment node
     XPathNavigator xnAttNode = xnMain.SelectSingleNode("/my:myFields/my:theAttachmentField", ns);
    
    //Create an XPathNavigator object for the filename node
     XPathNavigator xnFileName = xnMain.SelectSingleNode("/my:myFields/my:theAttachmentName", ns);
    
    //Obtain the text of the filename node.
     string fileName = xnFileName.Value;
     if (fileName.Length > 0)
     {
      //Encode the file and assign it to the attachment node.
      InfoPathAttachmentEncoder myEncoder = new InfoPathAttachmentEncoder(fileName);
    
    //Check for the "xsi:nil" attribute on the file attachment node and remove it
      //before setting the value to attach the filerRemove the "nil" attribute
      if (xnAttNode.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"))
       xnAttNode.DeleteSelf();
    
    //Attach the file
      xnAttNode.SetValue(myEncoder.ToBase64String());
     }              
    
    

Agregar un botón Guardar al formulario de InfoPath

  1. Vuelva a la plantilla de formulario InfoPathAttachmentEncoding.

  2. Agregue un botón Guardar con las instrucciones de la versión de InfoPath que usa:

    • InfoPath 2010: en el panel de tareas Controles , en Objetos, haga clic en Botón.
    • InfoPath 2007: en el panel de tareas Controles , en Estándar, haga clic en Botón.
  3. Haga clic con el botón derecho en el nuevo control Botón y, a continuación, haga clic en Propiedades del botón.

  4. En el cuadro de diálogo **Propiedades del botón **, escriba Guardar en el cuadro **Etiqueta **, escriba btnSave en el cuadro **ID **y, a continuación, haga clic en Editar código de formulario.

  5. Inserte el código siguiente:

     //Create an XmlNamespaceManager
     XmlNamespaceManager ns = this.NamespaceManager;
    
    //Create an XPathNavigator object for the Main data source
     XPathNavigator xnMain = this.MainDataSource.CreateNavigator();
    
    //Create an XPathNavigator object for the attachment node
     XPathNavigator xnAttNode = xnMain.SelectSingleNode("/my:myFields/my:theAttachmentField", ns);
    
    //Obtain the text of the node.
     string theAttachment = xnAttNode.Value;
     if(theAttachment.Length > 0)
     {
         InfoPathAttachmentDecoder myDecoder = new InfoPathAttachmentDecoder(theAttachment);
         myDecoder.SaveAttachment(@"Path to the folder to save the attachment");
     }                                              
    
    

Nota:

En este código, el marcador de posición Ruta de acceso a la carpeta para guardar los datos adjuntos representa la ubicación en la que desea guardar el archivo.

Haga clic en el icono Guardar y, a continuación, cierre VSTA.

Prueba del formulario

Antes de que este formulario pueda adjuntar un archivo, la plantilla de formulario de InfoPath debe ser de plena confianza. Para asegurarse de esto, realice una de las siguientes acciones:

  • Use un certificado de firma de código para firmar digitalmente el archivo de plantilla de formulario (.xsn). Al hacerlo, se pide a los usuarios que confíen en el formulario cuando abran el formulario. Esto hace que el formulario sea de plena confianza. Por lo tanto, se conceden permisos de plena confianza al código de Visual C#.
  • Cree una plantilla instalable.

Después de asegurarse de que la plantilla de formulario es de plena confianza, debe probarla. Para ello, siga estos pasos:

  1. Abra el formulario en modo vista previa siguiendo los pasos de la versión de InfoPath que está usando:

    • InfoPath 2010 En la pestaña Inicio , haga clic en Vista previa.
    • InfoPath 2007 En standardtoolbar, haga clic en Vista previa.
  2. En el formulario de InfoPath, escriba la ruta de acceso del archivo que desea adjuntar en el cuadro de texto y, a continuación, haga clic en Adjuntar.

    Nota Haga doble clic en el control Archivos adjuntos para comprobar que el archivo está codificado correctamente. 

  3. Haga clic en Guardar.

  4. Busque la ruta de acceso que proporcionó en el código de la sección "Agregar un botón Guardar al formulario de InfoPath" y, a continuación, asegúrese de que el archivo se guardó en esa carpeta. 

  5. Haga clic en Cerrar vista previa. Esto finaliza la prueba.