O compartilhamento de informações através de arquivos corresponde a um tipo de prática bastante difundido dentro do ambiente corporativo. Contratos, formulários de requisição, manuais de instruções, recibos e comprovantes financeiros são apenas alguns exemplos de arquivos comumente associados a processos desse gênero.

Por mais que soluções como o Microsoft Office e o Open Office contem com uma larga aceitação de mercado, as inúmeras versões destas, além das mais diversas configurações em computadores e em impressoras, podem ocasionar uma série de dificuldades aos usuários destes aplicativos. Tais problemas são particularmente frequentes com documentos do Microsoft Word: erros na abertura de arquivos ou ainda, a necessidade de reformatar todo um texto (corrigindo assim problemas com quebras de páginas), representam alguns tipos de ocorrências extremamente comuns neste sentido.

Diante disso, alguns formatos de arquivos foram desenvolvidos, tendo como objetivo principal viabilizar a criação de documentos que não estejam sujeitos a variações decorrentes do aplicativo utilizado, do equipamento voltado à impressão ou, até mesmo, do próprio sistema operacional empregado. Quando se considera a necessidade de criação de arquivos compatíveis com as principais plataformas de software e hardware, os padrões PDF e XPS são, sem sombra de dúvidas, as opções mais populares.

O formato PDF (sigla do inglês “Portable Document Format”) é de autoria da Adobe, tendo sido criado ainda na década de 1990. Esse padrão permite a geração de arquivos de extensão .pdf e dotados de um layout fixo (o qual evita com isso prováveis problemas de impressão), sendo que tais documentos englobam texto com diferentes fontes, imagens, índices, dentre outros elementos voltados à visualização de informações. Além disso, é possível ainda que recursos de compactação sejam empregados na geração de um documento PDF, de forma a se reduzir com isto o tamanho final do arquivo em questão.

Já o formato XPS (abreviação do inglês “Open XML Paper Specification”) foi concebido pela Microsoft, com o lançamento de sua primeira versão acontecendo no final de 2006. Arquivos gerados neste padrão possuem a extensão .xps, contando com uma estrutura bastante similar àquela adotada em documentos .pdf (layout fixo, inclusão de texto, imagens e outros elementos num mesmo arquivo, compactação das informações etc.). As diferenças mais significativas estão, neste último caso, no uso de elementos da especificação XML para a organização dos diferentes itens que compõem o conteúdo de um arquivo.

Considerando especificamente o Microsoft Word, este aplicativo conta com opções para a conversão de arquivos com a extensão .docx ou .doc para construções equivalentes nos padrões PDF ou XPS. Trata-se, portanto, de um recurso bem útil, sobretudo quando da necessidade envio de documentos respeitando-se aspectos de formatação como fontes, disposição de texto e imagens, quebras de páginas etc.

Sistemas voltados às mais variadas finalidades podem também “se comunicar” com o Microsoft Word, a fim de utilizar a funcionalidade de exportação para de documentos para outros formatos aqui citada ou ainda, consumir outros recursos disponibilizados por este processador de textos. O mecanismo que permite isto em soluções elaboradas com o .NET Framework é chamado de Interop, baseando-se no padrão COM (Component Object Model).

Sobre a tecnologia COM, é importante destacar que a mesma foi concebida pela própria Microsoft, tendo como objetivo principal oferecer alternativas para a interoperabilidade entre sistemas dentro da plataforma Windows.

Uma técnica comum em muitas aplicações consiste na criação de arquivos do Word que funcionam como templates, com essas estruturas sendo empregadas posteriormente na geração de novos arquivos, tomando por base dados manipulados por tais softwares. Isso abre caminho para a geração de documentos com uma formatação mais sofisticada e que, muito provavelmente, seria difícil de ser obtida com um gerador de relatórios convencional ou, até mesmo, por meio do uso de Interop com a criação de um documento “do zero”.

