Está en la página 1de 7

España - Español Iniciar sesión

MSDN Magazine Buscar MSDN Magazine con Bing

Inicio Temas Columnas Descargas Suscríbase RSS

Último número Todos los números Archivos de ayuda HTML

MSDN Magazine > Inicio > Todos los números > 2006 > November > Basic Instincts: Generación de documentos ...

Basic Instincts

Generación de documentos de
Word 2007 en el servidor
Ted Pattison

Descarga de código disponible en: BasicInstincts2006_11.exe (170 KB)


Browse the Code Online
Contenido
Mecanismos internos de los documentos de Word 2007
Generación del primer archivo DOCX
Generación de archivos DOCX en el servidor

Hasta ahora, la escritura e implementación de aplicaciones de servidor que leen, modifican y generan
documentos de Microsoft® Office presentaba un reto. El antiguo formato binario usado por
Microsoft Word, Excel® y PowerPoint® se presentó en 1997 y se ha mantenido como el formato de
archivo predeterminado hasta la versión de Office 2003. Sin embargo, se ha comprobado que resulta
demasiado complicado trabajar con este formato de archivo binario. La gran mayoría de aplicaciones de
producción que leen y escriben documentos de Office lo hacen a través del modelo de objeto de la
aplicación de Office de alojamiento.
Las aplicaciones y los componentes que usan el modelo de objeto de aplicaciones como Word o Excel,
se ejecutan mucho mejor en el escritorio que en escenarios de servidor. Cualquiera que haya dedicado
tiempo a escribir código de infraestructura adicional necesario para que una aplicación de escritorio de
Office se comporte de forma confiable en el servidor, comentará que es una solución nada deseable.
Esto se debe a que las aplicaciones de escritorio de Office como Word y Excel no se diseñaron para
ejecutarse en un servidor y requieren un programa de utilidad personalizado para cerrarse y reiniciarse
si se encuentran con un diálogo modal que precise de la intervención humana. MSDN Magazine Blog
La capacidad de leer y escribir documentos de Office sin contar con el modelo de objeto de la aplicación
de Office de alojamiento resulta mucho más deseable en un escenario de servidor. Office 2000 y November Issue of MSDN Magazine
Office 2003 presentaban algunas capacidades sencillas de creación de libros de Excel y documentos de As I wrote earlier, the Government Special Issue
Word mediante XML. Este avance ofrecía la posibilidad de escribir fragmentos de un documento de of MSDN Magazine, currently live on our Web
Office con una biblioteca XML como la que incluye Microsoft .NET Framework mediante el espacio de site, is worth checking out. The articles in the
nombres System.Xml. special... More...
martes, nov. 5
En el sistema Microsoft Office 2007, Microsoft ha llevado esta idea mucho más lejos adoptando los
formatos de archivo XML abiertos de Office para los documentos usados por Microsoft Office Word, Government Special Issue of MSDN Magazine
Excel y PowerPoint 2007. Estos formatos han entusiasmado a los desarrolladores de ASP.NET y Visit the MSDN Magazine Web site and you’ll
SharePoint®, ya que les ofrecen la posibilidad de leer, escribir y generar documentos de Word, libros de see we’ve been a bit busier than usual of late. In
Excel o presentaciones de PowerPoint en el servidor sin necesidad de que el sistema ejecute una addition to the regularly scheduled November
aplicación de escritorio de Office en el mismo. issue, fea... More...
viernes, nov. 1
Los formatos de archivo XML abiertos de Office van camino de convertirse en un estándar publicado por
la Asociación europea de fabricantes de informática (ECMA). Puede consultar más información sobre el More MSDN Magazine Blog entries >
proceso de normalización actual, descargar el último borrador de especificaciones de los formatos de
archivo XML abiertos de Office y buscar otros fantásticos recursos en línea en openxmldeveloper.com. El
objetivo del artículo de este mes es presentar los datos de programación necesarios para crear sencillos
documentos de Word en una aplicación ASP.NET y devolverlos a usuarios que podrán abrirlos
directamente con Word 2007. Current Issue

Mecanismos internos de los documentos de Word 2007


