quarta-feira, 9 de fevereiro de 2011

Chamando Componentes .NET no PowerBuilder - Via COM Wrappers

Artigo publicado em 11 de janeiro de 2011, no “Developers`s Powerbuilder journal”
Traduzido e adaptado por: Blog powerbuilder Brasil

Já escrevi inúmeros artigos sobre como usar componentes .NET, visuais e não visuais, em aplicações Win32 do PowerBuilder Clássico. Até então, todos eles envolviam componentes .NET originados do .NET Framework ou criados no Visual Studio. O que muda com o PowerBuilder 12 é que agora é possível escrever um componente não visual utilizando o PowerBuilder.NET, e a solução fica inteiramente baseada na plataforma PowerBuilder.
Tecnicamente, isso se tornou possível desde a introdução do target .NET assembly, no PowerBuilder 11. No entanto, há duas questões a serem observadas naquela abordagem:
  1. O PowerBuilder 11 (assim como o 11.5) não possuía um ambiente CLR, e referenciar classes .NET de objetos não visuais usados para criar o assembly requeria o uso de blocos de códigos condicionais, com suas próprias limitações (principalmente a falta de autoscripting, validação de script e uma pobre documentação da sintaxe).
  2. O PowerBuilder 11 (assim como o 11.5) gerava assemblies que não eram marcados como “COM visible”, um pré-requisito para que estes pudessem ser acessados via “COM Callable Wrappers” (CCW) pelas aplicações PowerBuilder Win32. Existe a possibilidade de forçar esta marcação, por exemplo, usando o ILDASM (IL disassembler) para decompilar o assembly, modificar o código decompilado e depois re-compilar com o ILASM. Este método, no entanto, está longe de ser ideal.
Com o PowerBuilder.NET, no PowerBuilder 12, temos um completo ambiente CLR PowerScript, totalmente suportado pelo autoscripting, validação de script e uma documentação de sintaxe melhor. Além disso, os assemblies gerados pelo PowerBuilder.NET são marcados como “COM visible”, por isso torna-se muito mais fácil utilizá-los em aplicações Win32 via CCW.

Criando o Assembly
Vamos implementar uma chamada à classe SMTPClient do .NET Framework como fizemos em exemplos anteriores, porém agora vamos fazer isso diretamente utilizando PowerScript, no PowerBuilder.NET:

System.Net.Mail.MailMessage myMailMessage
SmtpClient mySTMPClient
Attachment myAttachment
Exception ex

myMailMessage = create System.Net.Mail.MailMessage
mySTMPClient = create SmtpClient(iHost)

myMailMessage.From = create System.Net.Mail.MailAddress(iFrom)
myMailMessage.To.Add(iTo)
myMailMessage.Subject = iSubject
myMailMessage.IsBodyHtml = iIsHTML
myMailMessage.Body = iBody

if not IsNull(iCC) and iCC <> “” then
     myMailMessage.CC.Add(iCC)
end  if

choose case iSendUsing
case 0
     mySTMPClient.DeliveryMethod = SmtpDeliveryMethod.Network!

case  1
     mySTMPClient.DeliveryMethod = SmtpDeliveryMethod.PickupDirectoryFromIis!

case  2
     mySTMPClient.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory!

end choose

if iAuthenticationMode > 0 then
     mySTMPClient.Credentials = create NetworkCredential(iUser,iPassword)
end  if

mySTMPClient.Port = iPort

mySTMPClient.EnableSsl = iUseSSL

//Anexos
if not isNull(iAttachmentPath) and iAttachmentPath <> “” then
     myAttachment = create Attachment(iAttachmentPath)
     myMailMessage.Attachments.Add(myAttachment)
end if

//Envia a mensagem
mySTMPClient.Send(myMailMessage)


Este código é uma adaptação do código que Dave Fish utilizou para uma de suas sessões na TechWave 2010. Existem algumas variáveis de instância, indicadas pelo prefixo "i", como iSubject, iIsHTML e iBody. Como o PowerBuilder.NET não suporta propriedades na geração de assemblies .NET, tivemos que implementar métodos set no assembly para atribuir valores às variáveis de instância. Por serem triviais não vamos listar os códigos destes métodos neste artigo.
Agora que temos um objeto não visual com os métodos set, criamos um projeto do tipo .NET assembly para que o PowerBuilder possa gerar o objeto não visual como um assembly (veja as figuras abaixo). Executando o projeto, teremos cumprido parte do nosso objetivo.



Criando as Entradas de Registro CCW para o Assembly
Agora que temos nosso próprio assembly .NET, temos que criar as entradas de registro que a aplicação desenvolvida no PowerBuilder Clássico vai utilizar para consumir o assembly. Também poderíamos utilizar um arquivo manifest ao invés de entradas de registro, como já expliquei em outro artigo numa edição anterior do PBDJ (Developer`s PowerBuilder Journal). No entanto, nesta demonstração iremos utilizar entradas de registro.
O caminho que você deve seguir é executar a ferramenta REGASM, do .NET SDK, no assembly. No nosso exemplo, o nome dado ao assembly foi PBSmtpClient.dll, então devemos executar o REGASM no assembly conforme a linha de comando abaixo:
REGASM  PBSmtpClient.dll /regfile:PBSmtpClient.reg
Caso você execute o REGASM diretamente no assembly sem definir nenhum parâmetro, as entradas serão automaticamente adicionadas ao registro da máquina onde você tiver executado. Mas por duas razões você deve gerar as entradas em um arquivo registry (.REG) e incorporá-las depois. A primeira razão é que você poderá precisar deste arquivo .REG (e das informações nele contidas) para executar o assembly em outras máquinas.
A segunda razão é específica para sistemas operacionais de 64 bits, tal como a versão 64 bits do Windows 7. Quando você executa o REGASM em um assembly num sistema operacional de 64 bits, ele cria apenas as entradas de registro necessárias para aplicações de 64 bits. Você precisa então fazer um trabalho de “copiar e colar” para adicionar as informações necessárias às aplicações de 32 bits, como as aplicações desenvolvidas no PowerBuilder Clássico. O que você vai fazer é abrir o arquivo, copiar e colar as entradas de registro, duplicando-as. Então, para o segundo bloco (o que foi duplicado), procure por HKEY_CLASSES_ROOT e substitua este termo por HKEY_CLASSES_ROOT\Wow6432Node. O termo “Wow6432Node” é a sub-chave de todas as principais chaves de registro que contém entradas utilizadas por aplicações de 32 bits.
Por exemplo, a primeira entrada no arquivo seria algo do tipo:
[HKEY_CLASSES_ROOT\PBSmtpClient.SmtpClient]
@="PBSmtpClient.SmtpClient"
Feita a cópia e a substituição, deverá existir uma entrada adicional no arquivo, conforme abaixo:
[HKEY_CLASSES_ROOT\Wow6432Node\PBSmtpClient.SmtpClient]
@="PBSmtpClient.SmtpClient"

