Ver Mensaje Individual
  #38  
Antiguo 02-04-2009
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Reputación: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
He investigado el tema de leer y escribir en los puertos, dada la peculiar dificultad en XP que obliga al uso de librerías externas o al uso de drivers.

Voy a colocar un código que funciona sin librerías ni drivers. El único requisito es que seamos Administradores del sistema. Con un driver funciona sin ser administradores, pero para instalar dicho driver si debemos tener esos privilegios.

El truco está en usar una API poco conocida y que se usa para los Debuggers: ZwSystemDebugControl.

Código:
//---------------------------------------------------------------------------
#pragma hdrstop

//---------------------------------------------------------------------------
#pragma argsused

//------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>

//#pragma comment(lib, "advapi32")
//#pragma link "advapi32.lib"

#define NTAPI       __stdcall

typedef int NTSTATUS;

typedef enum _SYSDBG_COMMAND
{
  SysDbgSysReadIoSpace = 14,
  SysDbgSysWriteIoSpace = 15
}SYSDBG_COMMAND, *PSYSDBG_COMMAND;

typedef NTSTATUS (NTAPI * PZwSystemDebugControl) (
    SYSDBG_COMMAND ControlCode,
    PVOID InputBuffer,
    ULONG InputBufferLength,
    PVOID OutputBuffer,
    ULONG OutputBufferLength,
    PULONG ReturnLength
    );

PZwSystemDebugControl ZwSystemDebugControl = NULL;

typedef struct _IO_STRUCT
{
    DWORD IoAddr;       // IN: Aligned to NumBYTEs,I/O address
    DWORD Reserved1;    // Never accessed by the kernel
    PVOID pBuffer;      // IN (write) or OUT (read): Ptr to buffer
    DWORD NumBYTEs;     // IN: # BYTEs to read/write. Only use 1, 2, or 4.
    DWORD Reserved4;    // Must be 1
    DWORD Reserved5;    // Must be 0
    DWORD Reserved6;    // Must be 1
    DWORD Reserved7;    // Never accessed by the kernel
}
IO_STRUCT, *PIO_STRUCT;

BOOL EnablePrivilege (PCSTR name)
{
    HANDLE hToken;
    TOKEN_PRIVILEGES priv = {1, {0, 0, SE_PRIVILEGE_ENABLED}};

    LookupPrivilegeValue(0, name, &priv.Privileges[0].Luid);
    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
    AdjustTokenPrivileges (hToken, FALSE, &priv, sizeof priv, 0, 0);
    CloseHandle (hToken);

    return (GetLastError() == ERROR_SUCCESS);
}

BOOL Inicializa()
{
    HMODULE hNtdll;
    hNtdll = LoadLibrary ("ntdll.dll");

    if(EnablePrivilege(SE_DEBUG_NAME)==FALSE){
       printf("Usted no tiene suficientes privilegios\n");
       return FALSE;
    }

    if(hNtdll){
       ZwSystemDebugControl = (PZwSystemDebugControl)GetProcAddress(hNtdll, "ZwSystemDebugControl");
       return TRUE;
    }
    return FALSE;
}

BYTE InPortB(int Port)
{
    BYTE Value;
    IO_STRUCT io;

    io.IoAddr = Port;
    io.Reserved1 = 0;
    io.pBuffer = (PVOID)(PULONG)&Value;
    io.NumBYTEs = sizeof(BYTE);
    io.Reserved4 = 1;
    io.Reserved5 = 0;
    io.Reserved6 = 1;
    io.Reserved7 = 0;

    ZwSystemDebugControl(SysDbgSysReadIoSpace, &io, sizeof(io), NULL, 0, NULL);
    return Value;
}

void OutPortB(int Port, BYTE Value)
{
    IO_STRUCT io;
    
    io.IoAddr = Port;
    io.Reserved1 = 0;
    io.pBuffer = (PVOID)(PULONG)&Value;
    io.NumBYTEs = sizeof(BYTE);
    io.Reserved4 = 1;
    io.Reserved5 = 0;
    io.Reserved6 = 1;
    io.Reserved7 = 0;
    
    ZwSystemDebugControl(SysDbgSysWriteIoSpace, &io, sizeof(io), NULL, 0, NULL);
};

void BeepOn (int Freq)
{
    BYTE b;

    if((Freq >= 20) && (Freq <= 20000)){
        Freq = 1193181 / Freq;
        b = InPortB(0x61);
        if((b & 3) == 0){
           OutPortB (0x61, (BYTE) (b | 3));
           OutPortB (0x43, 0xb6);
        }
        OutPortB (0x42, (BYTE)Freq);
        OutPortB (0x42, (BYTE)(Freq >> 8));
    }
}

void BeepOff (void)
{
    BYTE b;

    b = (InPortB(0x61) & 0xfc);
    OutPortB(0x61, b);
}

// Sólo funciona en Windows XP y superiores
// Se debe ser Administrador del Sistema
int main(void)
{
    if(Inicializa()==FALSE){
       printf("Error al inicializar los puertos\n");
       Sleep (2000);
       return 0;
    }

    // Aquí podemos utilizar las funciones InPortB y OutPortB

    // Activamos el altavoz del sistema durante 300ms con una frecuencia
    // de 1000Hz
    BeepOn(1000);  // frecuencia de 1000Hz
    Sleep (300);
    BeepOff();

    return 0;
}
La función main demuestra como usar las funciones para activar el altavoz del sistema.

Patra escribir y leer del puerto paralelo, basta con:
Código:
Inicializa();
BYTE B = InPort(0x378);  // Lee del puerto paralelo
OutPort(0x378, 3);       // Escribe en el puerto paralelo el valor 3
Saludos.

Última edición por escafandra fecha: 02-04-2009 a las 22:30:21. Razón: Mejoras en la claridad del código
Responder Con Cita