Comencemos a examinar la estructura de un documento de Word simple basado en los formatos de
archivo XML abiertos de Office. Como podrá observar, los formatos de archivo XML abiertos de Office
se basan en la tecnología de archivos ZIP estándar. Cada archivo de un nivel superior se guarda como
archivo ZIP, lo que significa que podrá abrir un documento de Word de igual forma que un archivo ZIP y
consultar su contenido con la compatibilidad de archivos ZIP integrada en el Explorador de Windows ®.
Tenga en cuenta que las aplicaciones del sistema Microsoft Office 2007 como Word y Excel incluyen
extensiones de archivo para documentos que usan el nuevo formato. Por ejemplo, la extensión .docx se
usa para documentos de Word almacenados en formatos de archivo XML abiertos de Office, mientras
que la extensión más conocida .doc se sigue usando para los documentos de Word almacenados en
formato binario.
Para entender esta explicación, cree un nuevo documento en Word 2007 y agregue el texto "Hello Word".
Guarde el documento con el formato predeterminado en un nuevo archivo con el nombre Hello.docx y
cierre Word. A continuación, busque Hello.docx con el Explorador de Windows y cambie su nombre por Browse All MSDN Magazines
Hello.zip. Abra Hello.zip y vea la estructura de carpetas y archivos que Word ha creado internamente
(consulte la figura 1).
Subscribe to MSDN Flash
newsletter

Receive the MSDN Flash e-mail newsletter every


other week, with news and information
other week, with news and information
personalized to your interests and areas of
focus.

figura 1 archivo DOCX es un archivo ZIP (Haga clic aquí para obtener una imagen más grande) (Hacer clic
en la imagen para ampliarla)
El archivo del nivel superior (Hello.docx) se conoce como paquete. Puesto que un paquete se implementa
como un archivo ZIP estándar, ofrece una compresión automática y hace que su contenido esté accesible
de inmediato para muchas utilidades y API existentes, tanto en plataformas Windows como en otras
plataformas similares.
Dentro de un paquete hay dos tipos de contenido interno: componentes y elementos. En general, los
componentes incluyen el contenido y los elementos contienen los metadatos que describen los
componentes. Los elementos se pueden dividir aún más en elementos de relación y elementos de tipo de
contenido. Un componente es una parte interna que incluye contenido que se almacena en el paquete. La
mayoría de los componentes son archivos de texto simples que se serializan como XML con un esquema
XML asociado. No obstante, los componentes también se pueden serializar como datos binarios si es
necesario, por ejemplo, cuando un documento de Word contiene una imagen o un archivo multimedia.
Los nombres de los componentes son identificadores uniformes de recursos (URI) que contienen la ruta
relativa dentro del archivo de paquete junto con el nombre del archivo del componente. Por ejemplo, la
parte principal de un paquete de un documento de Word es /word/document.xml. A continuación, se
incluyen algunos nombres de componente típicos adicionales que encontrará en el paquete de un
documento de Word simple:

/[Content_Types].xml
/_rels/.rels
/docProps/app.xml
/docProps/core.xml
/word/_rels/document.xml.rels
/word/document.xml
/word/fontTable.xml
/word/settings.xml
/word/styles.xml
/word/theme/theme1.xml

Los formatos de archivo XML abiertos de Office usan relaciones para definir las asociaciones entre un
componente de origen y uno de destino. La relación de un paquete define una asociación entre el
paquete de nivel superior y un componente. La relación de un componente define una asociación entre
un componente principal y uno secundario. Las relaciones son importantes porque permiten detectar
estas asociaciones sin tener que examinar el contenido de los componentes en cuestión. Esto significa
que las relaciones son independientes del esquema específico de contenido y, por tanto, permiten una
resolución más rápida. Existe una ventaja adicional por el hecho de poder establecer una relación entre
dos componentes sin tener que modificar cada uno de ellos.
Las relaciones se definen en las partes internas conocidas como elementos de relación. Un elemento de
relación se almacena en el interior de un paquete al igual que un componente, aunque no se considera
componente como tal. Para mantener la coherencia, los elementos de relación se crean siempre dentro
de las carpetas _rels.
Por ejemplo, un paquete contiene exactamente un elemento de relación de paquete denominado
/_rels/.rels. El elemento de relación de paquete contiene elementos XML para definir las relaciones del
paquete, como, por ejemplo, la que existe entre el paquete del nivel superior para un archivo .docx y el
componente interno /word/document.xml, como se muestra a continuación:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>


