精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>电脑技术>>○ DOS>>实用资料>>DOS设备驱动程序与Windows进程的通信

主题:DOS设备驱动程序与Windows进程的通信
发信人: chenjr()
整理人: smallhors(1999-07-22 22:58:34), 站内信件

     基于Windows软件平台的应用的迅速普及,使得开发DOS驱动程序与

Windows应用程序接口的需求日益迫切。本文介绍了实模式DOS设备驱动程序访问


Windows保护模式进程动态申请的数据段,实现处于DOS与Windows不同工作模式的


程之间的通信的一种方法。

关键词 进程通信 保护模式 实模式 DOS Driver DPMI



  随着计算机硬件的快速发展,功能强大的Microsoft Windows得到越来越广泛


应用,软件环境由Windows替代DOS是大势所趋。增强模式的虚拟设备驱动棗序桘


VxD(.386文件)是人们能够编写的最强大的Windows应用程序,但却它是Windows编


中一个艰难且高度专业化的分支,而且一般用户应用程序独享自制外部设备硬件


源。Windows 3.x采用非抢先式多任务消息驱动运行机制,所以Windows下如何解


实时高速数据采集问题,便显得非常重要。Windows 3.x应用程序虽然可以运行在


护模式下,享有多于1M的内存,但它并未脱离实模式的DOS。在实时获取和控制系


中,为快速响应外界变化而编写DOS设备驱动程序是简单而有效的选择。显而易见


必须解决实模式的DOS设备驱动程序与保护模式的Windows进程之间的通信问题。


Windows API

  能否既充分利用Windows统一、美观的交互界面,又能够保障数据采集的实时


呢?答案是肯定的。利用Windows提供的DPMI(DOS保护模式接口)功能,以及内核


数GlobalDOSAlloc(),就可以实现由DOS设备驱动程序直接访问Windows应用程序


态申请的缓冲区的目的。这个函数可以分配既能够被Windows应用程序存取,也能


DOS 设备驱动程序访问的内存块。

  Windows 3.x通常运行于386增强模式,亦即对应着DOS环境下的保护模式。在


强模式下,由于增加了虚拟内存管理,由描述符表(GDT和LDT)得到的线性地址与


理地址之间并没有必然的联系。它们之间只有一种类似于表格的对应关系,所以


要利用DOS保护模式接口(DPMI)来完成这项工作。

①DWORD GlobalDosAlloc(cbAlloc)棗在 GWindows环境中分配一块能在MS- DOS实


式下管理的全局内存。

DWORD cbAlloc; /* 指定要分配的内存字节数*/

  函数GlobalDosAlloc()分配的内存保证位于第一个1M线性地址空间之内。因


系统内存池是极为有限系统资源,所以,应用程序都应尽量压缩该函数所申请的


存尺寸。函数返回值的高字是段值,而低字是相应的段选择符。DOS Driver可以


用段值访问实模式内存,而Windows应用程序则利用段选择符访问保护模式内存。


果Windows不能分配所要求大小的内存块,将返回零值。

  注意:通过GlobalDosAlloc()函数分配的内存空间不需要象通常进行数据存


那样,使用GlobalLock()函数来锁定该段内存空间。

②UINT GlobalDosFree(uPMSelector)棗释放前面由sFGlobalDosAlloc函数分配的
 

全局内存对象。

UINT uPMSelector; /* 待释放的内存段选择符*/