Uma vez feito isso (considerando que você está em um sistema de 64 bits), dê um duplo-clique no arquivo .REG para que o Windows adicione a informação ao registro. Caso você esteja em um sistema de 32 bits, execute diretamente o arquivo gerado pelo REGASM, sem nenhuma modificação.

Chamando o Assembly no PowerBuilder Clássico

Depois que as entradas de registro já foram adicionadas ao registro do Windows, a aplicação PowerBuilder já pode acessar o assembly como se fosse um componente COM padrão, utilizando automação OLE. O código é praticamente o mesmo que nós utilizamos em exemplos anteriores, quando tratamos de assemblies gerados no Visual Studio:

integer             li_rc
oleobject          smtp
smtp = CREATE oleobject
li_rc = smtp.ConnectToNewObject ( "PBSmtpClient.SmtpClient" )
smtp.SetFrom ( "first.last@domain.com" )
smtp.SetTo ( "bruce.armstrong@teamsybase.com" )
smtp.SetSubject ( "Test" )
smtp.SetBody ( "This is only a test" )
smtp.SetHost ( "mail.domain.com" )
smtp.SendMessage()
smtp.DisconnectObject()
Destroy smtp

Considerações Finais

Existem algumas limitações para esta abordagem, como já relatei em minha sessão na TechWave 2008, principalmente relacionadas à captura de informações de erros de exceções lançadas pelo assembly (eu também direcionei naquela sessão o caminho para solucionar estes problemas). Desta forma, esta técnica deve ser bastante útil para aquelas aplicações onde a quantidade de chamadas que você precisa fazer para classes .NET é limitada o suficiente para que a migração completa para WinForm ou WPF não se justifique. O uso desta técnica permite que você mantenha sua aplicação no PowerBuilder Clássico, adicionando funcionalidades.NET conforme necessário.

Nenhum comentário:

Postar um comentário