<Relationships xmlns="../package/2006/relationships ">
<Relationship Id="rId1"
Type="../officeDocument/2006/relationships/officeDocument "
Target="word/document.xml"/>
</Relationships>

Como puede ver, un elemento de relación define un nombre, un tipo y un componente de destino.
También observará que el nombre de tipo de la relación se define con las mismas convenciones que se
usan para crear espacios de nombres XML.
Además del elemento de relación de paquete, los paquetes pueden contener también uno o varios
elementos de relación de componente. Por ejemplo, las relaciones entre /word/document.xml y los
componentes secundarios se definen en un elemento de relación de paquete ubicado en el URI
/word/_rels/document.xml.rels. Tenga en cuenta que el atributo Target de una relación del elemento de
relación de componente es un URI relativo al componente principal y no al paquete de nivel superior.
Cada componente de un paquete se define en cuanto a un tipo de contenido específico. Los tipos de
contenido son metadatos que definen un tipo de medio, un subtipo y un conjunto de parámetros
opcionales del componente. Cualquier tipo de contenido que se use en un paquete, se debe definir de
forma explícita en un elemento de tipo de contenido. Cada paquete cuenta con un elemento de tipo de
contenido denominado /[Content_Types].xml. En la figura 2, se muestra un ejemplo de definiciones de
tipo de contenido incluidas en /[Content_Types].xml. Observe en la ilustración que los elementos de
relación son como componentes, ya que también se definen con un tipo de contenido asociado.

Figure 2 Paquete de definición de tipos de contenido


Figure 2 Paquete de definición de tipos de contenido

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>


<Types xmlns=

"http://schemas.openxmlformats.org/package/2006/content-types">

<Default Extension="rels" ContentType=


"application/vnd.openxmlformats-package.relationships+xml"/>

<Default Extension="xml" ContentType="application/xml"/>

<Override PartName="/word/document.xml"
ContentType="application/vnd.openxmlformats-
officedocument.wordprocessingml.document.main+xml"/>
</Types>

El usuario de un paquete usa los tipos de contenido para interpretar cómo leer y representar el
contenido de los componentes. Como puede observar en la figura 2, un tipo de contenido
predeterminado normalmente está asociado a una extensión de archivo, como .rels o .xml. Los tipos de
contenido de invalidación se usan para definir un tipo de contenido que es distinto al predeterminado y
que está asociado a la extensión de archivo en un componente específico. Por ejemplo, la figura 2
muestra cómo /word/document.xml está asociado a un tipo de contenido que es distinto del tipo de
contenido predeterminado que se usa para archivos con la extensión .xml.

Generación del primer archivo DOCX


Aunque existen numerosas bibliotecas que puede usar para leer y escribir en los archivos ZIP, debe usar
la nueva API de paquete que forma parte del ensamblado WindowsBase.dll que se incluye con
.NET Framework 3.0 siempre que sea posible, pues esta API reconoce los formatos de archivo XML
abiertos de Office. Por ejemplo, hay una serie de métodos adecuados que facilitan la adición de
elementos de relación al elemento de relación y la adición de elementos de tipo de contenido al
elemento de tipo de contenido. La API de paquete facilita los procesos, ya que nunca deberá manipular
estos elementos directamente.
El código de este mes usa la versión de WindowsBase.dll que se instala con la versión preliminar para la
comunidad tecnológica (CTP) de febrero de WinFX® Runtime Components. Tenga en cuenta que se
cambió el nombre de WinFX Runtime Components a .NET Framework 3.0 con la versión de CTP de junio.
Puede usar cualquiera de estas dos versiones o cualquier versión posterior de .NET Framework 3.0. Para
probar el código que vamos a escribir en esta artículo, también necesitará instalar Word 2007 Beta 2 o
posterior. (Los cambios en Office desde la versión Beta 2 puede que necesiten alguna modificación del
código que se incluye aquí.)
Una vez que haya instalado .NET Framework 3.0, que incluye WindowsBase.dll, puede comenzar a
programar con la API de paquete en un proyecto de Visual Studio® 2005 agregando una referencia,
como se muestra en la figura 3.

