dos虚拟机本来是老玩意儿了,没想到一直有朋友关心,现在就把开发dos虚拟机的文章写完,介绍一下开发串口通信程序。先用一条短接线把PC机串口的收发短接,这样就能实现自发自收了,再来一段C程序:
#include "stdio.h"
void main(void)
{
unsigned char byteID;
__asm
{
//初始化串口,9600,无校验,1位停止位
mov al,80H
mov dx,03FBH
out dx,al
mov al,0CH
mov dx,03F8H
out dx,al
mov al,00H
mov dx,03F9H
out dx,al
mov al,03H
mov dx,03FBH
out dx,al
mov al,00H
mov dx,03F9H
out dx,al
//发送字节01h
mov dx,03FDH
COM_OUT1:
in al,dx
test al,20H
je COM_OUT1
mov al,01H //在这里可以修改发送字节
mov dx,03F8H
out dx,al
//接收字节
MOV DX,03FDH
COM_IN1:
in al,dx
TEST al,01H
JE COM_IN1
MOV DX,03F8H
in al,dx
MOV byteID,al
}
//显示接收的字节
printf ("SampleService0 returned = %x/n", byteID);
} // main
用16位的编译器编译后成一个exe文件,在dos操作系统下运行就能看到显示结果了。因为windows操作系统禁止直接操作硬件设备,这样的程序在windows下是不能跑的。
下面我们就来虚拟一个串口设备,让它在windows下跑起来。先来一段C程序:
#include "stdio.h"
#define PORT_IDENTIFY 0x300
#define PORT_READ 0x301
#define PORT_WRITE 0x302
void main(void)
{
unsigned char byteIDi;
_asm mov dx, PORT_IDENTIFY
_asm in al, dx
_asm mov byteID, al
printf("Port I/O: ID %d read from port 0x%x/n",
byteID, PORT_IDENTIFY);
_asm mov dx, PORT_WRITE
_asm mov al, 01H
_asm out dx, al
_asm mov dx, PORT_READ
_asm in al, dx
_asm mov byteID, al
printf ("SampleService0 returned = %x/n", byteID);
} // main
这段程序虚拟的串口定义了三个端口:0x300,0x301,0x302,通过读0x300端口判断虚拟串口设备是否存在,然后往0x302端口写了一个01h,再读0x301端口的字节。
只有这样一个文件是没法跑的,还需要有一个vdd来截取这些操作,要整一个vdd出来需要以下五个源文件:
1,iovdd.c
// IOVDD.C - Demonstate port and memory-mapped I/O
#include <windows.h>
#include <vddsvc.h>
#include <winioctl.h>
#include "iovdd.h"
typedef struct _GENPORT_WRITE_INPUT {
ULONG PortNumber; // Port # to write to
union { // Data to be output to port
ULONG LongData;
USHORT ShortData;
UCHAR CharData;
};
} GENPORT_WRITE_INPUT;
// Function Prototypes
BOOL VDDLibMain(HINSTANCE, ULONG, LPVOID);
VOID IoVDD_ReadByte(WORD wPort, PBYTE byteData);
VOID IoVDD_WriteByte(WORD wPort, BYTE byteData);
VOID IoVDD_Memory(ULONG ulAddress, ULONG RWFlags);
VOID Debug(LPSTR szDebug);
// Globals
HANDLE hVDD = NULL;
VDD_IO_PORTRANGE portRange;
ULONG ulAddr;
PBYTE pMem;
BYTE byteStatus = 0;
BYTE byteCount = 0;
BOOL bIoHooked = FALSE;
BOOL bMemHooked= FALSE;
BOOL bMemAllocated = FALSE;
BOOL bDebug = TRUE;
HANDLE hDevice=NULL;
/**---------------------------------------------**/
BOOL VDDLibMain(HINSTANCE hInst, ULONG ulReason,
LPVOID lpRsrv)
{
VDD_IO_HANDLERS ioHandlers;
hVDD = hInst;
switch(ulReason)
{
case DLL_PROCESS_ATTACH:
/* hDevice = CreateFile((LPTSTR)".//simpldrv",
GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
*/
Debug("IOVDD: VDDLibMain - Attach/n");
portRange.First = IOVDD_PORT_START;
portRange.Last = IOVDD_PORT_END;
ioHandlers.inb_handler = IoVDD_ReadByte;
ioHandlers.inw_handler = NULL;
ioHandlers.insb_handler = NULL;
ioHandlers.insw_handler = NULL;
ioHandlers.outb_handler = IoVDD_WriteByte;
ioHandlers.outw_handler = NULL;
ioHandlers.outsb_handler = NULL;
ioHandlers.outsw_handler = NULL;
if (!(bIoHooked = VDDInstallIOHook(hVDD,
1, &portRange, &ioHandlers)))
{
Debug("IOVDD: Port hook failed");
return FALSE;
}
/*
ulAddr = (ULONG)MAKELONG(0, 0xCC00);
pMem = (PBYTE)GetVDMPointer(ulAddr,
IOVDD_MIO_RANGE, 0);
if (!(bMemHooked = VDDInstallMemoryHook(
hVDD, pMem, IOVDD_MIO_RANGE,
(PVDD_MEMORY_HANDLER)IoVDD_Memory)))
{
Debug("IOVDD: Memory hook failed");
return FALSE;
}*/
break;
case DLL_PROCESS_DETACH:
Debug("IOVDD: VDDLibMain - Detach/n");
if (bIoHooked)
VDDDeInstallIOHook(hVDD, 1, &portRange);
CloseHandle(hDevice);
/* if (bMemHooked)
VDDDeInstallMemoryHook(hVDD, pMem,
IOVDD_MIO_RANGE);
if (bMemAllocated)
VDDFreeMem(hVDD, (PVOID)pMem,
IOVDD_MIO_RANGE);
if (pMem)
FreeVDMPointer(ulAddr, IOVDD_MIO_RANGE,
pMem, FALSE);*/
break;
default: break;
}
return TRUE;
} // VDDLibMain
/**---------------------------------------------**/
VOID IoVDD_ReadByte(WORD wPort, PBYTE byteData)
{
// HANDLE hDevice=NULL;
DWORD dwCount=0L;
ULONG PortNumber = wPort;
HANDLE hComm;
// handle ports that apps reads from
switch(wPort)
{
case IOVDD_PORT_IDENTIFY:
Debug("IOVDD: IOVDD_PORT_IDENTIFY/n");
hComm = CreateFile("com1",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if(INVALID_HANDLE_VALUE==hComm)
{
// int err=GetLastError();
Debug("Error in open COM port: com1./n");
// return FALSE;
}
hDevice = CreateFile((LPTSTR)".//simpldrv",
GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// DeviceIoControl(hDevice, (DWORD)IOCTL_SIMPLDRV_HELLO,
// NULL, 0, byteData, 1, &dwCount, NULL);
DeviceIoControl(
hDevice, // Handle to device
(DWORD)IOCTL_SIMPLDRV_HELLO, // IO Control code for Read
&PortNumber, // Buffer to driver.
sizeof(PortNumber), // Length of buffer in bytes.
byteData, // Buffer from driver.
1, // Length of buffer in bytes.
&dwCount, // Bytes placed in DataBuffer.
NULL // NULL means wait till op. completes.
);
// CloseHandle(hDevice);
break;
// case IOVDD_PORT_STATUS:
case 0x301:
Debug("IOVDD: IOVDD_PORT_STATUS/n");
// *byteData = byteStatus;
DeviceIoControl(
hDevice, // Handle to device
(DWORD)IOCTL_SIMPLDRV_HELLO, // IO Control code for Read
&PortNumber, // Buffer to driver.
sizeof(PortNumber), // Length of buffer in bytes.
byteData, // Buffer from driver.
1, // Length of buffer in bytes.
&dwCount, // Bytes placed in DataBuffer.
NULL // NULL means wait till op. completes.
);
break;
/*
case IOVDD_PORT_COUNT:
Debug("IOVDD: IOVDD_PORT_COUNT/n");
*byteData = byteCount;
break;
*/
default:
Debug("IOVDD: Unsupported port read/n");
break;
}
return;
} // IoVDD_ReadByte
/**---------------------------------------------**/
VOID IoVDD_WriteByte(WORD wPort, BYTE byteData)
{
// HANDLE hDevice=NULL;
/* DWORD dwCount=0L;
// handle ports that apps write to
switch(wPort)
{
case IOVDD_PORT_READ:
Debug("IOVDD: IOVDD_PORT_READ/n");
byteStatus = FALSE;
// request kernel-mode driver to read,
// when read completes, set status
if (byteCount > 35) byteCount = 35;
memcpy(pMem,
"This would be data read from device",
byteCount);
byteStatus = TRUE;
break;
case IOVDD_PORT_WRITE:
Debug("IOVDD: IOVDD_PORT_WRITE/n");
byteStatus = FALSE;
// request kernel-mode driver to write,
// when write request completes, set status
byteStatus = TRUE;
break;
case IOVDD_PORT_COUNT:
Debug("IOVDD: IOVDD_PORT_COUNT/n");
// this is how many bytes to write
byteCount = byteData;
if (byteCount > IOVDD_MIO_RANGE)
byteCount = IOVDD_MIO_RANGE;
break;
case IOVDD_PORT_READ:
default:
Debug("IOVDD: Unsupported port write/n");
break;
}*/
GENPORT_WRITE_INPUT InputBuffer;
DWORD ReturnedLength;
InputBuffer.PortNumber = wPort;
InputBuffer.CharData = byteData;
DeviceIoControl(
hDevice, // Handle to device
(DWORD)IOCTL_GPD_WRITE_PORT_UCHAR, // IO Control code for Write
&InputBuffer, // Buffer to driver. Holds port & data.
5, // Length of buffer in bytes.
NULL, // Buffer from driver. Not used.
0, // Length of buffer in bytes.
&ReturnedLength, // Bytes placed in outbuf. Should be 0.
NULL // NULL means wait till I/O completes.
);
// byteData = InputBuffer.CharData;
byteStatus = TRUE;
return;
} // IoVDD_WriteByte
/**---------------------------------------------
VOID IoVDD_Memory(ULONG ulAddress, ULONG RWFlags)
{
Debug("IOVDD: IoVDD_Memory/n");
bMemAllocated = VDDAllocMem(hVDD, pMem,
IOVDD_MIO_RANGE);
return;
} // IoVDD_Memory
/**---------------------------------------------**/
VOID Debug(LPSTR szDebug)
{
if (bDebug) OutputDebugString(szDebug);
} // Debug
// end of file
2,iovdd.h
// IOVDD.H - Include file for SIMPLVDD.C
#define IOVDD_PORT_START 0x300
#define IOVDD_PORT_END 0x304
#define IOVDD_PORT_IDENTIFY 0x300
//#define IOVDD_PORT_READ 0x301
//#define IOVDD_PORT_WRITE 0x302
//#define IOVDD_PORT_COUNT 0x303
#define IOVDD_PORT_STATUS 0x304
#define IOVDD_MIO_SEG 0xCC00
#define IOVDD_MIO_ADDR (((ULONG)IOVDD_MIO_SEG) << 16)
#define IOVDD_MIO_RANGE 128+1
// SimplDrv information
#define FILE_DEVICE_SIMPLDRV 0x00008300
#define SIMPLDRV_IOCTL_INDEX 0x830
#define IOCTL_SIMPLDRV_HELLO CTL_CODE(FILE_DEVICE_SIMPLDRV, /
SIMPLDRV_IOCTL_INDEX, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_GPD_WRITE_PORT_UCHAR /
CTL_CODE(FILE_DEVICE_SIMPLDRV, SIMPLDRV_IOCTL_INDEX+1, METHOD_BUFFERED, FILE_ANY_ACCESS)
// end of file
3,iovdd.def
; IOVDD.DEF - Module definition file for IOVDD.DLL
LIBRARY IOVDD
;DESCRIPTION 'VDD to demonstrate port I/O trapping
EXPORTS
VDDLibMain
; end of file
4,SOURCES
TARGETNAME=iovdd
TARGETPATH=obj
TARGETTYPE=DYNLINK
TARGETLIBS=$(BASEDIR)/lib/*/$(DDKBUILDENV)/kernel32.lib /
$(BASEDIR)/lib/*/$(DDKBUILDENV)/user32.lib /
$(BASEDIR)/lib/*/$(DDKBUILDENV)/advapi32.lib /
$(BASEDIR)/lib/*/$(DDKBUILDENV)/ntvdm.lib
DLLENTRY=VDDLibMain
DLLBASE=0x2000000
SOURCES=iovdd.c
INDENTED_DIRECTIVES=1
C_DEFINES=-DWIN_32 -DDEBUG
5,MAKEFILE
# Sample VDD makefile
#
# Copyright (c) 1991, Microsoft Corporation
#
# History:
# Created 16-Dec-1991 Sudeep Bharati (sudeepb)
#
# DO NOT EDIT THIS FILE!!! Edit ./sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the components of NT OS/2
#
!INCLUDE $(NTMAKEENV)/makefile.def
有了这五个源文件,就能用DDK build生成一个iovdd.dll文件了。要让这个vdd起作用,需要把这个dll文件拷到windows/system32目录下,重命名为iovdd1.dll。还需要修改注册表,为了方便广大人民群众,我有整了一个修改注册表的文件iovdd.reg:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Control/VirtualDeviceDrivers]
"VDD"=hex(7):69,00,6F,00,76,00,64,00,64,00,31,00,2E,00,64,00,6C,00,6C,00
什么乱七八糟的?双击后运行就知道了。为什么要把iovdd.dll改名为iovdd1.dll,因为我发现vdd好像必须要有六个字符才能起作用。再要问为什么需要六个字符?只有微软的人能回答了。
现在截取操作的vdd有了,再把它们发送到相应的内核模式驱动程序就大功告成了。现在来写内核驱动程序。编译内核驱动程序需要以下四个文件:
1,simpldrv.c
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
simpldrv.c
Abstract:
A simple kernel-mode driver sample.
Environment:
kernel mode only
Notes:
See readme.txt
Revision History:
06-25-93 : created
--*/
#include "ntddk.h"
#include "stdarg.h"
#include "stdio.h"
#include "simpldrv.h"
//
// The following is the debug print macro- when we are building checked
// drivers "DBG" will be defined (by the /ddk/setenv.cmd script), and we
// will see debug messages appearing on the KD screen on the host debug
// machine. When we build free drivers "DBG" is not defined, and calls
// to SimplDrvKdPrint are removed.
//
typedef struct _GENPORT_WRITE_INPUT {
ULONG PortNumber; // Port # to write to
union { // Data to be output to port
ULONG LongData;
USHORT ShortData;
UCHAR CharData;
};
} GENPORT_WRITE_INPUT;
#ifdef DBG
#define SimplDrvKdPrint(arg) DbgPrint arg
#else
#define SimplDrvKdPrint(arg)
#endif
NTSTATUS
SimplDrvDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
VOID
SimplDrvUnload(
IN PDRIVER_OBJECT DriverObject
);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS ntStatus;
WCHAR deviceNameBuffer[] = L"//Device//SimplDrv";
UNICODE_STRING deviceNameUnicodeString;
PDEVICE_EXTENSION deviceExtension;
WCHAR deviceLinkBuffer[] = L"//DosDevices//SIMPLDRV";
UNICODE_STRING deviceLinkUnicodeString;
SimplDrvKdPrint (("SIMPLDRV.SYS: entering DriverEntry/n"));
//
// A real driver would:
//
// 1. Report it's resources (IoReportResourceUsage)
//
// 2. Attempt to locate the device(s) it supports
//
// OK, we've claimed our resources & found our h/w, so create
// a device and initialize stuff...
//
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer
);
//
// Create an EXCLUSIVE device, i.e. only 1 thread at a time can send
// i/o requests.
//
ntStatus = IoCreateDevice (DriverObject,
sizeof (DEVICE_EXTENSION),
&deviceNameUnicodeString,
FILE_DEVICE_SIMPLDRV,
0,
TRUE,
&deviceObject
);
if (NT_SUCCESS(ntStatus))
{
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
//
// Set up synchronization objects, state info,, etc.
//
//
// Create a symbolic link that Win32 apps can specify to gain access
// to this driver/device
//
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceLinkBuffer
);
ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
&deviceNameUnicodeString
);
if (!NT_SUCCESS(ntStatus))
{
SimplDrvKdPrint (("SIMPLDRV.SYS: IoCreateSymbolicLink failed/n"));
}
//
// Create dispatch points for device control, create, close.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SimplDrvDispatch;
DriverObject->DriverUnload = SimplDrvUnload;
}
//done_DriverEntry:
if (!NT_SUCCESS(ntStatus))
{
//
// Something went wrong, so clean up (free resources, etc.)
//
if (deviceObject)
IoDeleteDevice (deviceObject);
}
return ntStatus;
}
NTSTATUS
SimplDrvDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
{
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
PVOID ioBuffer; //PVOID
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
NTSTATUS ntStatus;
// added by PLT
unsigned char ucValue = 13;
GENPORT_WRITE_INPUT ucValue1;
ULONG ucValue2;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// Get a pointer to the device extension
//
deviceExtension = DeviceObject->DeviceExtension;
//
// Get the pointer to the input/output buffer and it's length
//
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (irpStack->MajorFunction)
{
case IRP_MJ_CREATE:
SimplDrvKdPrint (("SIMPLDRV.SYS: IRP_MJ_CREATE/n"));
break;
case IRP_MJ_CLOSE:
SimplDrvKdPrint (("SIMPLDRV.SYS: IRP_MJ_CLOSE/n"));
break;
case IRP_MJ_DEVICE_CONTROL:
// SimplDrvKdPrint (("SIMPLDRV.SYS: IRP_MJ_DEVICE_CONTROL/n"));
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (ioControlCode)
{
case IOCTL_SIMPLDRV_HELLO:
{
//
// Some app is saying hello
//
RtlMoveMemory(&ucValue2,ioBuffer,sizeof(ucValue2));
switch (ucValue2)
{
case 0x300:
{
__asm
{
mov al,80H
mov dx,03FBH
out dx,al
mov al,0CH
mov dx,03F8H
out dx,al
mov al,00H
mov dx,03F9H
out dx,al
mov al,03H
mov dx,03FBH
out dx,al
// mov dx,03fch
// out dx,al
mov al,00H
mov dx,03F9H
out dx,al
}
// added by PLT
RtlMoveMemory(ioBuffer, &ucValue, sizeof(ucValue));
Irp->IoStatus.Information = sizeof(ucValue);
break;
}
case 0x301:
{
__asm
{
MOV DX,03FDH
COM_IN1:
in al,dx
// _emit 0xEC
TEST al,01
JE COM_IN1
MOV DX,03F8H
in al,dx
// _emit 0xEC
MOV ucValue,al
}
// _asm mov dx,3F8H
// _asm in al,dx
// _asm mov ucValue,al
RtlMoveMemory(ioBuffer, &ucValue, sizeof(ucValue));
Irp->IoStatus.Information = sizeof(ucValue);
break;
}
/* case 0x304:
{
_asm mov dx,3FDH
_asm in al,dx
_asm mov ucValue,al
RtlMoveMemory(ioBuffer, &ucValue, sizeof(ucValue));
Irp->IoStatus.Information = sizeof(ucValue);
break;
}*/
}
break;
}
case IOCTL_GPD_WRITE_PORT_UCHAR:
{
// SimplDrvKdPrint (("SIMPLDRV.SYS: zouyu_ok/n"));
RtlMoveMemory(&ucValue1,ioBuffer,5);
switch (ucValue1.PortNumber)
{
/* case 0x301:
{
_asm mov dx,3FBH
_asm mov al,ucValue1.CharData
_asm out dx,al
SimplDrvKdPrint (("SIMPLDRV.SYS: 3FBH/n"));
break;
}*/
case 0x302:
{
__asm
{
mov dx,03FDH
COM_OUT1:
in al,dx
test al,20H
je COM_OUT1
mov al,ucValue1.CharData
mov dx,03F8H
out dx,al
}
/*
// _asm mov dx,3F8H
// _asm mov al,ucValue1.CharData
// _asm out dx,al
if (ucValue1.CharData==0xfe)
{
SimplDrvKdPrint (("SIMPLDRV.SYS: 0xfe/n"));
}
else
{
SimplDrvKdPrint (("SIMPLDRV.SYS: other/n"));
}*/
break;
}
/* case 0x303:
{
_asm mov dx,3F9H
_asm mov al,ucValue1.CharData
_asm out dx,al
SimplDrvKdPrint (("SIMPLDRV.SYS: 3F9H/n"));
break;
}*/
}
break;
}
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
SimplDrvKdPrint (("SIMPLDRV.SYS: unknown IRP_MJ_DEVICE_CONTROL/n"));
break;
}
break;
}
//
// DON'T get cute and try to use the status field of
// the irp in the return status. That IRP IS GONE as
// soon as you call IoCompleteRequest.
//
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest (Irp,
IO_NO_INCREMENT
);
//
// We never have pending operation so always return the status code.
//
return ntStatus;
}
VOID
SimplDrvUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object
Return Value:
--*/
{
WCHAR deviceLinkBuffer[] = L"//DosDevices//SIMPLDRV";
UNICODE_STRING deviceLinkUnicodeString;
//
// Free any resources
//
//
// Delete the symbolic link
//
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceLinkBuffer
);
IoDeleteSymbolicLink (&deviceLinkUnicodeString);
//
// Delete the device object
//
IoDeleteDevice (DriverObject->DeviceObject);
SimplDrvKdPrint (("SIMPLDRV.SYS: unloading/n"));
}
2,simpldrv.h
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
simpldrv.h
Abstract:
This module contains the PRIVATE (driver-only) definitions for the
code that implements the mono device driver.
Environment:
Kernel & user mode
Revision History:
06-25-93 : created
--*/
//
// A structure representing the instance information associated with
// a particular device
//
typedef struct _DEVICE_EXTENSION
{
ULONG StateVariable;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
//
// Define the various device type values. Note that values used by Microsoft
// Corporation are in the range 0-32767, and 32768-65535 are reserved for use
// by customers.
//
#define FILE_DEVICE_SIMPLDRV 0x00008300
//
// Macro definition for defining IOCTL and FSCTL function control codes. Note
// that function codes 0-2047 are reserved for Microsoft Corporation, and
// 2048-4095 are reserved for customers.
//
#define SIMPLDRV_IOCTL_INDEX 0x830
//
// The MONO device driver IOCTLs
//
#define IOCTL_SIMPLDRV_HELLO CTL_CODE(FILE_DEVICE_SIMPLDRV, /
SIMPLDRV_IOCTL_INDEX, /
METHOD_BUFFERED, /
FILE_ANY_ACCESS)
#define IOCTL_GPD_WRITE_PORT_UCHAR /
CTL_CODE(FILE_DEVICE_SIMPLDRV, SIMPLDRV_IOCTL_INDEX+1, METHOD_BUFFERED, FILE_ANY_ACCESS)
3,SOURCES
TARGETNAME=simpldrv
TARGETPATH=obj
TARGETTYPE=DRIVER
SOURCES=simpldrv.c
4,MAKEFILE
#
# DO NOT EDIT THIS FILE!!! Edit ./sources. if you want to add a new source
# file to this component. This file merely indirects to the real make file
# that is shared by all the driver components of the Windows NT DDK
#
!INCLUDE $(NTMAKEENV)/makefile.def
编译成功后会生成一个simpldrv.sys,怎样加载这个sys文件,搞过windows设备驱动程序的人都知道,应该不用我多说了。
最后补充说一句,因为这些代码都是97年写的了,很多源程序没有多加注解,看帖的朋友只有自己多体会了。