23 de junho de 2009

Obtendo informações da CPU em Delphi

Publiquei em Maio um post a respeito da obtenção do MAC Address em Delphi para gerar um código que identificasse um computador de forma única. Naquela ocasião, sugeri que se incluisse informações sobre a CPU para melhorar o código obtido. Então, vou mostrar aqui como obter essas informações.

A primeira coisa a saber é que as informações sobre a CPU são obtidas através de uma instrução assembly chamada CPUID. Prepare a escova de bits!

A instrução CPUID usa o registrador EAX para determinar que tipo de informação deve ser retornado. Por exemplo, quando o EAX está com valor 0 (zero), CPUID retorna um texto de 12 caracteres com a identificação do fabricante da CPU. No exemplo que segue, uso o comando ASM do Delphi para submeter as instruções assembly.
var VendorID : array[0..12] of char;
begin
Asm
// Isso faz com que EAX tenha valor zero
XOR EAX, EAX

// Chama a instrução CPUID
CPUID

// Retorna 4 caracteres em cada um
// dos registradores EBX, EDX e ECX,
// totalizando 12 caracteres do ID
// do fabricante.
MOV dword ptr [VendorID], EBX
MOV dword ptr [VendorID+4], EDX
MOV dword ptr [VendorID+8], ECX
end;
// Como no C++, terminar com zero
VendorID[12] := Char(0);

Para obter o tipo, o modelo, a família e o stepping do processador, devemos usar EAX com valor 1. O stepping identifica melhorias do mesmo processador, sendo a primeira sempre A0 e nas releases seguintes há acréscimos no número e/ou na letra. O tipo mostra se o processador é Original, OverDrive ou Dual. Modelo e família são numerações dadas pelos fabricantes a cada versão de seus chips. O retorno desses valores se dá no próprio EAX.

Quando chamamos CPUID com o valor de EAX igual a 1, outras informações são retornadas em outros registradores. Em EDX e ECX são retornadas indicações da presença de recursos da CPU. Informações sobre recursos extras são colocados em EBX. O trecho abaixo mostra como recuperar a assinatura da CPU (tipo + modelo + familia + stepping) além de reportar a presença de FPU (Floating Point Unit, que é o coprocessador matemático), se o processador possui tecnologia MMX (melhora processamentos envolvendo multimedia) e, no caso do processador ser Intel, se ele é HTT (Hyper Thread Technology, isto é, se há emulação de mais processadores).
var retStr, dType : String;
REGEAX, REGEBX, REGEDX : LongWord;
dLogicalProcessorCount : integer;
dFamily, dModel, dStepping, dFamilyEx, dModelEx : integer;
hasFpu, hasMmx, hasHtt : boolean;
begin
asm
MOV EAX, 1
CPUID
MOV [REGEAX], EAX
MOV [REGEBX], EBX
MOV [REGEDX], EDX
end;

dFamily := ((REGEAX shr 8) and $F);
dModel := ((REGEAX shr 4) and $F);
dStepping := (REGEAX and $F);

dFamilyEx := ((REGEAX shr 20) and $FF);
dModelEx := ((REGEAX shr 16) and $F);

case (((REGEAX shr 12) and $7)) of
0: dType := 'Original';
1: dType := 'OverDrive';
2: dType := 'Dual';
end;

hasFpu := ((REGEDX and $00000001) <> 0);
hasMmx := ((REGEDX and $00800000) <> 0);
hasHtt := ((REGEDX and $10000000) <> 0);

if ((StrComp(VendorID, 'GenuineIntel') = 0) And HasHTT) then
dLogicalProcessorCount := ((REGEBX shr 16) and $FF)
else
dLogicalProcessorCount := -1;

retStr := dType +
IntToStr (dFamily) + IntToStr (dModel) +
IntToHex (dStepping, 2) +
IntToStr (dFamilyEx) + IntToStr (dModelEx);

Tenho uma lista maior com mapeando os valores retornados em EDX com os recursos possívels. Caso julguem interessante, coloco em outro post esta lista.

9 comentários :

Anônimo disse...

Tive um grande problema em usar o mac como uma das chaves compostas para se gerar um hardkey. Analisei inúmeras funções e quando achava que estava tudo ok me deparei com a seguinte situação.

Usava para gerar hardkey mac+serial fisico do hd, e dependendo do sistema op usava o lógico, pois vc não consegue extrair informações se não estiver em modo adm windows 7 e vista + cgc do cliente + serial windows.

Um dia testando mac no vista tive a surpresa que ao registrar o sistema ele dava uma mac xx-xx-xx-xx-xx quando coloquei um disposivo usb dongle bluetooth na porta 1 a surpresa o mac mudou, sendo assim o mac que era primário xx se transformou em yy invalidando a chave. Não sei por que vista fez isso, no xp não faz essa mudança mas no vista e no windows 7 dependendo da porta usb que vc colocar um dongle bluetooth ele muda para mac primário do dongle. Fiquei sem saída. Você tem alguma alternativa para tal situação ?

Luís Gustavo Fabbro disse...

No post sobre a obtenção do MAC Address, eu uso a estrutura IP_ADAPTER_INFO na qual há um campo chamado Type que te permite distinguir os diversos tipos de adaptores presentes em seu computador. Basta, então, percorrer a lista toda e usar o primeiro adaptador cujo tipo for MIB_IF_TYPE_ETHERNET (placas de rede).

Anônimo disse...

E se o adaptador estiver desativado, ou seja imagine que você gerou uma chave mac+hd fisico+sei la o que. Ai blz, um certo dia o usuário foi lá e desativou as placas de rede wi-fi ou a placa de rede que você havia gerado a senha e ativou a placa por cabo. Assim a função pega o próximo ativo e a chave fica inválida.

Luís Gustavo Fabbro disse...

Você está certo: qualquer alteração feita no hardware e/ou software no qual a chave se baseia torna a chave inválida. Assim, se o seu licenciamento é baseado neste parâmetro, terá que inlcuir alguma cláusula relativa a mudanças na placa de rede ou na versão do sistema operacional.

É o que faz a SAP - a licença do Business One é atribuída a um código baseado em hardware, o que os leva a recomendar a instalação dessa licença num servidor, onde mudanças são sempre mais planejadas para evitar para a empresa.

Unknown disse...

Obrigado a função foi muito útil pra mim.
edeilson.s@hotmail.com

Anônimo disse...

como devo aplicar esse código no meu programa para imprimir as informações na tela?

Luís Gustavo Fabbro disse...

Veja que no último quadro mostrando programação nest post é preparada uma variável do tipo string chamada retStr. Ao final da função, ela contem todas as informações obtidas sobre a CPU. Basta, então, colocar um TLabel na sua tela (ou outro componente que possa exibir texto, como grid, edit, etc.) e colocar na propriedade Text o valor contido na variável.

Anônimo disse...

"Tenho uma lista maior com mapeando os valores retornados em EDX com os recursos possívels. Caso julguem interessante, coloco em outro post esta lista."

Tem como você passar essa lista maior com este mapeamento.

Obrigado

Felipe Luiz Carnevali

Luís Gustavo Fabbro disse...

Felipe

Inclui um novo post para tratar dos demais recursos. Ele pode ser acessado neste link.

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.