Os tipos NativeInt e NativeUInt em Delphis pré 2009 #AQuemPossaInteressar

Categoria: Artigos
Categoria Pai: Addicted 2 Delphi!
Acessos: 3767
Imagem meramente ilustrativa

Com este artigo eu pretendo inaugurar uma série de artigos com assuntos bem aleatórios e não programados, os quais eu descubro enquanto estou trabalhando. Serão assuntos que não são capazes de gerar artigos completos por si mesmos, porém, dentro desta série, a qual chamo de "A quem possa interessar", eles serão abordados como "drops", pensamentos rápidos.

O Delphi 2006 não possui o tipo ULONG_PTR e eu precisava desse tipo para poder usar algumas funções de API do Windows. Pesquisei a respeito e, segundo a Microsoft, o tipo ULONG_PTR é um unsigned __int3264.

Para você que só trabalha com Delphi e não entende o que isso significa, eu traduzo: um ULONG_PTR é simplesmente um inteiro, sem sinal, de 32 bits (4 Bytes) ou de 64 bits (8 Bytes) de acordo com a "plataforma". O problema dessa definição reside na palavra plataforma, que pode facilmente ser confundida com Sistema Operacional, ou seja, a "bitagem" do Windows onde o programa será executado, contudo, plataforma diz respeito a compilação.

Em suma, segundo a definição da Microsoft, um ULONG_PTR equivale, no Delphi, a um UInt64 (64 bits, 8 Bytes), caso o programa seja compilado com um compilador para 64 bits, ou equivale a um Cardinal (32 bits, 4 Bytes), caso o programa seja compilado com um compilador para 32 bits.

Com o intuito de ganhar tempo, fui ver como os Delphis mais modernos implementam o tipo ULONG_PTR a fim copiar a solução. Olhei a unit Winodws do Delphi Rio, e lá estava: ULONG_PTR = NativeUInt. Segundo a Embarcadero, um NativeUInt é:

Defines a platform-dependent unsigned integer.

NativeUInt represents a subset of the natural numbers. The range of NativeUInt depends on the current platform. On 32-bit platforms, NativeUInt is equivalent to the Cardinal type. On 64-bit platforms, NativeUInt is equivalent to the UInt64 type.

The size of NativeUInt is equivalent to the size of the pointer on the current platform.

Em outras palavras, caso seu inglês esteja ruim (que vergonha programador!) o que está escrito aí é exatamente a mesma coisa que a Microsoft disse a respeito do tipo __int3264, portanto, não vou nem traduzir!

Novamente aqui se fala em plataforma e aqui, novamente, plataforma diz respeito ao ambiente de compilação e não ao ambiente de execução. Pude comprovar isso no Delphi Rio, compilando um programa de exemplo e retornando o tamanho de NativeUInt, obtendo os seguintes resultados: quando compilado com o compilador para 32 bits, NativeUInt tem 32bits (4 Bytes) e quando compilado com um compilador para 64 bits, NativeUInt tem 64 bits (8 Bytes). Nos dois casos eu rodei o programa de exemplo em um Windows de 64 bits, o que prova que em todas as definições, PLATAFORMA, diz respeito ao ambiente de compilação e não ao ambiente de execução.

Voltando ao problema inicial de ter um tipo ULONG_PTR no Delphi 2006, resolvi simplesmente imitar o que o Delphi Rio faz e simplesmente incluir em uma unit a declaração ULONG_PTR = NativeUInt e com isso tudo que eu precisava compilou corretamente, contudo, ao executar eu obtive erros de parâmetro inválido nas funções de API que eu estava usando.

Eu achava que tudo estava correto quanto ao tipo ULONG_PTR que eu acabara de definir, portanto, nem imaginei que ele fosse o culpado, porém, após algumas investigações mais profundas sem achar o culpado eu resolvi, como forma de teste para descartar problema no ULONG_PTR, compilar no Delphi 2006 o mesmo exemplo que eu compilei no Delphi Rio e tive uma surpresa! No Delphi 2006, que só compila executáveis de 32 bits, o tipo NativeUInt tem 8 Bytes (64 bits)! Ou seja, o Delphi 2006 interpreta erradamente o tipo NativeUInt como sendo um UInt64, e a função de API que eu estava usando esperava um inteiro sem sinal de 32 bits como parâmetro e eis ai o motivo do erro acontecer no Delphi 2006 e não no Delphi Rio. Testes usando um executável compilado no Delphi 2006 em um Windows de 32 bits mostraram o mesmo resultado, provando que o Delphi 2006 de fato estava interpretando o tipo NativeUInt de forma totalmente equivocada!

Ao procurar referências online a respeito de NativeUInt e Delphi 2006, descobri que isso de fato é um bug conhecido e que só foi corrigido no Delphi 2009, portanto, se você possui os Delphis 7, 2005, 2006 ou 2007 o tipo NativeUInt e seu irmão com sinal NativeInt são na verdade sempre inteiros de 64 bits e eu recomendo que não os use, afinal, tipos de dados que dependem de compiladores só fazem sentido quando o Delphi possui suporte a mais de uma plataforma e estes Delphis só compilam para uma plataforma (32 bits).

Para resolver esse problema eu tive que definir o tipo que eu precisava (ULONG_PTR) como sendo DWORD (Cardinal), que tem 32 bits, apenas nas versões de Delphi onde o tipo NativeUInt está bugado. Como todas as versões bugadas são de 32 bits eu não preciso lidar com 64 bits. Eis o trecho de código:

{$IF RTLVersion < 20 }
ULONG_PTR = DWORD;
{$IFEND}

O código acima diz que se eu estiver compilando em qualquer Delphi até o Delphi 2007, o tipo ULONG_PTR deve ser um inteiro sem sinal de 32 bits (DWORD). Para entender a diretiva de compilação RTLVersion que eu usei, leia o artigo Diretivas de compilação e versões do Delphi.

Fontes

Agradecimentos