Há alguns dias, publiquei um post contando o esforço da Microsoft para vencer a resistência dos usuários em trocar o Windows XP pelo novo Windows 7, que ainda nem foi lançado. O foco do esforço descrito lá é o "Modo XP", recurso que permite aos usuários do Windows 7 executarem programas feitos para Windows XP sem correr o risco de incompatibilidade.
No entanto, vi uma notícia hoje explicando que esse recurso se baseia no Virtual PC que, por sua vez, requer tecnologia de virtualização embutida no processador. Ou seja, computadores equipados com processadores Intel ou AMD sem a chamada "virtualization technology" (Intel-VT e AMD-V, respectivamente) não serão capazes de suportar o "Modo XP".
Aqueles que quiserem ou necessitarem usar esse recurso do Windows 7, poderão ter que gastar um dinheiro extra para trocar também o seu hardware. Uma lista dos processadores da Intel, com a indicação se suportam ou não o VT, pode ser encontrada aqui para CPUs de desktop e aqui para CPUs de notebooks. Dos modelos da AMD que ainda estão a venda, apenas o Sempron não possui suporte à virtualização.
Se quiser determinar por software se seu processador possui tal suporte, há um programa chamado SecureAble que é gratuito. Ele exibe algumas informações a respeito de recursos do seu processador que podem afetar a segurança do computador, dentre elas a presença de tecnologia de virtualização baseada em hardware.
Uma outra restrição é que a Microsoft distribuirá o add-on para Modo XP apenas em algumas versões do Windows 7, aquelas mais voltadas ao ambiente corporativo : Professional, Enterprise e Ultimate.
=> Mais Informações
Post sobre lançamento do Windows 7, Site oficial do Windows7, Chips que não suportarão Modo XP, How Many Intel CPUs will fail the XP Mode test ?
7 de maio de 2009
Modo XP no Windows 7 dependerá do hardware
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:
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 :
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:
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.
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';
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 :
Em pascal, o mapeamento seria como segue :
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 ...
.. podem ser assim mapeadas em Pascal :
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.
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;
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;
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);
TWInfo* ObtemInfo (int id);
.. podem ser assim mapeadas em Pascal :
Type TWInfoPtr = ^TWInfo;
procedure FazAlgumaCoisa (AParm : TWInfo); cdecl;
function ObtemInfo (id : integer) : TWInfoPtr; cdecl;
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.
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.