Исходный код драйвера для прямого доступа к портам (LPT, COM и др.) компьютера. Для лучшего понимания устройства и работы драйвера, можете прочитать эту статью.
; Драйвер для прямого доступа к портам компьютера - pbdriverio.sys.
Declare DriverEntry(*DriverObject, *RegistryPath)
; Точка входа в программу.
!public PureBasicStart
!section '.code' code readable executable align 8
!PureBasicStart:
*A=@DriverEntry()
!jmp [p_A]
; Декларация функций для FASM.
!extrn PB_PeekL
!extrn PB_PokeL
!extrn PB_PeekB
!extrn PB_PokeB
;!extrn _DbgPrint
!extrn _IoCompleteRequest@8
!extrn _RtlInitUnicodeString@8
!extrn _IoCreateDevice@28
!extrn _IoDeleteDevice@4
!extrn _IoCreateSymbolicLink@8
!extrn _IoDeleteSymbolicLink@4
; Импорт функций ядра.
Import "ntoskrnl.lib"
IoCompleteRequest(*IRP, PriorityBoost)
RtlInitUnicodeString(*UString, *String)
IoCreateDevice(*DriverObject, DeviceExtensionSize, *UDeviceName, DeviceType, DeviceCharacteristics, Exclusive, *DeviceObject)
IoDeleteDevice(*DeviceObject)
IoCreateSymbolicLink(*SymbolicLinkName, *DeviceName)
IoDeleteSymbolicLink(*SymbolicLinkName)
EndImport
; ImportC "ntoskrnl.lib"
; DbgPrint(a.s)
; EndImport
#IOCTL_READ_PORT_UCHAR = $200
#IOCTL_WRITE_PORT_UCHAR = $400
; Прямая запись в порт.
Procedure.b InPort(Port.u)
Protected Result.b=0
EnableASM
MOV DX, Port
IN al,DX
MOV Result, al
DisableASM
ProcedureReturn Result
EndProcedure
; Прямое чтение из порта.
Procedure OutPort(Port.u, Byte.a)
EnableASM
MOV al, Byte
MOV DX, Port
OUT DX, al
DisableASM
EndProcedure
Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
Protected ntStatus, *Point, *Stack.IO_STACK_LOCATION
*Stack = *pIrp\Tail\Overlay\CurrentStackLocation
inBuffersize = *Stack\Parameters\DeviceIoControl\InputBufferLength
outBuffersize = *Stack\Parameters\DeviceIoControl\OutputBufferLength
CtrlBuff = PeekL(*pIrp\SystemBuffer)
address = CtrlBuff & $FFFF
Byte.a = (CtrlBuff>>16)&255
Code = *Stack\Parameters\DeviceIoControl\IoControlCode
Select Code
Case #IOCTL_READ_PORT_UCHAR
InByte.b=InPort(address)
PokeB(*pIrp\SystemBuffer, InByte)
*pIrp\IoStatus\Information = 1
Case #IOCTL_WRITE_PORT_UCHAR
OutPort(address, Byte)
*pIrp\IoStatus\Information = 0
Default
ntStatus = #STATUS_UNSUCCESSFUL
*pIrp\IoStatus\Information = 0
EndSelect
ntStatus = #STATUS_SUCCESS
*pIrp\IoStatus\Status = ntStatus
IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
ProcedureReturn ntStatus
EndProcedure
Procedure CreateDispatch(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
*pIrp\IoStatus\Information = 0
*pIrp\IoStatus\Status = #STATUS_SUCCESS
IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
ProcedureReturn #STATUS_SUCCESS
EndProcedure
Procedure UnloadDriver(*DriverObject.DRIVER_OBJECT)
Protected uniDOSString.UNICODE_STRING
RtlInitUnicodeString(@uniDOSString, ?DosDevices)
IoDeleteSymbolicLink (@uniDOSString)
IoDeleteDevice(*DriverObject\DeviceObject)
EndProcedure
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
Protected deviceObject.DEVICE_OBJECT
Protected uniNameString.UNICODE_STRING
Protected uniDOSString.UNICODE_STRING
RtlInitUnicodeString(@uniNameString, ?Device)
RtlInitUnicodeString(@uniDOSString, ?DosDevices)
status = IoCreateDevice(*DriverObject, 0, @uniNameString, #FILE_DEVICE_UNKNOWN, 0, #False, @deviceObject)
If status <> #STATUS_SUCCESS
ProcedureReturn status
EndIf
status = IoCreateSymbolicLink(@uniDOSString, @uniNameString)
If status <> #STATUS_SUCCESS
IoDeleteDevice(@deviceObject) ; Мы должны сами убирать "хвосты" в режиме ядра!
ProcedureReturn status
EndIf
*DriverObject\DriverUnload = @UnloadDriver()
*DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch()
*DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl()
ProcedureReturn #STATUS_SUCCESS
EndProcedure
;
DataSection
Device:
!du '\Device\pbdriverio', 0, 0
DosDevices:
!du '\DosDevices\pbdriverio', 0, 0
EndDataSectionЭто аналог довольно известного драйвера, используемого в библиотеке inpout32.dll.
Компилируем его с помощью PureBasic.
Скачать драйвер, а так же аналог указанной библиотеки, названный PB_IO.dll (в месте с исходными текстами и примерами использования), можно здесь http://pure-basic.narod.ru/forum_files/ … ver_IO.zip
Примечательно что PB_IO.dll при той же функциональности, имеет в три раза меньший размер чем inpout32.dll (12 КБ PB_IO.dll и 32 КБ inpout32.dll). Теперь вы понимаете сколько "мусора" в inpout32.dll?
Скриншот одного из примеров его использования, измеряющий температуру процессора и системной платы (будет работать не на всех компьютерах).
Код примера.
CompilerIf Defined(PBIO_OK, #PB_Constant)=0
Enumeration
#PBIO_OK
#PBIO_ErrCopyDriver
#PBIO_ErrInstallDriver
#PBIO_ErrAccess
EndEnumeration
CompilerEndIf
If OpenLibrary(2, "..\PB_IO.dll")=0
MessageRequester("", "Нет PB_IO.dll.", #MB_OK|#MB_ICONERROR)
End
EndIf
Prototype Inp(PortAddress.u)
Prototype Out(PortAddress.u, Byte.a)
Prototype Status()
Prototype.f Version()
Global Inp.Inp =GetFunction(2, "Inp")
Global Out.Out =GetFunction(2, "Out")
Status.Status = GetFunction(2, "Status")
Version.Version =GetFunction(2, "Version")
#ADR_REG = $295 ;Это адреса регистров системной платы, с помощью которых можно узнать температуру
#DATA_REG = $296
Procedure Termo() ; Эта процедура вызывается по таймеру каждую секунду
Out(#ADR_REG, $2B) ; Получает текущую температуру процессора
x=Inp(#DATA_REG)
SetGadgetItemText(0,0,StrU(x, #PB_Byte)+" °C",1) ; отображаем её в таблице
Out(#ADR_REG, $29) ; Получает текущую температуру системной платы
x=Inp(#DATA_REG)
SetGadgetItemText(0,1,StrU(x, #PB_Byte)+" °C",1) ; отображаем её в таблице
EndProcedure
Err = Status()
If Err<>#PBIO_OK
MessageRequester("", "Ошибка драйвера "+Str(Err))
EndIf
OpenWindow(0,0,0,274,80,"TermoControl",#PB_Window_MinimizeGadget|#PB_Window_Invisible|#PB_Window_ScreenCentered)
ListIconGadget(0,2,4,270,70,"Имя",120,#PB_ListIcon_GridLines) ; Таблица
SetGadgetFont(0,LoadFont(0,"MS Sans Serif",10) ) ; Шрифт используемый в таблице
AddGadgetColumn(0, 1, "Температура", 140) ; Добавление колонки в таблицу
AddGadgetItem(0, 0, "Процессор") ; Добавление строк в таблицу
AddGadgetItem(0, 1, "Мат. плата")
Termo()
AddWindowTimer(0,2,1000) ; Таймер.
HideWindow(0,0) ; Отображение окна
Repeat ; Главный цикл программы
Event=WaitWindowEvent()
If Event=#PB_Event_Timer
Termo()
EndIf
Until Event=#PB_Event_CloseWindow