有过dos编程经历的老鸟们一定都很怀念在dos平台上写程序的随心所欲的日子。前几天看到一篇开发dos虚拟机程序的技术文章,说是可以在不修改16位dos程序的情况下,让dos程序在win32上跑起来,我一下来了兴趣,可写出来的东西怎么也没法加载。最后我在苏联老大哥的一个偏僻的网站上找到几段代码,虽说俄文我一点不懂,可那几段代码经过我稍加修改,居然编译通过并加载成功了。为了感谢苏联老大哥对我国社会主义建设事业的无私援助,我将我修改编译成功的代码贴在下面,希望对想写dos虚拟机程序的朋友有所帮助。代码由六个文件组成,就像发现远古时期的藏宝图总会残缺不全一样,应该有一些文件遗失了,不过这对由一定功底的朋友应该不是问题了。我至今没搞懂这些代码是一个什么东西的驱动程序。以下是六个程序的源代码:
1,sources文件:
TARGETNAME=mi1201
TARGETPATH=obj
TARGETTYPE=DYNLINK
TARGETLIBS=$(BASEDIR)/lib/*/$(DDKBUILDENV)/kernel32.lib /
$(BASEDIR)/lib/*/$(DDKBUILDENV)/ntvdm.lib
DLLENTRY=VDDInitialize
DLLBASE=0x2000000
SOURCES=vdd.c
INDENTED_DIRECTIVES=1
C_DEFINES=-DWIN_32 -DDEBUG
2,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
3,mi1201.def文件:
LIBRARY VDD
EXPORTS
VDDInitialize
4,gpioctl.h文件:
// Device type -- in the "User Defined" range."
#define GPD_TYPE 40000
// The IOCTL function codes from 0x800 to 0xFFF are for customer use.
#define IOCTL_GPD_READ_PORT_UCHAR /
CTL_CODE( GPD_TYPE, 0x900, METHOD_BUFFERED, FILE_READ_ACCESS )
#define IOCTL_GPD_READ_PORT_USHORT /
CTL_CODE( GPD_TYPE, 0x901, METHOD_BUFFERED, FILE_READ_ACCESS )
#define IOCTL_GPD_READ_PORT_ULONG /
CTL_CODE( GPD_TYPE, 0x902, METHOD_BUFFERED, FILE_READ_ACCESS )
#define IOCTL_GPD_WRITE_PORT_UCHAR /
CTL_CODE(GPD_TYPE, 0x910, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_GPD_WRITE_PORT_USHORT /
CTL_CODE(GPD_TYPE, 0x911, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_GPD_WRITE_PORT_ULONG /
CTL_CODE(GPD_TYPE, 0x912, METHOD_BUFFERED, FILE_WRITE_ACCESS)
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;
5,vdd.h文件:
#include "windows.h"
// VDD services header
#include <vddsvc.h>
// private macro definitions
#define PAGE_SIZE 0x1000
/*disconnected I/O value */
#define FLOATING_IO 0xFF
#define FLOATING_MIO 0xFF
// I/O mapped I/O
#define IO_PORT_FIRST1 0xED00
#define IO_PORT_LAST1 0xEE00
#define IO_PORT_FIRST2 0x120
#define IO_PORT_LAST2 0x127
#define IO_PORT_FIRE_DMA_SLOW IO_PORT_FIRST
#define IO_PORT_FIRE_DMA_FAST IO_PORT_FIRST + 1
#define IO_PORT_DMA IO_PORT_FIRST + 2
#define IO_PORT_RANGE IO_PORT_LAST - IO_PORT_FIRST + 1
// memory mapped I/O
#define MIO_SEGMENT 0xC000
#define MIO_PORT_FIRST 0
#define MIO_PORT_LAST 7
#define MIO_PORT_FIRE_DMA MIO_PORT_FIRST
#define MIO_PORT_DMA MIO_PORT_FIRST + 1
#define MIO_PORT_RANGE MIO_PORT_LAST - MIO_PORT_FIRST + 1
#define MIO_ADDRESS ((((ULONG)MIO_SEGMENT) << 16) | MIO_PORT_FIRST)
// DMA
#define DMA_CHANNEL 1
#define DMA_PORT_BASE 0
#define DMA_SHIFT_COUNT 0
#define DMA_INTERRUPT_LINE 2
#define DMA_INTERRUPT_PIC ICA_SLAVE
#define DMA_PORT_PAGE 0x83
#define DMA_PORT_ADDR DMA_PORT_BASE + 2
#define DMA_PORT_COUNT DMA_PORT_BASE + 3
#define DMA_PORT_CMD DMA_PORT_BASE + 8
#define DMA_PORT_REQUEST DMA_PORT_BASE + 9
#define DMA_PORT_SNGLE_MASK DMA_PORT_BASE + 10
#define DMA_PORT_MODE DMA_PORT_BASE + 11
#define DMA_PORT_FLIPFLOP DMA_PORT_BASE + 12
#define DMA_PORT_TEMP DMA_PORT_BASE + 13
#define DMA_PORT_CLEARMASK DMA_PORT_BASE + 14
#define DMA_PORT_WRTEMASK DMA_PORT_BASE + 15
/* function prototype definitions */
/* entry function of VDD */
BOOL VddDllEntry(HANDLE hVdd, DWORD dwReason, LPVOID lpReserved);
/* private functions */
VOID MyInB(WORD, PBYTE);
VOID MyOutB(WORD, BYTE);
VOID MyMIOHandler(ULONG, ULONG);
WORD FakeDD_DMARead(PBYTE, WORD);
WORD FakeDD_DMAWrite(PBYTE, WORD);
BOOLEAN SlowDMA();
BOOLEAN FastDMA();
6,vdd.c文件:
#include "vdd.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <winioctl.h>
#include "gpioctl.h"
/** Global variables **/
HANDLE hndFile;
HANDLE hVDD; /* VDD module handle */
BOOL IOHook; /* true if we installed a I/O hooked */
// BOOLEAN IOHook; /* true if we installed a I/O hooked */
static VDD_IO_PORTRANGE PortRange[2];
BOOL
VDDInitialize(
HANDLE hVdd,
DWORD dwReason,
LPVOID lpReserved)
{
VDD_IO_HANDLERS IOHandlers[2];
hVDD = hVdd;
switch ( dwReason ) {
case DLL_PROCESS_ATTACH:
hndFile = CreateFile(
".//PortIODev", // Open the Device "file"
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
IOHandlers[0].inb_handler = MyInB;
IOHandlers[0].inw_handler = NULL;
IOHandlers[0].insb_handler = NULL;
IOHandlers[0].insw_handler = NULL;
IOHandlers[0].outb_handler = MyOutB;
IOHandlers[0].outw_handler = NULL;
IOHandlers[0].outsb_handler = NULL;
IOHandlers[0].outsw_handler = NULL;
PortRange[0].First = IO_PORT_FIRST1;
PortRange[0].Last = IO_PORT_LAST1;
// 呩忪 ぅ?イΕ?
// IOHandlers[1]=IOHandlers[0]
IOHandlers[1].inb_handler = MyInB;
IOHandlers[1].inw_handler = NULL;
IOHandlers[1].insb_handler = NULL;
IOHandlers[1].insw_handler = NULL;
IOHandlers[1].outb_handler = MyOutB;
IOHandlers[1].outw_handler = NULL;
IOHandlers[1].outsb_handler = NULL;
IOHandlers[1].outsw_handler = NULL;
PortRange[1].First = IO_PORT_FIRST2;
PortRange[1].Last = IO_PORT_LAST2;
// hook I/O mapped I/O
IOHook = VDDInstallIOHook(hVDD, (WORD)2, PortRange, IOHandlers);
break;
case DLL_PROCESS_DETACH:
// communicate to appropriate Device driver about your departure
if (IOHook)
VDDDeInstallIOHook(hVDD, 2, PortRange);
CloseHandle(hndFile);
break;
default:
break;
}
return TRUE;
}
VOID
MyInB(
WORD Port,
PBYTE Buffer
)
{
ULONG PortNumber = Port;
DWORD ReturnedLength;
DeviceIoControl(
hndFile, // Handle to device
IOCTL_GPD_READ_PORT_UCHAR, // IO Control code for Read
&PortNumber, // Buffer to driver.
sizeof(PortNumber), // Length of buffer in bytes.
Buffer, // Buffer from driver.
1, // Length of buffer in bytes.
&ReturnedLength, // Bytes placed in DataBuffer.
NULL // NULL means wait till op. completes.
);
}
VOID
MyOutB(
WORD Port,
BYTE Data
)
{
GENPORT_WRITE_INPUT InputBuffer;
DWORD ReturnedLength;
InputBuffer.PortNumber = Port;
InputBuffer.CharData = Data;
DeviceIoControl(
hndFile, // Handle to device
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.
);
Data = InputBuffer.CharData;
}
我在此基础上开发了一个dos虚拟机程序,16位的串口程序可以不用修改在上面运行,考虑到现在搞这些古怪玩意儿的人不多,程序的代码又不少,就不想贴出来了,有感兴趣的朋友可以在下面留言,我发现有知音就贴出来。