Archive

Posts Tagged ‘Office’

Fechando WINWORD.EXE ao utilizar o PIA

December 21, 2016 Leave a comment

CENÁRIO:

Cenário bem comum em automação de processos é precisar criar/editar arquivos Office de forma automática e sem iteração do usuário final.

Para isso, podemos usar o Open XML SDK 2.5 para Microsoft Office: https://www.microsoft.com/en-us/download/details.aspx?id=30425.

Mas o Open XML SDK é apenas para os arquivos atuais do Office (pós 2007) que usam o OpenXML em sua concepção (.docx, .xlsx, etc).

Em tempos primórdios, tínhamos que usar o Primary Interop Assemblies (PIA) para trabalhar com arquivos Office via código: https://www.microsoft.com/en-us/download/details.aspx?id=3508.

E o trabalho é BEM MAIS árduo do que usar o Open XML SDK.

ANÁLISE:

E um cenário deveras comum, é encontrar uma aplicação que usa o Interop para manipular arquivos Office consumindo memória e nunca mais devolvendo, criando diversos processos, sem fecha-los após uso.

clip_image002

Cada processo WINWORD.EXE, neste exemplo, consumindo 25Mb de memória. E cada utilização, mais processos, até estourar memória do servidor (ou fechar os processos manualmente).

SOLUÇÃO:

A primeira dica é evitar o uso de “2 pontos” no mesmo “comando”.

Exemplo – Ruim

WordDOC.Document doc = app.Documents.Open(@"c:\teste.doc");

 

Exemplo – Bom

WordDOC.Documents d = app.Documents;

WordDOC.Document doc = d.Open(@"c:\teste.doc");

 

Bom, essa dica vai evitar que sejam criados wrappers em objetos COM que segurem o processo em memória.

A outra dica é sinalizar que os objetos já podem ser finalizados. Após o uso, vá finalizando o uso do objetos regressivamente.

 

using WordDOC = Microsoft.Office.Interop.Word;

Application app = new Application();

WordDOC.Documents d = app.Documents;

object nullobject = Type.Missing;

object doNotSaveChanges = WordDOC.WdSaveOptions.wdDoNotSaveChanges;

try

{

WordDOC.Document doc = d.Open(@"c:\teste.doc");

doc.Activate();

doc.SaveAs(finfo.FullName.Replace(".doc", "_tmp.docx"), WordDOC.WdSaveFormat.wdFormatDocumentDefault);

((Microsoft.Office.Interop.Word._Document)doc).Close(ref doNotSaveChanges, ref nullobject, ref nullobject);

Marshal.FinalReleaseComObject(doc);

Marshal.FinalReleaseComObject(d);

((Microsoft.Office.Interop.Word._Application)app).Quit(ref nullobject, ref nullobject, ref nullobject);

Marshal.FinalReleaseComObject(app);

}

catch (Exception ex)

{

HandleException(ex);

}

 

Dessa forma os objetos serão finalizados quando o GC ocorrer.

Abraço!

Old format or invalid type library. (Exception from HRESULT: 0x80028018 (TYPE_E_INVDATAREAD))

Olá! Smile

Overview:

Manipulando arquivos Office programaticamente, algumas vezes encontramos problemas para começar a fazer alguma coisa.

Cenário:

Neste caso não foi diferente. Logo ao começar a rodar meu código, encontrei um erro e até então um pouco confuso.

Mas então lembrei que já havia passado por isso antes, mas agora resolvi escrever! J

Estou fazendo alguns trabalhos de exportação das informações do Project Server para planilhas Excel, exportando as informações de todos os projetos da empresa em questão.

ERRO:

Meu código cria uma planilha em runtime, e começa a preencher as células com as informações encontradas.

Ao gerar uma nova Workbook, dentro da Application do Excel, usando Interop, o erro abaixo era gerado:

Old format or invalid type library. (Exception from HRESULT: 0x80028018 (TYPE_E_INVDATAREAD)).

Nesta linha:

XLS.Workbook workbook = app.Workbooks.Add(misValue);

SOLUÇÃO:

Com um pouco de pesquisa, descobri que esse erro é gerado por incompatibilidade de idioma entre o Office e as configurações do Windows.

Para resolver o problema, vá até o Control Panel > Regional and Language Settings e altere as configurações para que as configurações de idioma do Windows “casem” com as configurações do Office.

clip_image002

Ou forçe no código o idioma desejado:

XLS.Application app = new XLS.Application();

                //forçando idioma 
                System.Threading.Thread.CurrentThread.CurrentCulture =
                        System.Globalization.CultureInfo.CreateSpecificCulture("en-US");

                XLS.Workbook workbook = app.Workbooks.Add(misValue);
                XLS.Worksheet sheet = (XLS.Worksheet)workbook.Worksheets.get_Item(1);

Abraço!