Atenção: esse artigo tem dois vídeos complementares.
Clique e assista o primeiro!

Clique e assista o segundo!

De se que trata o artigo

Trata da habilidade de acessar componentes .NET a partir do Delphi, ou acessar componentes do Delphi a partir do .NET, acessar serviços web feitos em ambas as linguagens ou ainda trocar mensagens via API do Windows.

Para que serve

Não é possível hoje em dia, com os prazos diminuindo e os requisitos aumentando, criar-se um sistema do zero. Sempre é necessário partir de algo pronto, de um legado, ou comprar e integrar bibliotecas e serviços de terceiros, não importando a tecnologia com que foram feitos.

Em que situação o tema é útil

Em sistemas híbridos, multiplataforma, distribuídos e integrados é extremamente necessário que se reutilizem componentes de software já prontos. Este artigo será útil para todas as ocasiões em que for necessário acessar um Web Service feito em .NET pelo Delphi, acessar uma DLL feita em Delphi pelo .NET, trocar arquivos de texto ou XML entre as duas plataformas, monitorar mensagens na API do Windows ou até fazer com que aplicações se comuniquem diretamente via sockets, onde é necessário interoperabilidade.

Interoperabilidade

Neste artigo são mostradas algumas técnicas de interoperabilidade entre aplicações Delphi Prism (e por extensão C# ou qualquer outra compatível com .NET Framework) e Delphi Win32 nativas. São mostrados métodos de se integrar os dois ambientes via DLLs, via mensagens da API do Windows, via Web Services e outros métodos mais “exóticos”. O objetivo final do artigo é tentar ao máximo criar uma aplicação nova, em .NET, sobre uma aplicação Win32 nativa, aproveitando-se tudo que for possível e com mínimo esforço ou mínimo de alterações na aplicação legada.

Há várias situações em que é necessário integrar ambientes diferentes. As mais comuns são quando uma empresa adquire um conjunto de bibliotecas que não são feitas nativamente na linguagem onde ele deseja usar, por exemplo, compra uma coleção de DLLs feitas em C++ para usar no C#, ou quando a empresa contrata um terceiro apenas para desenvolver a biblioteca. Mais comum ainda são as integrações feitas via Web Services SOAP e via HTTP puro, podendo usar ou não REST e podendo usar ou não XML.

Um importante conceito nesses casos é determinar o que é o componente, entendê-lo como uma caixa preta, criar um programa simples para testá-lo e só então integrá-lo na aplicação principal. Do ponto de vista da aplicação principal esse componente será apenas um método, ou uma unit com um conjunto de métodos.

Para usar DLL é necessário que as funções desta sejam declaradas com stdcall e que se use PChar no lugar de strings. Também é possível usar uma biblioteca do .NET no Delphi. Para isso a biblioteca deve ter um strong name, deve estar no GAC e deve ter a propriedade ComVisible(true) nos parâmetros da biblioteca.

Também é possível a comunicação entre programas e componentes via Web Services, mas, ampliando um pouco os horizontes e pensando mais abstratamente: Web Service é qualquer “site” hospedado na web que fornece um serviço ou funcionalidade. Sendo assim um Web Service não precisa necessariamente seguir o protocolo SOAP, que é bastante extenso, mas pode se beneficiar de qualquer chamada HTTP pura que retorne um XML como resultado.

Outro meio de se implementar a comunicação entre os sistemas é através de troca de mensagens pela API do Windows. Nesta forma o componente ou sistema legado em questão não é um conjunto de DLLs mas sim um programa rodando.

Um ponto muito importante para a integração entre sistemas é a serialização de objetos complexos e estruturas (structs ou records). É possível serializar objetos no formato XML, JSON, Yammel ou TXT. Algumas bibliotecas do Delphi ou do .NET podem auxiliar nesta tarefa, mas esses métodos de serialização podem ser implementados manualmente também. Nem todos os métodos de serialização serão abordados neste artigo.

Comunicação direta via sockets, usando protocolo próprio, pode ser interessante para se passar parâmetros ou objetos serializados entre aplicações. Abstratamente é isso que aplicações DataSnap e Web Services fazem. Em último caso pode-se recorrer ao método mais antigo de todos para integração entre sistemas: troca de arquivos TXT.

DLLs

Assim como o Visual C++ e qualquer outro compilador da Microsoft a direção ou convenção de chamada de métodos é, por padrão, stdcall, herança do C/C++. No Delphi a convenção de chamada utilizada é a FastCall. Nada impediria de mudar isso, mas o que é padrão em um ambiente tem de ser avisado no outro. O que torna isso impossível é o fato de que a convenção FastCall não foi padronizada, tendo sido implementada no Delphi e no .NET/C++ de maneira diferente. Por isso FastCall é incompatível entre Delphi e .NET. Use sempre as convenções padronizadas, dando preferência sempre a stdcall, que é o mais universal.

Nota do DevMan

Convenções de chamada explicam para o sistema, em baixo nível, qual a ordem dos parâmetros de um método, quais serão trazidos dos registradores e quais serão trazidos da memória e “de quem” é a responsabilidade de limpar a pilha: de quem está chamando ou de quem é chamada. A diferença entre stdcall e fastcall é que enquanto stdcall foi padronizado por normas ISO/ANSI, fastcall pode ser implementado diferente de acordo com o fabricante do compilador ou da linguagem. O fastcall do Delphi Win32 não encontra correspondente nas outras linguagens. Para compreender as diferenças entre as convenções de chamada é necessário compreender um pouco de assembly e o conceito de pilha. Enquanto no stdcall a responsabilidade de desempilhar os argumentos ou valores é sempre da função chamada o fastcall tem os primeiros parâmetros armazenados nos registradores do processador enquanto que os subseqüentes ficam na pilha. Como mencionado a implementação de fastcall pode ser diferente de acordo com o compilador e não é aberta, pode ser proprietária. Na convenção stdcall os parâmetros são empilhados na ordem reversa, a função chamada desempilha todos os argumentos quando retorna, dados primitivos são retornados no registrador EAX ou nos registradores EAX:EDX e estruturas de até 8 bytes são retornadas no par EAX:EDX. Já o fastcall usa os registradores para os quatro primeiros argumentos e a pilha para os subsequentes. Entende-se por função chamadora a que está por fora, que faz a chamada e por função chamada aquela que é executada dentro de uma chamadora. Em um exemplo hipotético caso o Delphi usasse por padrão stdcall, se no evento onClick do button1 é executada a função ShowMessage(‘hello world’) então a ShowMessage é a chamada e button1Click é a chamadora. ShowMessage teria a obrigação de desempilhar o parâmetro ‘Hello World’.

...

Quer ler esse conteúdo completo? Tenha acesso completo