O objetivo deste artigo é demonstrar como utilizar Interop na conversão de documentos do Word para arquivos .pdf ou .xps. Isto será feito através de um projeto de testes, em que estarão detalhados os diversos recursos necessários à implementação de funções deste tipo.

Criando a aplicação de exemplo

A solução que está sendo apresentada neste artigo foi criada no .NET framework 4.5, através da utilização do Microsoft Visual Studio 2012 Professional.

Para gerar o projeto de testes será necessário, dentro do Visual Studio, acessar o menu File, opção New, sub opção Project. Dentro da tela New Project (Figura 1) selecionar o template Windows Forms Application, informando no campo Name o nome da aplicação a ser gerada (“TesteConversaoDocumentos”, neste caso); no campo Location é possível ainda definir o diretório no qual serão criados os arquivos para este projeto.

Criando um projeto Windows Forms para testes

Figura 1: Criando um projeto Windows Forms para testes

Configurando a utilização da biblioteca COM do Word no projeto

Para que seja possível a utilização de recursos do Microsoft Word no projeto de testes, será necessário adicionar uma referência à biblioteca COM do Microsoft Word.

Dentro do Solution Explorer, este procedimento pode ser realizado clicando com o botão direito sobre o item "References" de um projeto e selecionando na sequência a opção "Add Reference..." (conforme indicado na Figura 2).

Adicionando uma referência a um projeto de testes

Figura 2: Adicionando uma referência a um projeto de testes

Aparecerá então a janela “Reference Manager”. Selecionar do lado esquerdo o item “COM”; localizar agora a biblioteca “Microsoft Word 12.0 Object Library” e selecionar a mesma (Figura 3). Acionar finalmente o botão “OK”, de maneira que a referência seja incluída no projeto Windows Forms.

OBSERVAÇÃO: o exemplo apresentado neste artigo baseou-se na biblioteca COM do Microsoft Word 2007 (“Microsoft Word 12.0 Object Library”). Em um computador que possua o Word 2010 instalado, deverá ser adicionada uma referência à biblioteca “Microsoft Word 14.0 Object Library”, a fim de possibilitar com isto a utilização dos recursos necessários à conversão de documentos.

Adicionando ao projeto uma referência à biblioteca COM do Word

Figura 3: Adicionando ao projeto uma referência à biblioteca COM do Word

Criação das classes utilizadas na conversão de documentos

Com o projeto TesteConversaoDocumentos criado e a referência à biblioteca COM já adicionada ao mesmo, será necessário prosseguir com a implementação das classes empregadas na conversão de documentos do Word para arquivos nos formatos PDF ou XPS. O primeiro destes tipos será chamado de “ArquivoWord”.

A fim de gerar o arquivo necessário à codificação da classe ArquivoWord, clicar dentro do Solution Explorer com o botão direito do mouse sobre a aplicação TesteConversaoDocumentos, escolhendo em seguida no menu de atalho a opção Add, sub opção New Item. Neste momento será exibida a tela Add New Item (Figura 4); preencher o campo Name com “ArquivoWord.cs”.

Criando o arquivo para implementação da classe ArquivoWord

Figura 4: Criando o arquivo para implementação da classe ArquivoWord

O tipo ArquivoWord (Listagem 1) corresponde a um arquivo do Word (extensão .docx ou .doc), sendo que por meio do mesmo será possível a geração de um documento equivalente nos formatos PDF ou XPS.

O construtor de ArquivoWord recebe como dado de entrada o caminho do arquivo a ser convertido (parâmetro “caminhoArquivoWord”). Uma instância do aplicativo Microsoft Word será disponibilizada em memória (atributo “_word”), com isto acontecendo através da criação de um objeto do tipo Application (namespace Microsoft.Office.Interop.Word). Já o atributo de nome “_doc” conterá uma referência para a classe Document, a qual representa um documento do Word.