figura 3 agregue referencia a WindowsBase.dll (Haga clic aquí para obtener una imagen más
figura 3 agregue referencia a WindowsBase.dll (Haga clic aquí para obtener una imagen más
grande) (Hacer clic en la imagen para ampliarla)
Las clases que componen la API de paquete están incluidas en el espacio de nombres System.IO.Package.
Al trabajar con paquetes, con frecuencia programará con clases antiguas y (esperemos que) conocidas
en los espacios de nombres System.IO y System.Xml. Examine el código de la figura 4 que muestra el
esqueleto de creación de un nuevo paquete.

Figure 4 Creación de un nuevo paquete

Imports System
Imports System.IO
Imports System.IO.Packaging
Imports System.Xml

Class GenerateDOCX

Shared Sub Main()

‘*** Create a new package


Dim pack As Package = Package.Open("c:\Data\Hello.docx", _
FileMode.Create, _
FileAccess.ReadWrite)

‘*** Write code here to create parts and add content

‘*** Close package


pack.Close()

End Sub

End Class

El espacio de nombres System.IO.Packaging contiene la clase Package, que muestra un método


compartido denominado Open que se usa para crear nuevos paquetes y abrir paquetes existentes. Al
igual que con otras clases relacionadas con la E/S de archivos, una llamada a Open siempre se debe
complementar con una llamada a Close.

Una vez que haya creado el nuevo paquete, el siguiente paso es crear uno o varios componentes y
serializar el contenido de los mismos. En el ejemplo del artículo de este mes, seguiremos las directrices
de una aplicación "Hello World", que requerirá la creación de un único componente denominado
\word\document.xml. Podemos crear un componente llamando al método CreatePart de un objeto
Package abierto y transfiriendo los parámetros para un URI y un tipo de contenido basado en cadenas:

'*** Create main document part (document.xml) ...


Dim uri As Uri = New Uri("/word/document.xml", UriKind.Relative)
Dim partContentType As String = "application/vnd.openxmlformats" & _
"-officedocument.wordprocessingml.document.main+xml"
Dim part As PackagePart = pack.CreatePart(uri, partContentType)

'*** Get stream for document.xml


Dim streamPart As New StreamWriter(part.GetStream(FileMode.Create, _
FileAccess.Write))

La llamada a CreatePart transfiere un URI de acuerdo con la ruta /word/document.xml y el tipo de


contenido que necesitan los formatos de archivo XML abiertos de Office para el componente de un
documento de procesador de textos que contenga el historial principal. Una vez creado el componente,
debemos serializar el contenido en él mediante técnicas de programación estándar basadas en
secuencias. El código que acabamos de ver abre una secuencia en el componente llamando al método
GetStream y usa el objeto Stream resultante para inicializar un objeto StreamWriter.
El objeto StreamWriter se va a usar para serializar el documento XML de "Hello World" en document.xml.
Eche un vistazo al siguiente documento XML; representa el ejemplo más simple de los documentos XML
que se pueden serializar en document.xml:

<?xml version="1.0" encoding="utf-8"?>


<w:document xmlns:w=
"http://schemas.openxmlformats.org/wordprocessingml/2006/3/main">
<w:body>
<w:p>
<w:r>
<w:t>Hello Word 2007</w:t>
</w:r>
</w:p>
</w:body>
</w:document>

Tenga en cuenta que todos los elementos de este documento XML se definen en el espacio de nombres
schemas.openxmlformats.org/wordprocessingml/2006/3/main según los formatos de archivo XML
abiertos de Office. El documento XML contiene un elemento de documento de alto nivel. En el elemento
del documento, hay un elemento de cuerpo que contiene el historial principal.
En el elemento de cuerpo, hay un elemento <p> para cada párrafo. En el elemento <p> hay una <r>
que define una ejecución. Una ejecución es una región de elementos que comparten el mismo conjunto
de características. En la ejecución, hay un elemento <t> que define un intervalo de texto, en este caso
de características. En la ejecución, hay un elemento <t> que define un intervalo de texto, en este caso
"Hello Word 2007".
Ahora vamos a generar el documento XML con código mediante la clase XmlDocument en el espacio de
nombres System.Xml. Si echa un vistazo a la figura 5, observará cómo el código crea estos elementos en
la estructura adecuada y con el espacio de nombres correspondiente. También debe tener en cuenta que
el código escribe el documento XML en la secuencia mediante el objeto StreamWriter y que, a
continuación, cierra la secuencia y descarga el contenido serializado en el objeto Package.

Figure 5 Generación de un documento XML

‘*** Define string variable for Open XML namespace for nsWP:
Dim nsWP As String = &quot;http://schemas.openxmlformats.org&quot; &amp; _
&quot;/wordprocessingml/2006/3/main&quot;

‘*** Create the start part, set up the nested structure ...
Dim xmlPart As XmlDocument = New XmlDocument()
Dim tagDocument As XmlElement
tagDocument = xmlPart.CreateElement(&quot;w:document&quot;, nsWP)
xmlPart.AppendChild(tagDocument)
Dim tagBody As XmlElement
tagBody = xmlPart.CreateElement(&quot;w:body&quot;, nsWP)
tagDocument.AppendChild(tagBody)
Dim tagParagraph As XmlElement
tagParagraph = xmlPart.CreateElement(&quot;w:p&quot;, nsWP)
tagBody.AppendChild(tagParagraph)
Dim tagRun As XmlElement
tagRun = xmlPart.CreateElement(&quot;w:r&quot;, nsWP)
tagParagraph.AppendChild(tagRun)
Dim tagText As XmlElement
tagText = xmlPart.CreateElement(&quot;w:t&quot;, nsWP)
tagRun.AppendChild(tagText)

‘*** Insert text into part as a Text node


Dim nodeText As XmlNode
nodeText = xmlPart.CreateNode(XmlNodeType.Text, &quot;w:t&quot;, nsWP)
nodeText.Value = &quot;Hello Word 2007&quot;
tagText.AppendChild(nodeText)

‘*** Write XML to part and close stream


xmlPart.Save(streamPart)

‘*** Close stream and flush XML content into package


streamPart.Close()
pack.Flush()

Ya hemos terminado de escribir el contenido XML en document.xml. El último paso consiste en crear una
relación entre el paquete y document.xml llamando al método CreateRelationship del objeto Package.
Este proceso resulta sencillo siempre que conozca el valor de cadena correcto para el tipo de relación y
pueda obtener un nombre único (como rId1) para la relación que va a crear:

'*** Create the relationship part


Dim relationshipType As String = _
"http://schemas.openxmlformats.org" & _
"/officeDocument/2006/relationships/officeDocument"
pack.CreateRelationship(uri, TargetMode.Internal, _
relationshipType, "rId1")
pack.Flush()

'*** Close package


pack.Close()

También debe observar la llamada a Flush después de la llamada a CreateRelationship. Esta llamada
fuerza a la API de paquete a actualizar el elemento de relación de paquete con el elemento Relationship
adecuado. La última llamada al método Close del objeto Package termina la serialización del paquete y
libera el identificador de archivo de Hello.docx.
Ya hemos visto todos los pasos para generar un archivo .docx simple desde una aplicación de consola

escrita en Visual Basic® 2005, todo ello disponible aquí. Ahora vamos a escribir código para generar un
archivo .docx en el servidor desde una aplicación ASP.NET.

Generación de archivos DOCX en el servidor


Lo primero que se debe tener en cuenta al modificar código desde una aplicación de consola para que
se ejecute en un servidor Web es que probablemente desee evitar tener que guardar el paquete como
un archivo físico en el sistema de archivos del equipo host. En su lugar, será más rápido simplemente
crear el paquete en una secuencia de memoria del proceso de trabajo de ASP.NET. Posteriormente,
puede volver a escribirlo en el cliente mediante el objeto OutputStream del objeto Response ASP.NET.
Vamos a comenzar cambiando el código para usar un objeto MemoryStream en lugar de un archivo
físico. Examine el código de la figura 6, que se ha agregado a un controlador de eventos de servidor en
una página de ASP.NET 2.0. Tenga en cuenta que el primer parámetro de Package.Open ha cambiado de
una ruta de archivo basada en cadenas a un objeto MemoryStream. Este enfoque le permitirá volver a
usar el mismo código para crear el paquete y sus componentes, tal y como hicimos previamente. No
obstante, no debe preocuparse por la creación y asignación de nombres de un archivo de nivel de SO.
obstante, no debe preocuparse por la creación y asignación de nombres de un archivo de nivel de SO.
Puede que este enfoque ofrezca tiempos de respuesta más breves y un mejor rendimiento en escenarios
de mucho tráfico.

Figure 6 Uso del objeto MemoryStream

‘*** Create in-memory stream as buffer


Dim bufferStream As New MemoryStream()

‘*** Create new package in memory stream


Dim pack As Package = Package.Open( _
bufferStream, FileMode.Create, FileAccess.ReadWrite)

‘*** This calls same code shown in Hello World example


WriteContentToPackage(pack)

‘*** Save/close package object leaving DOCX file in MemoryStream


pack.Close()

‘*** (1) SET UP HTTP HEADERS FOR RESPONSE


‘*** (2) WRITE PACKAGE CONTENT INTO RESPONSE BODY

El código que acabamos de ver crea un objeto MemoryStream y, a continuación, serializa un archivo
.docx en él, simplemente de igual forma que se serializa un archivo .docx en un archivo físico. El código
del método WriteContentToPackage personalizado se tomó directamente del código interno de la
aplicación de consola anterior. No obstante, ahora crea un paquete y lo serializa en un búfer de memoria
en lugar de en un archivo físico.
Una vez escrito el paquete en el objeto MemoryStream y después de llamar a Close en el objeto de
paquete, termina el trabajo con la API de paquete. Todo lo que queda por hacer es configurar los
encabezados HTTP correspondientes y escribir el contenido del paquete en el cuerpo de la respuesta
que se va a devolver al cliente.
Comencemos con los encabezados HTTP. Se debe llamar a los métodos en el objeto de respuesta
ASP.NET para borrar cualquier encabezado existente y para agregar un encabezado contenido-
disposición que especifique un anexo con un nombre de archivo de Hello.docx:

Response.ClearHeaders()
Response.AddHeader("content-disposition", _
"attachment; filename=Hello.docx")

A continuación, debe establecer la codificación y el tipo de contenido MIME para la respuesta HTTP y
después escribir el contenido binario para el paquete en el cuerpo de la respuesta HTTP. Esto se puede
realizar mediante el código que aparece en la figura 7. Observe que las dos últimas llamadas a
Response.Flush y a Response.Close son necesarias para asegurarse de que el paquete completo está
escrito en su totalidad en la respuesta HTTP.

Figure 7 Response.ClearContent

Response.ClearContent()
Response.ContentEncoding = System.Text.Encoding.UTF8
Response.ContentType = &quot;application/vnd.ms-word.document.12&quot;

‘*** Write package to response stream


bufferStream.Position = 0
Dim writer As New BinaryWriter(Response.OutputStream)
Dim reader As New Bina NO RESPONSE YET | ryReader(bufferStream)
writer.Write(reader.ReadBytes(bufferStream.Length))
reader.Close()
writer.Close()
bufferStream.Close()

‘*** flush and close the response object


Response.Flush()
Response.Close()

Siempre que el equipo cliente se ha configurado para comprender el tipo de contenido MIME asociado
a un archivo .docx, al usuario se le presentarán las opciones habituales: abra el documento en Word o
guárdelo en la unidad de disco local.
Si el usuario hace clic en el botón Abrir, el archivo .docx se abre automáticamente en Word como se
muestra en la figura 8. Es interesante observar que en este punto el paquete no se ha guardado nunca
como un archivo físico en el sistema de archivo. Se ha almacenado sólo en memoria, tanto en el servidor
web como en el equipo de escritorio cliente. Si el usuario cierra el documento sin guardarlo, es como si
nunca hubiera existido. Esto convierte a este enfoque en perfecto para la generación de plantillas de
cartas, notas, listas de clientes y cualquier tipo de documento en el que se pueda pensar.
figura 8 documento se abre en Word 2007 (Haga clic aquí para obtener una imagen más grande) (Hacer
clic en la imagen para ampliarla)

Envíe sus preguntas y comentarios a Ted Pattison escribiendo a instinct@microsoft.com.

Ted Pattison, autor y profesor, ha fundado recientemente Ted Pattison Group


(http://www.TedPattison.net), una empresa dedicada a ofrecer educación avanzada adicional a
desarrolladores sobre las tecnologías SharePoint. Ted Pattison también está escribiendo un libro
titulado Inside Windows SharePoint Services 3.0 para Microsoft Press.

Administre su perfil | MSDN Flash en Español | Contacto | Aviso legal


© 2014 Microsoft. Reservados todos los derechos. Términos de uso | Marcas Registradas | Privacidad

También podría gustarte