The previous examples were more theoretical.
Consider one more example driver. This is a complete driver, which can be used not only by example, but also be used in your program. If someone had to work with the ports of the computer, then perhaps you know that modern operating systems Windows, based on the core NT, do not allow direct access to the ports of the user application. In other words, a user-mode prohibited assembly instructions "IN" and "OUT". But these instructions are allowed in kernel mode, if you create a driver, which on command, the user program will work with a given port, the program will be able to using driver to read or write data to the required port.
But as we know, everything is invented before us, and there is such a project, as a library Inpout32.dll.
http://logix4u.net/
Let's create using PureBasic its analogue.
First we create a kernel mode driver.
Code: Select all
Declare DriverEntry(*DriverObject, *RegistryPath)
; Import kernel function of "ntoskrnl.exe".
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
#IOCTL_READ_PORT_UCHAR = $200
#IOCTL_WRITE_PORT_UCHAR = $400
; Entry point in main function the driver.
*EntryPoint = @DriverEntry()
!jmp [p_EntryPoint]
EnableExplicit
; Direct write in port.
Procedure.a InPort(Port.u)
Protected Result.a=0
EnableASM
MOV DX, Port
IN al,DX
MOV Result, al
DisableASM
ProcedureReturn Result
EndProcedure
; Direct reading from port.
Procedure OutPort(Port.u, Byte.a)
EnableASM
MOV al, Byte
MOV DX, Port
OUT DX, al
DisableASM
EndProcedure
; This procedure, called kernel manager,
; calling WinAPI functions DeviceIoControl_().
Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
Protected ntStatus, *Point, *Stack.IO_STACK_LOCATION
Protected InBuffersize, OutBuffersize, CtrlBuff
Protected Port.u, Byte.a, InByte.a, Code
*Stack = *pIrp\Tail\Overlay\CurrentStackLocation
; This is the "dwIoControlCode", sent messages of WinAPI functions DeviceIoControl_().
Code = *Stack\Parameters\DeviceIoControl\IoControlCode
; This is the "nInBufferSize", sent messages of WinAPI functions DeviceIoControl_().
InBuffersize = *Stack\Parameters\DeviceIoControl\InputBufferLength
; This is the "nOutBufferSize", sent messages of WinAPI functions DeviceIoControl_().
OutBuffersize = *Stack\Parameters\DeviceIoControl\OutputBufferLength
; This is the "lpInBuffer", sent messages of WinAPI functions DeviceIoControl_().
CtrlBuff = PeekI(*pIrp\SystemBuffer)
Port = CtrlBuff & $FFFF
ntStatus = #STATUS_SUCCESS ; This value returns WinAPI functions DeviceIoControl_().
Select Code
Case #IOCTL_READ_PORT_UCHAR ; Reading from a port.
InByte=InPort(Port) ;
PokeA(*pIrp\SystemBuffer, InByte) ; Read a byte from the port is placed in a buffer.
*pIrp\IoStatus\Information = 1 ; In buffer, write 1 byte.
Case #IOCTL_WRITE_PORT_UCHAR ; Writing in Port.
Byte = (CtrlBuff>>16)&255
OutPort(Port, Byte)
*pIrp\IoStatus\Information = 0 ; In buffer, write 0 byte.
Default ; The command is not supported.
ntStatus = #STATUS_UNSUCCESSFUL
*pIrp\IoStatus\Information = 0 ; In buffer, write 0 byte.
EndSelect
; Message processed.
; More information. http://msdn.microsoft.com/en-us/library/windows/hardware/ff548343(v=vs.85).aspx
*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 for unloading driver.
Procedure UnloadDriver(*DriverObject.DRIVER_OBJECT)
Protected uniDOSString.UNICODE_STRING
RtlInitUnicodeString(@uniDOSString, ?DosDevices)
IoDeleteSymbolicLink (@uniDOSString)
IoDeleteDevice(*DriverObject\DeviceObject)
EndProcedure
; Procedure initialize driver.
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
Protected deviceObject.DEVICE_OBJECT
Protected uniNameString.UNICODE_STRING
Protected uniDOSString.UNICODE_STRING
Protected status
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) ; We need to remove an object!
; In mode kernel, of system will
; not do it even after unloading the driver!
ProcedureReturn status
EndIf
; Registration procedures.
*DriverObject\DriverUnload = @UnloadDriver() ; Procedure for unloading drivers
*DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch() ; Called when WinAPI, CreateFile_().
*DriverObject\MajorFunction[#IRP_MJ_CLOSE] = @CreateDispatch() ; Called when WinAPI, CloseHandle_().
*DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl() ; ; Called when WinAPI, DeviceIoControl_().
ProcedureReturn #STATUS_SUCCESS
EndProcedure
; Name of the driver in system.
DataSection
Device:
!du '\Device\pbdriverio', 0, 0
DosDevices:
!du '\DosDevices\pbdriverio', 0, 0
EndDataSection
When you load the driver, will be performed the procedure code DriverEntry(), in which the driver, register (to him will be assigned symbolic names that can be used in CreateFile_()) and will be assigned to unload the driver procedure and call processing WinAPI functions CreateFile_(), CloseHandle_() and DeviceIoControl_().
In procedure of DeviceIoControl() driver that handles the request of the same name WinAPI function, with which the data transmitted to the driver and received from him.
Procedure processes the two queries:
#IOCTL_READ_PORT_UCHAR ; Reading from a port.
#IOCTL_WRITE_PORT_UCHAR ; Writing in Port.
Upon receipt of the first request, the called is procedure InPort (), which performed read data from the port.
Upon receipt of the second request, it calls the procedure OutPort (), writes the data to the port.
----------
Now for a code library (DLL), is being called from the driver. This is just an example. Not necessarily that the driver was in a DLL. It may invoke a directly of the program's.
Code: Select all
#IOCTL_READ_PORT_UCHAR = $200
#IOCTL_WRITE_PORT_UCHAR = $400
CompilerIf Defined(PBIO_OK, #PB_Constant)=0
Enumeration
#PBIO_OK
#PBIO_ErrCopyDriver
#PBIO_ErrInstallDriver
#PBIO_ErrAccess
EndEnumeration
CompilerEndIf
Structure Param_Info
hDriverID.i
ErrStatus.i
DrFileName.s
DriverName.s
*Point
Len.i
EndStructure
Declare OpenDriver()
Declare Driver_UnInstall(Drivers_Name.s)
EnableExplicit
ProcedureDLL AttachProcess(Instance)
Global ParamInfo.Param_Info
ParamInfo\ErrStatus=#PBIO_OK
ParamInfo\DrFileName = GetTemporaryDirectory()+"pbdriverio.sys"
ParamInfo\DriverName = "pbdriverio"
ParamInfo\Point = ?Driver
ParamInfo\Len = ?DriverEnd-?Driver
ParamInfo\hDriverID = OpenDriver()
EndProcedure
ProcedureDLL DetachProcess(Instance)
If ParamInfo\hDriverID
CloseHandle_(ParamInfo\hDriverID)
ParamInfo\hDriverID=0
EndIf
; Unloading drivers
; Driver_UnInstall(ParamInfo\DriverName)
; If FileSize(ParamInfo\DrFileName)>0
; DeleteFile(ParamInfo\DrFileName)
; EndIf
EndProcedure
Procedure Driver_Start(Drivers_Name.s)
Protected hSCManager.i, hServ.i
Protected ErrorCode, Result
Result=#False
hSCManager = OpenSCManager_(#Null, #Null, #SC_MANAGER_ALL_ACCESS)
If hSCManager = 0
If GetLastError_() = #ERROR_ACCESS_DENIED
hSCManager = OpenSCManager_(#Null, #Null, #GENERIC_READ)
hServ = OpenService_(hSCManager, Drivers_Name, #GENERIC_EXECUTE)
If StartService_(hServ, 0, #Null)
Result=#True
EndIf
EndIf
Else
hServ = OpenService_(hSCManager, Drivers_Name, #GENERIC_EXECUTE)
If StartService_(hServ, 0, #Null)
Result=#True
Else
ErrorCode=GetLastError_()
If ErrorCode=1056
Result=#True
EndIf
EndIf
EndIf
If hServ : CloseServiceHandle_(hServ) : EndIf
If hSCManager : CloseServiceHandle_(hSCManager) : EndIf
ProcedureReturn Result
EndProcedure
Procedure Driver_UnInstall(Drivers_Name.s)
Protected hSCManager.i, hServ.i
Protected ServiceStatus.SERVICE_STATUS
hSCManager = OpenSCManager_(#Null, #Null, #SC_MANAGER_ALL_ACCESS)
hServ = OpenService_(hSCManager, Drivers_Name, #SERVICE_ALL_ACCESS)
If hServ<>#Null
ControlService_(hServ, #SERVICE_CONTROL_STOP, @ServiceStatus)
DeleteService_(hServ)
EndIf
If hServ : CloseServiceHandle_(hServ) : EndIf
If hSCManager : CloseServiceHandle_(hSCManager) : EndIf
EndProcedure
Procedure Driver_Install(Drivers_Name.s)
Protected Result, FileID, File.s, Mgr
Protected ErrorCode, Ser, Count
Result=#False
Count=0 : FileID=0 : Mgr=0 : Ser=0
File=ParamInfo\DrFileName
If FileSize(File) <> ParamInfo\Len Or CRC32FileFingerprint(File) <> CRC32Fingerprint(ParamInfo\Point, ParamInfo\Len)
FileID=CreateFile(#PB_Any, File)
If FileID
WriteData(FileID, ParamInfo\Point, ParamInfo\Len)
CloseFile(FileID)
ElseIf ParamInfo\ErrStatus = #PBIO_OK
ParamInfo\ErrStatus = #PBIO_ErrCopyDriver
EndIf
Else
FileID=2
EndIf
If FileID
Driver_Install_M1:
Mgr = OpenSCManager_(#Null, #Null, #SC_MANAGER_ALL_ACCESS)
If Mgr
Ser = CreateService_(Mgr, Drivers_Name, Drivers_Name, #SERVICE_ALL_ACCESS, #SERVICE_KERNEL_DRIVER, #SERVICE_DEMAND_START, #SERVICE_ERROR_NORMAL, File, #Null, 0, 0, 0, 0)
ErrorCode=GetLastError_()
If Ser
Result=#True
ElseIf ErrorCode=1073
Result=#True
ElseIf ErrorCode=1072
If Count=0
If Ser : CloseServiceHandle_(Ser) : EndIf
If Mgr : CloseServiceHandle_(Mgr) : EndIf
Driver_UnInstall(Drivers_Name)
Count+1
Goto Driver_Install_M1
EndIf
EndIf
EndIf
EndIf
If Ser : CloseServiceHandle_(Ser) : EndIf
If Mgr : CloseServiceHandle_(Mgr) : EndIf
If Result=#False And ParamInfo\ErrStatus = #PBIO_OK
ParamInfo\ErrStatus = #PBIO_ErrInstallDriver
EndIf
ProcedureReturn Result
EndProcedure
Procedure OpenDriver()
Protected Result, hDriver
Result=0
hDriver = CreateFile_("\\.\"+ParamInfo\DriverName, #GENERIC_READ | #GENERIC_WRITE, 0, 0, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, 0)
If hDriver=#INVALID_HANDLE_VALUE
If Driver_Install(ParamInfo\DriverName)
If Driver_Start(ParamInfo\DriverName)
hDriver = CreateFile_("\\.\"+ParamInfo\DriverName, #GENERIC_READ | #GENERIC_WRITE, 0, 0, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL, 0)
If hDriver <> #INVALID_HANDLE_VALUE
Result=hDriver
EndIf
EndIf
EndIf
Else
Result=hDriver
EndIf
If Result=0 And ParamInfo\ErrStatus = #PBIO_OK
ParamInfo\ErrStatus = #PBIO_ErrAccess
EndIf
ProcedureReturn Result
EndProcedure
ProcedureDLL Inp(PortAddress.u) ; Read a byte from the port, address given in 'PortAddress'.
Protected Result, Buffer.i, BytesReturned.i, OutBuff.i
Result=0 : Buffer=0 : OutBuff=0
If ParamInfo\hDriverID
Buffer=PortAddress
DeviceIoControl_(ParamInfo\hDriverID, #IOCTL_READ_PORT_UCHAR, @Buffer, 2, @OutBuff, 1, @BytesReturned, 0)
Result=OutBuff
EndIf
ProcedureReturn Result
EndProcedure
ProcedureDLL Out(PortAddress.u, Byte.a) ; Writing a byte to the port, address given in 'PortAddress'.
Protected Result, Buffer.i, BytesReturned.i
Result=0
If ParamInfo\hDriverID
Buffer=PortAddress
PokeA(@Buffer+2, Byte)
DeviceIoControl_(ParamInfo\hDriverID, #IOCTL_WRITE_PORT_UCHAR, @Buffer, 3, 0, 0, @BytesReturned, 0)
EndIf
ProcedureReturn Result
EndProcedure
ProcedureDLL Status() ; Status of the driver. If there are no errors, then 0.
ProcedureReturn ParamInfo\ErrStatus
EndProcedure
ProcedureDLL.f Version()
ProcedureReturn 1.4
EndProcedure
DataSection
Driver:
IncludeBinary "Driver\pbdriverio.sys"
DriverEnd::
EndDataSection
The library in the first place trying to call the driver on his symbolic name "\\.\pbdriverio".
If she fails, then checks to see if the driver on the disk and, if necessary, the driver is extracted from the library to the disk, and then registers in the system. Then, again, tries to call the driver on his name symbols.
From the library exports several functions.
Inp(PortAddress.u) ; Read a byte from the port, address given in 'PortAddress'.
Out(PortAddress.u, Byte.a) ; Writing a byte to the port, address given in 'PortAddress'.
Status() ; Status of the driver. If there are no errors, then 0.
Version()
Files: http://pure-basic.narod.ru/forum_files/ ... PortIO.zip