6 de maio de 2009

Chamando funções e classes C++ no Delphi - parte 2

Dando continuidade ao post sobre chamada de código C++ no Delphi, falarei sobre name mangling e como isso influencia na chamada de funções C/C++ dentro do delphi.

Na linguagem C++, é permitido criar funções "sobrecarregadas" (overloaded), isto é, várias funções podem ter o mesmo nome mas ter parâmetros em quantidade e tipos diferentes. Por causa dessa peculiaridade, compiladores C++ incluem "decorações" no nome de todas as funções - sobrecarregadas ou não - de modo a garantir a unicidade desses nomes no código binário final gerado. Normalmente, essa "decoração" significa incluir mnemônicos do tipo de retorno da função e um mnemônico do tipo de cada parâmetro. Veja o exemplo abaixo, tirado do Wikipedia para o C++ da Borland:

Função C++Nome exportado
void funcao(int par1)@funcao$qi
void funcao(int par1, char par2)@funcao$qizc
void funcao(void)@funcao$qv

Então, para mapear uma função C++ no Delphi, precisaremos descobrir o nome com que ela foi exportada na biblioteca DLL e utilizar esse nome na declaração pascal. Suponha que a DLL seja BIBLIO.DLL e as funções são as do exemplo acima. O mapeamento dessas funções em Delphi seria :

procedure funcao1 (par1 : integer);cdecl;
external 'BIBLIO.DLL' name '@funcao$qi';
procedure funcao2(par1 : integer; par2 : char);cdecl;
external 'BIBLIO.DLL' name '@funcao$qizc';
procedure funcao3;cdecl;
external 'BIBLIO.DLL' name '@funcao$qv';

Esse tipo de mapeamento é estático, de forma que as DLLs assim mapeadas são carregadas imediamente, junto com o executável. Se preferir carregar as bibliotecas somente quando forem de fato necessárias, use as funções LoadLibrary e GetProcAddress, lembrando que o nome de função que deve ser passado a essa última é o nome com as "decorações".

Como descobrir o nome modificado pelo compilador e exportado nas bibliotecas é assunto tratado em outro post.

3) Para o caso de ter que usar classes instanciadas do C++ no Delphi, o mapeamento de tipos para os campos deve ser feito da mesma maneira que para estruturas, como mostrado no post anterior. Para as funções virtuais da classe, o mapeamento deve ser feito do mesmo modo que as funções mostrado no post anterior, com uma diferença : deve-se sinalizar ao Delphi que essa função é abstrata, isto é, que essa função será localizável pela tabela de funções virtuais e que o Delphi não deve esperar encontrar a implementação da função nessa classe. Segue exemplo do mapeamento de uma função virtual do C++ no Delphi; este exemplo é utilizado na prática na ABC71, dentro do Gerador de Relatórios:

procedure Preview (aReport : TPtrFolderData);virtual;abstract;

Como a tabela de funções virtuais funciona de forma idêntica no Delphi e no C++, ao invocar essa função ("mensagem", para os puristas) no Delphi, a função que será chamada efetivamente será aquela cujo corpo está codificado na biblioteca C++. Lembre-se que no pascal ela foi declarada como "abstrata" e portanto não tem implementação aí.

Implicações disso que foi exposto nos dois últimos parágrafos : as funções que serão chamadas no Delphi têm que ser virtuais no C++ e o C++ deve disponibilizar uma forma de se obter uma instância da classe, provavelmente através de uma função tipo Create ou do tipo Get.

Por fim, as regras e recomendações são bastante parecidas com isso caso se queira fazer o contrário, isto é, chamar no C++ código feito no Delphi.

5 de maio de 2009

Chamando funções e classes C++ no Delphi

Devido às suas características de linguagem próxima à linguagem de máquina, o C/ C++ é bastante popular entre os desenvolvedores de bibliotecas que buscam - ou precisam de - performance na execução de seus códigos. Basta uma pesquisa no popular site de hospedagem de softwares de código aberto SourceForge para ver a quantidade de projetos em C ou C++, abrangendo as mais diversas áreas : há brokers, servidores web, bibliotecas para renderização de gráficos 3D, tratamento de XML, etc.

Publiquei há alguns dias um texto sobre como encapsular chamadas C++ num código gerenciado (como, por exemplo, C#) mas chamar funções C/C++ ou utilizar classes C++ em Delphi é bem mais simples. Apesar de diferenças óbvias entre as duas linguagens, elas guardam muitas semelhanças que facilitam o intercâmbio. A maioria dos tipos de dados é igual, a tabela de funções virtuais de classes funciona igual, ambas possuem formas compatíveis de modificar o alinhamento de bytes em estruturas e de modificar a ordem da passagem de parâmetros na chamada de funções (esquerda para a direita ou direita para a esquerda).

Vamos por partes : é preciso mapear funções, estruturas e classes do C/C++ para Delphi, isto é, criar um fonte no Delphi com as definições de tipos e funções em pascal com base nos tipos e funções publicados pela biblioteca C/C++.

1) Os tipos de dados atômicos do C/C++ possuem correlatos em pascal. Por exemplo, considere a struct C/C++ abaixo :
typedef struct {
long id;
double qty;
char name [25];
} TWInfo;

Em pascal, o mapeamento seria como segue :
TWInfo = record
id : longint;
qty : double;
name : array [0..24] of char;
end;

Algo importante a ter em mente ao trabalhar com estruturas nessa situação é que há configuração para regular o alinhamento de bytes, isto é, a forma que o compilador determinará onde cada campo da estrutura será armazenado na memória.