③WORD HIWORD(DWORD dwInteger)棗取出参数(DdwInteger所指定的32位整数值的


高字。

④WORD LOWORD(DWORD dwVal)棗取出参数VadwVal所指定的32位整数值 的低字。


程序设计

  下面列出的程序展示了具体的实现过程,它通过调用Windows内核函数

GlobalDosAlloc()申请内存块作为与DOS Driver进行通信的缓冲区。设备驱动程


DOSDRV.EXE挂接中断77h(对应IRQ15),既可以等待来自硬件的中断,数据采集完


之后,向Windows应用程序WINCOMM.EXE发送消息,通知其进行数据接收和处理;


可以由Windows进程向DOS Driver发出服务请求,自主地完成数据的获取。

  由于程序篇幅较长,下面只列出关键部分,并加以说明。

Ⅰ.DOSDRV.ASM:

①DOS Driver安装检查
入口:
AX = 通信印鉴
BX = 0
出口:
BX = 通信印鉴
②DOS Driver数据处理
入口:
    AX = 通信印鉴
   BX = 1
    CX = Segment => WORD
   DX = Offset => WORD

name dosdrv
Vect_Num equ 77h
Int_Flag equ 1234h
_TEXT segment word public 'CODE'
assume cs:_TEXT,ds:_TEXT
oldint dd 0 ;原中断向量地址
handle proc
[push ......] ;保护现场
cmp ax, Int_Flag ;鉴别通信印鉴
jnz short old_vect ;否,转数据采集
cmp bx, 0 ;申请类别鉴定
jnz short check
mov bx, ax ;设置检查成功标志
jmp short return
check: cmp bx, 1 ;申请类别鉴定
jnz short old_vect ;否,转数据采集
mov ds, cx
mov bx, dx ;内存地址定位
; ... 
;用户编制的数据处理过程
; ... 
jmp short return
old_vect: ;数据采集,中断寄存器设置,判断是否有接受消息的窗口
return: [pop ......] ;恢复现场
iret
handle endp
ALIGN 16
init_resident: 
dosdrv proc far
 [ ...... ] ;中断向量地址的保存、设置,以及程序驻留
dosdrv endp
_TEXT ends
 end dosdrv

Ⅱ.WINCOMM.CPP:
DWORD FAR PASCAL GlobalDosAlloc (DWORD);
UINT FAR PASCAL GlobalDosFree (UINT);
void IsTSR (void);
void CallTSR (void);

#include "windows.h"
#define WM_DOSWINCOMM WM_USER+1
int TestTSR = 0;
WORD PMSelector=0, SegAddr;
WORD FAR *farPtr;
DWORD windowsFlag;
long CALLBACK __export MainWndProc(hWnd, message, wParam, lParam)
HWND hWnd; UINT message; WPARAM wParam; LPARAM lParam; 
{ DWORD memoryPtr; /*Windows进程消息处理*/
switch (message)
{  case WM_CREATE: /*用户数据初始化过程*/
windowsFlag = GetWinFlags();
case WM_DOSWINCOMM:
if (! (windowsFlag & WF_PMODE))
{ /*Windows处于实模式的处理过程*/ break; }
IsTSR();
if (0==TestTSR)
       { /*DOS Driver未安装处理过程*/ }
else
if (0==PMSelector)
       { /*申请内存失败的处理*/ }
else
{ /*用户可根据需要申请内存*/
memoryPtr = GlobalDosAlloc(2);
PMSelector = LOWORD (memoryPtr);
SegAddr = HIWORD (memoryPtr); 
farPtr = (WORD FAR *) ( (DWORD)PMSelector << 16);
         CallTSR();
/*用户编制的处理过程*/
if (0!=PMSelector)
PMSelector = GlobalDosFree (PMSelector);
break;  }
   case WM_DESTROY:
if (0!=PMSelector)
PMSelector = GlobalDosFree (PMSelector);
PostQuitMessage(0);
break;
default: return (DefWindowProc(hWnd, message, wParam, lParam)); }
return (NULL);
}
下面的程序段为保护模式与实模式的接口:
void IsTSR()
{ _asm{ mov ax, 0200h
mov bl, 77h
int 31h ; DPMI调用
or cx, dx
jz short notsr
mov ax, 1234h
mov bx, 0
int 77h
;鉴别通信印鉴
cmp bx, 1234h
jnz short notsr
mov TestTSR, -1
notsr: }
}
void CallTSR()
{ _asm{ mov ax, 1234h
mov bx, 1
mov cx, SegAddr
xor dx, dx
int 77h }
}

所谓DPMI,是由Microsoft、Intel、IBM等多家公司联合建立的一种约定,
它规

定了一组服务程序,并可以在保护模式下使用INT 31h来调用它们。这些服务程序


提供者(如Windows 3.1)被称为DPMI服务程序(Server);而这些服务程序的使用者


(如保护模式下的DOS扩展程序)被称为客户程序(Client)。在同一个程序里,当需


由保护模式访问实模式的驱动程序或者TSR程序时,除了DPMI之外,别无选择。

在DOS提示符下运行DOSDRV.EXE程序,从而完成将被WINCOMM.EXE

调用的设备驱动
程序的安装。一旦Windows 被加载,即可运行WINCOMM.EXE程序以实现通信。

结束语

  利用Windows内核函数GlobalDosAlloc()所获得的内存对于Windows虚拟机来


是局部的,因此其它的虚拟机不能够访问该段内存。这种方法作为DOS设备驱动程


与Windows应用程序之间进行通信的一种模式,如经稍加改进,可以实现多个

Windows进程共同拥有一个DOS设备驱动程序,而相互之间互不干扰。当然也可以


现Windows进程之间的通信。


--
小白小白。一洗就白
表白表白。一清二白。。。。。。。。。
你忠实的朋友!!!!!

※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.104.34.196]

[关闭][返回]