Estruturas que dependam de ArquivoWord farão uso dos seguintes métodos:

  • ConverterArquivo: operação que recebe o nome do arquivo que será gerado como resultado do processo de conversão (parâmetro “caminhoArquivoConvertido”), além de um flag que determina se o arquivo será ou não um documento PDF (parâmetro “conversaoPDF”); caso este último valor seja false, será criado um arquivo no padrão XPS. Ainda sobre o funcionamento da operação ConverterArquivo, será a operação SaveAs da classe Document (namespace Microsoft.Office.Interop.Word) que transformará um arquivo comum do Word (extensão .docx ou .doc) numa construção equivalente baseada nas especificações PDF ou XPS;
  • FecharArquivo: finaliza a utilização do documento, liberando a instância do Word que se encontrava ativa na memória do computador em questão (invocando o método Quit a partir do objeto do tipo Application).

Quanto aos demais aspectos considerados na definição da classe ArquivoWord, foram tomadas precauções para evitar que instâncias do Microsoft Word fiquem perdidas na memória (sem terem sido desalocadas), consumindo recursos de forma desnecessária. Assim, merecem ser destacadas ainda as seguintes características na implementação do tipo ArquivoWord:

  • Está sendo implementada a interface IDisposable. Estruturas que manipulem recursos ditos como “não-gerenciáveis” (ou seja, que não são nativos do .NET Framework, justamente o caso da utilização de COM/Interop) devem derivar desta interface, a fim de que o Garbage Collector invoque o método Dispose; esta última operação representa o local em que os recursos serão liberados;
  • Todas as instâncias de objetos do Word têm o valor null associado às suas referências, com isto acontecendo ao término de sua utilização. Esse é o caso do método LiberarProcessoWord, o qual é acionado pelas operações FecharArquivo e Dispose (esta última seria disparada num último instante pelo Garbage Collector, se algum erro em um momento qualquer impedir uma chamada a FecharArquivo);
  • Dentro de LiberarProcessoWord é executado ainda o método Quit sobre o objeto do tipo Application, além de chamadas a outro método de nome ReleaseComObject (o qual recebe como parâmetro cada uma das instâncias criadas anteriormente);
  • A operação ReleaseComObject faz uso do método estático ReleaseComObject da classe Marshal (namespace System.Runtime.InteropServices), visando com isso desalocar a memória dos objetos COM que haviam sido gerados previamente.

Listagem 1: Classe ArquivoWord


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Word = Microsoft.Office.Interop.Word;

namespace TesteConversaoDocumentos
{
    public class ArquivoWord : IDisposable
    {
        private Word.Application _word;
        private Word.Document _doc;

        public ArquivoWord(string caminhoArquivoWord)
        {
            _word = new Word.Application();
            _doc = _word
                .Documents.Open(caminhoArquivoWord);
            _doc.Activate();
        }

        public void ConverterArquivo(
            string caminhoArquivoConvertido,
            bool conversaoPDF)
        {
            Word.WdSaveFormat formato;
            if (conversaoPDF)
                formato = Word.WdSaveFormat.wdFormatPDF;
            else
                formato = Word.WdSaveFormat.wdFormatXPS;
            _doc.SaveAs(caminhoArquivoConvertido, formato);
        }

        public void FecharArquivo()
        {
            // Fecha o arquivo do Word aberto anteriormente
            _doc.Close();
            LiberarProcessoWord();
        }

        public void Dispose()
        {
            LiberarProcessoWord();
        }

        private void LiberarProcessoWord()
        {
            // Libera objeto relacionado ao arquivo que
            // está sendo manipulado
            ReleaseComObject(_doc);
            _doc = null;

            // Encerra a instância do Word
            _word.Quit();
            ReleaseComObject(_word);
            _word = null;
        }

        private void ReleaseComObject(object o)
        {
            // Liberar instância do Interop
            if (o != null)
                System.Runtime.InteropServices
                    .Marshal.ReleaseComObject(o);
        }
    }
}

Na Listagem 2 está a implementação da classe estática WordHelper. Esse tipo será responsável pela conversão de arquivos do Word, empregando para isto instâncias da classe ArquivoWord. Para a criação do arquivo em que ficará o código-fonte do tipo WordHelper, seguir os mesmos procedimentos já descritos anteriormente para ArquivoWord.

