Archive

Posts Tagged ‘SDK’

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!

Advertisements

Value cannot be null – Instanciando OrganizationServiceProxy

December 30, 2015 Leave a comment

Cenário:

Meu primeiro post sobre Microsoft CRM! Smiley de boca aberta

Nas últimas semanas venho trabalhando em análise e melhoria de performance de alguns serviços que fazem integração entre uma aplicação legada e o Microsoft CRM 2015, usando IFD.

Os serviços estão deveras lentos. Nesse processo de análise estamos montando aplicações de testes paralelas aos serviços… e nessas aplicações estamos simulando maneiras diferentes de instanciar o serviço de comunicação com o CRM.

Para isso estou utilizando o SDK do CRM como base de apoio aos testes: http://go.microsoft.com/fwlink/?LinkID=512122.

ERRO:

Value cannot be null.

SOLUÇÃO:

Na correria… acabei copiando e colando uma url que deveria ser diferente!

No SDK do CRM, há um tipo de autenticação se usar os “Helpers” que existem no SDK. Nesse exemplo ele pede para instanciar assim:

 

#region Class Level Members

// To get discovery service address and organization unique name,

// Sign in to your CRM org and click Settings, Customization, Developer Resources.

// On Developer Resource page, find the discovery service address under Service Endpoints and organization unique name under Your Organization Information.

private String _discoveryServiceAddress = "https://MyCompany/XRMServices/2011/Discovery.svc";

private String _organizationUniqueName = "OrganizationUniqueName";

// Provide your user name and password.

private String _userName = "username@mydomain.com";

private String _password = "password";

// Provide domain name for the On-Premises org.

private String _domain = "mydomain";

#endregion Class Level Members

 

E aí ao trocar a url, eu copiei e colei uma url errada… coloquei a url “Organization.svc” ao invés da url correta “Discovery.svc”.

Ao colocar a url errada e tentar instanciar o OrganizationServiceProxy, dá o erro mencionado acima nesse método abaixo:

 

/// <summary>

/// Discovers the organizations that the calling user belongs to.

/// </summary>

/// <param name="service">A Discovery service proxy instance.</param>

/// <returns>Array containing detailed information on each organization that

/// the user belongs to.</returns>

public OrganizationDetailCollection DiscoverOrganizations(

IDiscoveryService service)

{

if (service == null) throw new ArgumentNullException("service");

RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();

RetrieveOrganizationsResponse orgResponse =

(RetrieveOrganizationsResponse)service.Execute(orgRequest);

return orgResponse.Details;

}

 

Após colocar a URL correta “Discovery.svc” , tudo funcionou perfeitamente.

Abraço!