Preface
Use Delphi 3.0 to write a VxD device driver. It compiles and passes under Delphi 3. There is no test under Delphi 2. The Object file M$ Linker 5.12.8181 created by Delphi 4 cannot be recognized. The assembler used here is M$'s Macro Assembler ver. 6.11d, the linker is M$ Incremental Linker ver. 5.12.8181 , they come from Windows 98DDK (http://www.microsoft.com/ddk/ddk98.htm).
introduce
There are two types of VxD device drivers for Windows:
1. Static VxD, loaded into the operating system and permanently existing in the memory;
2. Dynamic VxD, which is loaded into the memory when needed. After use, close the VxD to release the memory.
InPRise Delphi has the ability to create any type of VxD device driver. Below we will introduce how to create dynamic VxD.
When a Win32 application opens a VxD "virtual" device, VWIN32 uses LoadDevice to load the VxD into memory and creates a message W32_DEVICEIOCONTROL and sends it to the VxD.
That is to say, VxD should at least respond to the following two system messages and write one of the following functions:
SYS_DYNAMIC_DEVICE_INIT
SYS_DYNAMIC_DEVICE_EXIT
W32_DEVICEIOCONTROL function.
The message SYS_DYNAMIC_DEVICE_INIT is sent to VxD when trying to load VxD, and the message SYS_DYNAMIC_DEVICE_EXIT is sent to VxD when trying to dynamically exchange. The handler of the message should return the VXD_SUCCESS flag in the register AX after successful processing.
The dwService parameter of W32_DEVICEIOCONTROL has the following values:
DIOC_OPEN is sent when VxD attempts an open operation through the CreateFile() function (after the SYS_DYNAMIC_DEVICE_INIT message), and returns NO_ERROR (0) if successful;
DIOC_CLOSEHANDLE Sent when VxD attempts a close operation via the CloseHandle() function (before SYS_DYNAMIC_DEVICE_EXIT)
All other values > 0 mean a different function call (given by dwIoControlCode) when the VxD is called by the DeviceIoControl function.
Start module (vxdmain.asm)
...
extrn SysDynamicDeviceInit:PROC
extrn SysDynamicDeviceExit:PROC
extrn W32DeviceIoControl:PROC
...
PUBLIC DELPHIIO_DDB
Public @@HandleFinally
Public @initialization
...
Control_0 proc
cmp eax, SYS_DYNAMIC_DEVICE_INIT
jnz short chkSysDynExit
call SysDynamicDeviceInit
cmp eax, 1
retn
;-------------
chkSysDynExit:
cmp eax, SYS_DYNAMIC_DEVICE_EXIT
jnz short chkDevIOCtl
call SysDynamicDeviceExit
cmp eax, 1
retn
;-------------
chkDevIOCtl:
cmp eax, W32_DEVICEIOCONTROL
jnz short loc_ret
push esi
push edx
pushebx
pushecx
call W32DeviceIoControl
cmp eax, 1
retn
;-------------
loc_ret:
clc
retn
Control_0 endp
@@HandleFinally:
@initialization:
ret
_LTEXT ends
END
Delphi will call the external procedures HandleFinaly and initialization for the initialization/finalization of the unit, even if the initialization/finalization does not exist in the unit. Therefore, we create an empty external procedure entry in the assembly startup file.
Main Delphi program unit (vxdProcs.pas)
...
procedure ShellMessage(Handle, Flags : integer; const Message, Caption : PChar;
Callback, ReferenceData : pointer); stdcall; assembler;
asm
mov ebx, Handle // virtual machine handle
mov eax, Flags // message box flags
mov ecx, Message // address of message text
mov edi, Caption // address of caption text
mov esi, Callback // address of callback
mov edx, ReferenceData // reference data for callback
int 20H // VxDCall
dd 170004h // Shell_Message
end;
function SysDynamicDeviceInit: INTEGER;
begin
ShellMessage(0, $10, Copyright, 'SysDynInit: Hello from Delphi VxD !!!', nil, nil);
Result := VXD_SUCCESS;
end;
function SysDynamicDeviceExit: INTEGER;
begin
ShellMessage(0, $10, Copyright, 'SysDynDevExit: Bye from Delphi VxD !!!', nil, nil);
Result := VXD_SUCCESS;
end;
function W32DeviceIoControl(dwService : INTEGER;
dwDDB : INTEGER;
hDevice: INTEGER;
lpDIOCParms : pointer) : INTEGER;
begin
ShellMessage(0, $10, Copyright, 'W32DevIOCtl', nil, nil);
if (dwService = DIOC_OPEN) then
begin
Result := NO_ERROR;
end
else if (dwService = DIOC_CLOSEHANDLE) then
begin
Result := VXD_SUCCESS;
end
else if (dwService > MAX_PASVXD_W32_API) then
begin
Result := ERROR_NOT_SUPPORTED;
end
else
begin
Result := VXD_SUCCESS;
end;
end;
...
[Translator: Ok, the simple VxD device driver has been written. You can use it as a template for writing VxD device drivers. ]
Appendix 1: Make.bat
D:VISUAL~198DDKBINWin98ml -coff -DBLD_COFF -DIS_32 -W2 -c -Cx -Zm -DMASM6 vxdmain.asm
call dcc3.bat -J vxdprocs.pas
D:VISUAL~198DDKBINlink /DEF:vxddef.def /VXD vxdmain.obj vxdprocs /OUT:delphiio.vxd
Appendix 2:
Now let's write a test program for the VxD, with two buttons: one to open the VxD; one to close the VxD.
const
VxDName = '/.DELPHIIO.VXD';
...
function TVxDTestForm.OpenVxDDriver: boolean;
begin
HVxDHandle := CreateFile(VxDName,0,0,nil,0,FILE_FLAG_DELETE_ON_CLOSE,0);
Result := HVxDHandle <> INVALID_HANDLE_VALUE;
end;
procedure TVxDTestForm.CloseVxDDriver;
begin
if HVxDHandle <> INVALID_HANDLE_VALUE then begin
CloseHandle(HVxDHandle);
HVxDHandle := INVALID_HANDLE_VALUE;
end;
end