Caberá aos métodos públicos GerarArquivoPDF e GerarArquivoXPS invocar a operação privada ProcessarConversaoArquivo, a fim de que com isso sejam geradas, respectivamente, versões em PDF e XPS a partir de documentos do Word (por meio de uma referência baseada em ArquivoWord).

No que se refere ao método ProcessarConversaoArquivo, a manipulação da instância da classe ArquivoWord está sendo feita dentro de um bloco try-finally. Ocorrendo ou não problemas, a referência que estaria associada à variável de nome “arquivo” é liberada (definindo-se null como valor da mesma). Em seguida são invocadas as seguintes operações da classe GC (a qual representa o Garbage Collector):

  • Collect: força a execução do Garbage Collector, com a intenção de garantir a liberação de recursos;
  • WaitForPendingFinalizers: suspende o processamento atual, aguardando a execução do mecanismo de Garbage Collector.

Listagem 2: Classe WordHelper


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TesteConversaoDocumentos
{
    public static class WordHelper
    {
        private static void ProcessarConversaoArquivo(
            string caminhoArquivoWord,
            string caminhoArquivoConvertido,
            bool conversaoPDF)
        {
            ArquivoWord arquivo = null;

            try
            {
                arquivo = new ArquivoWord(caminhoArquivoWord);
                arquivo.ConverterArquivo(
                    caminhoArquivoConvertido, conversaoPDF);
                arquivo.FecharArquivo();
            }
            finally
            {
                arquivo = null;

                // Libera objetos da memória e não mais em
                // uso até este ponto
                System.GC.Collect();
                System.GC.WaitForPendingFinalizers();
            }
        }

        public static void GerarArquivoPDF(
            string caminhoArquivoWord,
            string caminhoArquivoConvertido)
        {
            ProcessarConversaoArquivo(
                caminhoArquivoWord,
                caminhoArquivoConvertido,
                true);
        }

        public static void GerarArquivoXPS(
            string caminhoArquivoWord,
            string caminhoArquivoConvertido)
        {
            ProcessarConversaoArquivo(
                caminhoArquivoWord,
                caminhoArquivoConvertido,
                false);
        }
    }
}

Implementando a tela para conversão de arquivos

Concluída a implementação das classes responsáveis pela conversão de documentos, será preciso agora renomear o formulário principal da aplicação. Isto é feito, dentro da janela Solution Explorer, clicando com o botão direito sobre o arquivo Form1.cs e selecionando a opção Rename: alterar então este nome de arquivo para FormPrincipal.cs. Tal procedimento fará com que a identificação da classe que corresponde ao formulário principal da aplicação também passe a ser FormPrincipal. Além disso, modificar por meio da janela Properties do Visual Studio a propriedade Text de FormPrincipal para “Teste de Conversão de Documentos do Word”.

Adicionar a este formulário os controles que se encontram listados na Tabela 1.

Tipo do ControleNome do Controle
LabellblArquivoAConverter
TextBoxtxtArquivoAConverter
ButtonbtnSelecionarArquivo
ButtonbtnConverter
ButtonbtnCancelarUpload
OpenFileDialogopenDialogArquivoWord
SaveFileDialogsaveDialogArquivoDestino

Tabela 1: Controles a serem adicionados ao formulário FormPrincipal

Já a Tabela 2 lista algumas propriedades dos componentes adicionados a FormPrincipal que precisarão ser alteradas.

Nome do ControlePropriedadeValor
lblArquivoAConverterTextArquivo a ser convertido:
txtArquivoAConverterReadOnlyTrue
btnSelecionarArquivoText...
btnConverterText&Converter
btnSairTextSai&r
openDialogArquivoWordFileNameEm branco (sem nenhum conteúdo)
openDialogArquivoWordFilterArquivo do Word 2007-2010 (*.docx)|*.docx|Arquivo do Word 97-2003 (*.doc)|*.doc
saveDialogArquivoDestinoSaveFileDialogArquivo PDF (*.pdf)|*.pdf|Arquivo XPS (*.xps)|*.xps

