Acesso direto a uma porta para o Windows NT/2000/XP

 

Até a chegada do Windows NT, acessar endereços de portas era tão simples quanto usar estas duas funções assembler:

 

procedure WritePort(Direccion: word; valor: byte);

begin

    asm

      mov dx,Direccion

      mov AL,valor

      out DX,AL

    end;

   end;

 

function ReadPort(Direccion: Word): Byte;

begin

    asm

      mov dx,Direccion

      em al,dx

      mov Result,al

    end;

   end;

 

Com a chegada do Windows NT, Windows 2000 e Windows XP a coisa ficou mais difícil. Nestes sistemas operacionais, os programas são executados em dois modos diferenciados: modo núcleo (kernel mode) e modo usuário (user mode).

Em modo núcleo, temos acesso a tudo. É o modo usado pelo núcleo e os drives instalados no sistema. Neste modo, os drivers podem 'conversar' com os periféricos, acessando as portas necessárias sem problemas.

Por razões de segurança, no modo usuário, os programas não têm acesso a todos os recursos do sistema. Por exemplo, um usuário sem privilégios poderia controlar a placa de rede diretamente, ler o teclado, manipular os circuitos da interface IDE, os arquivos lidos para os quais não tem permissão de acesso, etc.

As aplicações Delphi sempre são executadas em modo usuário.

Com esta limitação em mente, como faríamos para acessar as portas para as quais não temos permissão de acesso?  Bem, a solução é usar um driver instalado no núcleo.

Do momento que o driver roda em modo núcleo, terá acesso às portas e poderemos 'conversar' de modo simples com o mesmo, apesar de estarmos rodando em modo usuário.

Porém, onde acharemos um driver que nos permita realizar estas operações?

Bem, afortunadamente, alguém já o fez para nós.

Particularmente, devemos ter disponível um driver em modo núcleo, com suas fontes (no caso de querermos dar uma olhada nele) já compilado em uma DLL.

A URL da DLL é: http://www.logix4u.net/inpout32.htm

A DLL trabalha em qualquer Windows (inclusive Windows 98)

Além disto, por poder discernir quando é necessário o uso do driver, também trabalhará no Windows98 de modo transparente.

A DLL exporta duas funções que poderemos utilizar: uma é para escrever um valor em uma porta e a outra é para ler o conteúdo de uma porta.

Teremos simplesmente que definir as funções, para poder usá-las na nossa aplicação. Como sempre que usarmos funções exportadas por uma DLL, teremos dois modos de acesso às mesmas: fazendo o link estaticamente ou dinamicamente.

Fazer o link das funções da DLL para nossa aplicação de modo estático é bem mais simples: basta colocar estas duas linhas de código na seção de implementação:

 

function Inp32(wAddr: word): byte; stdcall; external 'inpout32.dll';

function Out32(wAddr: word; bOut: byte): byte; stdcall; external 'inpout32.dll';

 

Para poder usá-los mais tarde. Eis alguns exemplos:

 

{Send 65 to o port 378}

Out32($378,65);

 

{Read o port 379}

ShowMessage( 'Port $379:'+ IntToStr(Inp32($379)) );

 

Não entanto, se a DLL não estiver acessível no diretório da aplicação ou no diretório do sistema, quando executarmos a aplicação, obteremos uma bonita exceção ao iniciar a mesma.

Para evitar isto, podemos usar o link dinâmico das funções do DLL, isto é, carregar a DLL por meio de LoadLibrary e a seguir achar a direção das funções e designar para as mesmas dois ponteiros previamente definidos.