⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jiurl键盘驱动 2.htm

📁 JIURL键盘驱动
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0058)http://jiurl.nease.net/cn/document/KbdDriver/JiurlKbd2.htm -->
<HTML><HEAD><TITLE>JIURL键盘驱动 2</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<STYLE type=text/css>.title {
	FONT-WEIGHT: bold; FONT-SIZE: 21px; LINE-HEIGHT: 48px; FONT-FAMILY: "黑体", Arial, sans-serif; TEXT-DECORATION: none
}
.author {
	FONT-SIZE: 12px; LINE-HEIGHT: 16px; FONT-FAMILY: "宋体"
}
.content {
	FONT-SIZE: 14px; LINE-HEIGHT: 20px
}
</STYLE>

<META content="MSHTML 6.00.2900.2668" name=GENERATOR></HEAD>
<BODY bgColor=#f7f7f7 topMargin=5>
<DIV align=center>
<CENTER>
<TABLE height=29 cellSpacing=0 cellPadding=0 width="96%" border=0>
  <TBODY>
  <TR>
    <TD class=title width="100%" height=41>
      <P align=center><FONT face=宋体>JIURL键盘驱动 2</FONT></P></TD></TR></CENTER>
  <TR>
    <TD class=author width="100%" height=9>
      <P align=center><FONT face=宋体>作者: <A 
      href="mailto:jiurl@mail.china.com">JIURL</A> </FONT></P></TD></TR>
  <TR>
    <TD class=author width="100%" height=6>
      <P align=center><FONT 
      face=宋体>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
      主页: <A href="http://jiurl.yeah.net/">http://jiurl.yeah.net/</A> 
    </FONT></P></TD></TR>
  <TR>
    <TD class=author width="100%" height=2>
      <P align=center><FONT face=宋体>&nbsp;&nbsp;&nbsp; 日期: 2003-12-13</FONT> 
    </P></TD></TR></TBODY></TABLE></DIV>
<DIV align=center>
<CENTER>
<TABLE height=1 cellSpacing=0 cellPadding=0 width="96%" border=0>
  <TBODY>
  <TR>
    <TD width="100%" height=1>
      <HR color=#396da5 SIZE=3>
    </TD></TR></TBODY></TABLE></CENTER></DIV>