Tabela 2: Propriedades a serem alteradas nos controles adicionados a FormPrincipal

OBSERVAÇÃO: Para efeitos de simplificação, serão omitidos deste artigo os valores de propriedades de controles que definam tamanhos (Size, por exemplo) ou posicionamento (Location, por exemplo).

A Figura 5 demonstra um exemplo, em termos gerais, de como poderá ficar o formulário FormPrincipal ao término da configuração dos controles adicionados ao mesmo. Esta imagem foi gerada dentro do Visual Studio, a partir do editor visual desta ferramenta.

Formulário FormPrincipal em modo Design com todos os controles já configurados

Figura 5: Formulário FormPrincipal em modo Design com todos os controles já configurados

Por fim, na Listagem 3 é apresenta o código-fonte que define as funcionalidades de FormPrincipal. É possível observar neste último a existência dos seguintes métodos:

  • btnSelecionarArquivo_Click: evento que é acionado ao se clicar no botão “btnSelecionarArquivo”, de maneira que se abra uma tela em que deverá ser escolhido um documento do Word (via componente OpenFileDialog);
  • ValidarInformacoesArquivoSelecionado: determina se realmente um arquivo foi selecionado para conversão e, em caso afirmativo, se o mesmo é um documento válido do Microsoft Word (extensões .docx e .doc);
  • VerificarGeracaoArquivoDestino: solicita ao usuário que escolha o nome e o tipo do arquivo de destino (com novas validações), a fim de executar o processo de transformação de um documento para o equivalente nos formatos PDF ou XPS;
  • btnConverter_Click: evento Click do botão “btnConverter”. Faz uso dos dois métodos descritos anteriormente (ValidarInformacoesArquivoSelecionado e VerificarGeracaoArquivoDestino), checando primeiramente se o arquivo selecionado é válido e, após isto, processando a conversão deste item;
  • btnSair_Click: evento disparado quando se clica no botão “btnSair”.

Além da classe WordHelper, a implementação de FormPrincipal faz também faz uso dos tipos File e FileInfo (ambos definidos em System.IO).

Listagem 3: Classe FormPrincipal


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

namespace TesteConversaoDocumentos
{
    public partial class FormPrincipal : Form
    {
        public FormPrincipal()
        {
            InitializeComponent();
        }

        private void btnSelecionarArquivo_Click(
            object sender, EventArgs e)
        {
            if (openDialogArquivoWord.ShowDialog() ==
                DialogResult.OK)
            {
                txtArquivoAConverter.Text =
                    openDialogArquivoWord.FileName;
            }
        }

        private bool ValidarInformacoesArquivoSelecionado()
        {
            if (String.IsNullOrWhiteSpace(
                txtArquivoAConverter.Text))
            {
                MessageBox.Show(
                "É necessário selecionar um arquivo para conversão.");
                return false;
            }

            if (!File.Exists(txtArquivoAConverter.Text))
            {
                MessageBox.Show(
                    "O caminho de arquivo selecionado é inválido.");
                return false;
            }

            string extensaoDocumento = new FileInfo(
                txtArquivoAConverter.Text).Extension.ToLower();
            if (extensaoDocumento != ".docx" &&
                extensaoDocumento != ".doc")
            {
                MessageBox.Show(
                    "É necessário selecionar um arquivo do Word " +
                    "(extensão .docx ou .doc).");
                return false;
            }

            return true;
        }

        private void VerificarGeracaoArquivoDestino()
        {
            string arquivoDestino =
                saveDialogArquivoDestino.FileName;
            string extensaoDocumento = new FileInfo(
                arquivoDestino).Extension.ToLower();
            if (extensaoDocumento != ".pdf" &&
                extensaoDocumento != ".xps")
            {
                MessageBox.Show(
                    "O arquivo de destino precisa possuir as " +
                    "extensões .pdf ou .xps.");
                return;
            }

            if (File.Exists(arquivoDestino))
            {
                MessageBox.Show(String.Format(
                    "Impossível prosseguir. " +
                    "Já existe outro arquivo com este nome ({0}).",
                    arquivoDestino));
                return;
            }

            if (extensaoDocumento == ".pdf")
            {
                WordHelper.GerarArquivoPDF(
                    txtArquivoAConverter.Text,
                    arquivoDestino);
            }
            else
            {
                WordHelper.GerarArquivoXPS(
                    txtArquivoAConverter.Text,
                    arquivoDestino);
            }

            MessageBox.Show(String.Format(
                "O arquivo {0} foi gerado com sucesso.",
                saveDialogArquivoDestino.FileName));
        }

        private void btnConverter_Click(
            object sender, EventArgs e)
        {
            if (!ValidarInformacoesArquivoSelecionado())
                return;

            if (saveDialogArquivoDestino.ShowDialog() ==
                DialogResult.OK)
            {
                VerificarGeracaoArquivoDestino();
            }
        }

        private void btnSair_Click(object sender, EventArgs e)
        {
            Close();
        }
    }
}

Executando a aplicação de testes

Iniciando a execução da solução implementada neste artigo, será apresentada uma tela como aquela que consta na Figura 6.

Projeto TesteConversaoDocumentos em execução

Figura 6: Projeto TesteConversaoDocumentos em execução

Acionando o botão para a seleção de um documento do Word, aparecerá então uma janela similar à que consta na Figura 7.

Selecionando um documento do Word

Figura 7: Selecionando um documento do Word

Escolhendo um documento, o usuário será direcionado novamente para a tela inicial (neste momento o campo “Arquivo a ser convertido” já estará preenchido), conforme indicado na Figura 8.

Documento do Word já selecionado

Figura 8: Documento do Word já selecionado

Clicando sobre o botão “Converter”, será solicitado que se defina o nome do arquivo de destino. Neste primeiro caso, será um documento no formato .pdf (Figura 9). Ao se acionar o botão “Salvar”, ocorrerá a conversão para o padrão PDF, com a exibição de uma mensagem quando esse processo estiver concluído (Figura 10).

Definindo o nome do documento PDF que será gerado

Figura 9: Definindo o nome do documento PDF que será gerado

Conversão para um documento PDF concluída

Figura 10: Conversão para um documento PDF concluída

Indo até o local em que o documento PDF foi salvo (Figura 11), será possível abrir o mesmo a fim de se visualizar o seu conteúdo (Figura 12).

Documento PDF já salvo

Figura 11: Documento PDF já salvo

Visualizando o documento PDF gerado a partir de um arquivo do Word

Figura 12: Visualizando o documento PDF gerado a partir de um arquivo do Word

Repetindo o mesmo procedimento adotado com a geração de PDFs, a Figura 13 apresenta um exemplo de arquivo XPS baseado no mesmo documento do Word utilizado anteriormente.

Visualizando documento XPS gerado a partir de um arquivo do Word

Figura 13: Visualizando documento XPS gerado a partir de um arquivo do Word

Conclusão

Este artigo procurou demonstrar como é possível a conversão de documentos do Word para os formatos PDF ou XPS, partindo da utilização de recursos próprios do pacote Office (desde que tomados diversos cuidados no que se refere a liberar da memória o que havia sido carregado previamente).

É importante mencionar também que existem soluções comerciais que cumprem este objetivo, sem depender do mecanismo conhecido como Interop para a transformação de arquivos do Word em uma estrutura baseada num formato fixo. Contudo, nem sempre este tipo de opção poderá ser adotado em um projeto, seja por um orçamento restritivo ou ainda, por resistência de alguns profissionais em depender de componentes de terceiros.

Espero que o conteúdo aqui apresentado possa ser útil no seu dia-a-dia. Até uma próxima oportunidade!