2) A passagem de parâmetros para funções tem diferenças entre C e pascal, principalmente na ordem e no lugar em que os parâmetros são empilhados. Assim, as seguintes declarações de funções em C ...

void FazAlgumaCoisa (TWInfo AParm);
TWInfo* ObtemInfo (int id);

.. podem ser assim mapeadas em Pascal :

Type TWInfoPtr = ^TWInfo;
procedure FazAlgumaCoisa (AParm : TWInfo); cdecl;
function ObtemInfo (id : integer) : TWInfoPtr; cdecl;

onde cdecl instrui o compilador do Delphi a chamar essas funções da mesma forma que o C, seguindo a mesma ordem na hora de passar os parâmetros e escolhendo o mesmo local (stack ou registradores).

Para evitar deixar este post muito comprido, deixo para falar sobre a utilização de classes, tabela de funções virtuais e name mangling num próximo post.

4 de maio de 2009

.NET Multiplataforma

Quando foi lançado o framework .NET, um dos desejos declarados da Microsoft era que ele não se restringisse à plataforma Windows. Isto é, que o framework fosse tornado multiplataforma e programas feitos para rodar na CLR (Common Language Runtime) ou, mais precisamente, usando a CLI (Common Language Infrastructure) pudessem ser acessados, por exemplo, em Linux. Claramente, o objetivo era concorrer com o Java pois a Sun os havia impedido de introduzir modificações no Java.

Embora eu não tenha visto ampla divulgação, a Microsoft tem dado passos nesse direção desde 2005, quando submeteu ao ECMA International documento abrindo a especificação da infraestrutura de linguagem. A ECMA é uma espécie de consórcio criado para padronização de tecnologia de comunicação e de informação; abrir a infraestrutura comum das linguagens do .NET por meio desse consórcio abre caminho para que outros possam lançar suas próprias versões do runtime do .NET, permitindo na prática o mesmo tipo de portabilidade de código obtido com o Java.

Ok. Mas, tem alguém desenvolvendo alguma coisa nesse sentido ? Curioso a respeito dessa perspectiva, dei uma garimpada na Internet e localizei o projeto mais promissor : chama Mono e é patrocionado pela Novell.

A versão mais atual do projeto é a 2.4, publicada em março de 2009. De acordo com o site do projeto, http://www.mono-project.com, essa versão implementa funcionalidades que permitem classificá-la como compatível com a versão 2.0 do framework. No entanto, já possui algumas características até do framework 3.5. Também garantem que ela é capaz de executar programas gerados com o Visual Studio sem necessidade de recompilação. Ou seja, se sua aplicação .NET - incluindo aplicações ASP.NET - tem como alvo a versão 2 do framework, você deve executá-la sem problemas com o Mono. E, se faz uso de recursos de versões mais recentes, a Novell disponibiliza uma ferramenta chamada Migration Analyser que indica quais os pontos do seu programa poderão causar problema se executado com o Mono, permitindo compatibilizar seu código.

Há versões do Mono para diversas distribuições de Linux, para Unix, para MAC OS X e até para Windows, embora seja questionável sua utilidade aí, já que é onde a versão da própria Microsoft é distribuida. De acordo com o roadmap existente no site, até mesmo o tratamento completo do Windows Presentation Foundation está previsto.

Confesso que ainda não fiz um teste prático com ele para dar um testemunho confiável sobre a facilidade de portar uma aplicação. Mas assim que testar, farei um novo post para comentar.

=> Mais Informações
Mono Project, Padronização do Common Language Infrastructure (CLI), Plataformas suportadas.

Ganhadores da assinatura digital da "Engenharia de Software"

Quando postei em 24 de abril uma notícia sobre a Conferência de Engenharia de Software a ser realizada pela Devmedia, onde os 10 primeiros comentários ganhariam uma assinatura digital da revista Engenharia de Software (da própria Devmedia) confesso que tive medo. O Blog é muito recente e temi não conseguir 10 visitantes, ainda mais 10 visitantes que estivessem dispostos a registrar um comentário !

Para minha surpresa, antes do fim daquela tarde já tinha se esgotado o limite de comentários e algumas pessoas chegaram a comentar posteriormente ! A todos, agradeço as referências elogiosas e o incentivo pra continuar. Obrigado !

Como promessa é dívida, segue abaixo a lista com os nomes dos 10 ganhadores da assinatura digital da revista Engennharia de Software. A lista está em ordem alfabética mas pode ser encontrada aqui na ordem em que foram postadas :

Adriano Angelo
angeloboss@gmail.com

Anderson Cézar
andersoncezar@hotmail.com

Arnaldo Marinho
arnaldo.marinho@gmail.com

Bruna Paola Villela de Moraes
brunapaolav@gmail.com

Fernando Eugenio Correa
eugenio.fec@gmail.com

Jorge Tonami
jorgetonami@yahoo.com.br

Lidinei Aparecido Bernacci
lidinei.bernacci@gmail.com

Reginaldo José Rodrigues
rodrigues_rj@hotmail.com

Richard
richardscr@gmail.com

Thiago Ramalho
thiago.nramalho@gmail.com


A propósito, o evento Engenharia de Software Conference ocorrerá nos dias 22 e 23 de maio em São Paulo (E-Business Park, na Lapa).

=> Mais Informações
Portal da DevMedia, Engenharia de Software Conference, Programação das Palestras, post sobre o evento.