<DIV align=center>
<TABLE class=content height=200 cellSpacing=0 cellPadding=0 width="96%" 
border=0>
  <TBODY>
  <TR>
    <TD vAlign=top width="131%" height=200>
      <P><B>2 应用层基础知识</B><BR><BR>&nbsp;&nbsp;&nbsp; 在讨论使用键盘的应用程序这个问题之前,我们首先介绍一下 
      Windows 中,应用程序使用驱动,应用程序与驱动通信的一些问题。<BR><BR>2.1 
      应用程序如何使用驱动<BR><BR>&nbsp;&nbsp;&nbsp; 应用程序中使用 
      CreateFile,ReadFile,WriteFile,DeviceIoControl,CloseHandle 
      来指示驱动程序完成某种任务。比如我们在应用程序中使用 ReadFile 来让驱动读取硬件设备,我们在应用程序中使用 WriteFile 
      来让驱动写硬件设备,我们在应用程序中使用 DeviceIoContorl 来让驱动完成某些驱动支持的功能。而 ReadFile, 
      WriteFile, DeviceIoControl 这三个 api 都需要一个句柄作为参数,以确定他们是要哪个驱动来完成他们的请求。这个句柄是通过 
      CreateFile 获得的。使用 CloseHandle 关闭这个句柄。简单的说就是,应用程序中,首先要通过 CreateFile 
      获得一个句柄,之后应用程序可以以这个句柄为参数,使用 ReadFile,WriteFile,DeviceIoControl 
      让驱动程序执行某种操作。当不再使用时,通过 CloseHandle 关闭这个句柄。<BR><BR>&nbsp;&nbsp;&nbsp; 这几个 
      api 都位于 KERNEL32.DLL 中,他们最终会通过系统服务(int 2e)调用内核中的相应的函数,如 
      NtCreateFile,NtReadFile 等。而 NtCreateFile,NtReadFile 等函数中,会创建一个 
      IRP,并用传入的参数初始化这个 IRP,然后将这个 IRP 发给驱动,让驱动做处理。相应的 NtCreateFile 产生 
      IRP_MJ_CREATE 的 IRP ,NtReadFile 产生 IRP_MJ_READ 的 IRP。驱动得到这些 IRP 
      ,根据情况做处理,对于 IRP_MJ_READ ,会调用驱动中处理 IRP_MJ_READ 
      的部分,可能最后引起读硬件的操作。<BR><BR><BR>2.2 获得指定驱动的句柄<BR><BR>&nbsp;&nbsp;&nbsp; 
      对于希望被应用程序使用的驱动,会在初始化的过程中,把能找到它设备对象的一个 SymbolicLink 放在对象管理器命名空间(Object 
      Manager Namespace)的 \??\ 下。这样用 "\\\\.\\那个SymbolicLink的名字" 作为 CreateFile 的 
      lpFileName 参数,调用 CreateFile ,得到的句柄就可以找到相应的驱动的那个设备对象(\\.\ 会被转换成 
      \??\)。之后以这个句柄为参数使用 ReadFile,WriteFile,DeviceIoControl,产生的 IRP 
      就被发到相应的设备对象。也就是说只要驱动把 设备对象的 SymbolicLink 放在 \??\ 下,并且应用程序知道这个 SymbolicLink 
      的名字,就可以使用 CreateFile 得到相应的句柄。<BR><BR>HANDLE CreateFile(<BR>LPCTSTR 
      lpFileName, // file name<BR>DWORD dwDesiredAccess, // access mode<BR>DWORD 
      dwShareMode, // share mode<BR>LPSECURITY_ATTRIBUTES lpSecurityAttributes, 
      // SD<BR>DWORD dwCreationDisposition, // how to create<BR>DWORD 
      dwFlagsAndAttributes, // file attributes<BR>HANDLE hTemplateFile // handle 
      to template file<BR>);<BR><BR><BR>可以使用工具 WinObj 来查看 对象管理器命名空间(Object 
      Manager Namespace) 。WinObj 可以从 http://www.sysinternals.com 
      获得。关于内核对象和命名地址空间的详细介绍,可以参考《 JIURL玩玩Win2k 对象 
      》,这篇文章可以在我的主页上找到。<BR><BR>在驱动的初始化过程中,会通过调用 IoCreateDevice 
      创建设备对象,可以指定一个设备名作为IoCreateDevice 的参数(也可以不指定,那样这个设备对象就没有名字)。这样这个设备对象会被放在 
      对象管理器命名空间(Object Manager Namespace)的 \Device\ 下。不过应用程序只能访问命名空间的 \??\ 
      ,所以如果驱动希望把设备对象暴露给应用程序的话,会为设备对象创建一个 SymbolicLink 放在 \??\ 下。对于放在 \Device\ 
      下的有名字的设备,其他驱动程序如果知道它的名字,就可以使用 IoGetDeviceObjectPointer 
      得到这个设备对象的指针。<BR><BR>驱动可以通过 IoCreateSymbolicLink ,在 \??\ 下建立设备对象的 
      SymbolicLink 。这样应用程序必须要也知道该 SymbolicLink 的名字,然后就可以以这个符号链接名做参数使用 CreateFile 
      ,得到句柄。从 IoCreateSymbolicLink 的参数,我们可以知道,只能使用 IoCreateSymbolicLink 
      为有名字的设备对象建立 SymbolicLink。<BR><BR>另一种方法是,使用一个 GUID 来标识一个设备接口。驱动使用标识设备的 GUID 
      做参数调用IoRegisterDeviceInterface ,然后使用 IoSetDeviceInterfaceState ,就会为设备对象在 
      \??\ 下产生一个符号链接(SymbolicLink)。应用程序使用同一个 GUID 做参数,使用API: 
      SetupDiGetClassDevs, SetupDiEnumDeviceInterfaces, 
      SetupDiGetDeviceInterfaceDetail 就可以得到创建的 \??\ 下的符号链接名,就可以以这个符号链接名做参数使用 
      CreateFile ,得到句柄。<BR><BR>&nbsp;&nbsp;&nbsp; 
      句柄简介。每个进程都有一个自己的句柄表,句柄表中放着内核对象的指针,句柄就是内核对象在句柄表中的索引。通过句柄就可以在进程的句柄表中找到对应的内核对象的指针。关于句柄的详细介绍,可以参考 
      《 JIURL玩玩Win2k 进程线程篇 HANDLE_TABLE 》,这篇文章可以在我的主页上找到。<BR><BR>2.3 
      一些结论<BR><BR>&nbsp;&nbsp;&nbsp; SymbolicLink 对象可以找到相应的 设备对象。SymbolicLink 
      对象中保存着相应的 设备对象的地址。设备对象不保存它的 SymbolicLink 对象的任何信息。SymbolicLink 
      对象的地址保存在对象管理器命名空间(Object Manager Namespace)中。也就是说只要知道 SymbolicLink 
      的名字,就可以在对象管理器命名空间中找到它。应用程序 CreateFile 得到的句柄,通过这个句柄在进程的句柄表中找到的是一个文件对象(File 
      Object)。文件对象 对应的 设备对象 中不保存这个文件对象的任何信息。对应的 SymbolicLink 
      对象中也不保存这个文件对象的任何信息。这个文件对象的地址,保存在应用程序的句柄表中,应用程序通过句柄可以找到这个文件对象。这个 文件对象 
      中保存着对应的 设备对象 的地址。可以猜到,应用程序在用 CreateFile 创建的时候,会根据参数中的 SymolicLink 名字,找到 
      SymolicLink 对象,进而找到该对象中保存的 设备对象 的地址,然后直接把找到的 设备对象 的地址保存在文件对象中。文件对象的 +04 
      struct _DEVICE_OBJECT *DeviceObject 
      处,保存着对应的设备对象的地址。<BR><BR>&nbsp;&nbsp;&nbsp; 对于需要暴露接口给应用程序的驱动。首先,驱动中需要在 
      对象管理器命名空间的 \??\ 下,为设备对象建立一个 SymbolicLink ,不管采取何种方式。之后,应用程序要知道这个 
      SymbolicLink 的名字,不管采取何种方式。然后应用程序以 "\\\\.\\那个SymbolicLink的名字" 为参数使用 
      CreateFile 得到一个句柄。这样,之后的 DeviceIoControl(),WriteFile(),ReadFile() 使用前面用 
      CreateFile 得到的句柄作为参数,他们可以通过这个句柄,找到对应的文件对象,而这个文件对象中保存有对应的 设备对象 的指针,这样就可以将 
      IRP 发到这些设备。&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp; 
      上面的结论是通过对一个小例子进行观察得到的。<BR><BR>2.4 IRP 将被发往设备栈的栈顶<BR><BR>&nbsp;&nbsp;&nbsp; 
      IRP 
      将无论如何被发往设备栈的顶。CreateFile,ReadFile,WriteFile,DeviceIoControl,CloseHandle。他们最终都会产生一个 
      IRP,发给一个设备对象。对于 CreateFile 来说通过 SymbolicLink的名字 
      来找到一个设备对象。对于其他的几个函数,通过句柄,找到一个文件对象,文件对象中保存有设备对象的指针。不过产生的 IRP 
      并不一定发给找到的这个设备对象,而是发给找到的这个设备对象所在设备栈的最顶上的一个设备对象。<BR><BR>&nbsp;&nbsp;&nbsp; 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -