驅動程序設計課程大作業(yè)鍵盤過濾驅動程序設計_第1頁
驅動程序設計課程大作業(yè)鍵盤過濾驅動程序設計_第2頁
驅動程序設計課程大作業(yè)鍵盤過濾驅動程序設計_第3頁
驅動程序設計課程大作業(yè)鍵盤過濾驅動程序設計_第4頁
驅動程序設計課程大作業(yè)鍵盤過濾驅動程序設計_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、驅動程序設計 課程大作業(yè)驅動程序設計課程大作業(yè)鍵盤過濾驅動程序設計班級:姓名: 學號:2009年2月11日一、主要設計思路目標:鍵盤過濾驅動。利用驅動分層機制,使用過濾驅動捕獲鍵盤的掃描碼并保存下來;應用程序定時訪問驅動程序取回掃描碼,轉換成相應的按鍵名稱并顯示;通過應用程序設定按鍵映射,應用程序將指令傳送給驅動程序,以實現(xiàn)將指定的按鍵消息轉換成其他按鍵。應用程序驅動程序顯示按鍵設置映射讀掃描碼設置映射捕獲掃描碼 鍵盤過濾驅動是工作在異步模式下的。系統(tǒng)為了得到一個按鍵操作,首先要發(fā)送一個irp_mj_read消息到驅動的設備棧,驅動收到這個irp后,會一直保持這個irp為未確定(pending

2、)態(tài),因為當時并沒有按鍵操作。直到一個鍵被真正的按下,驅動此時就會立刻完成這個irp,并將剛按下的鍵的相關數(shù)據(jù)做為該irp的返回值。在該irp帶著對應的數(shù)據(jù)返回后,操作系統(tǒng)將這些值傳遞給對應的事件系統(tǒng)來處理,然后系統(tǒng)緊接著又會立刻發(fā)送一個irp_mj_read請求,等待下次的按鍵操作,重復以上的步驟。為了實現(xiàn)截獲鍵盤消息,需要在過濾驅動程序中創(chuàng)建一個掛接到物理鍵盤設備上層的過濾驅動設備。系統(tǒng)發(fā)送的irp_mj_read消息會首先到達過濾驅動設備,這樣就可以有機會給irp_mj_read設置指定的完成例程,然后將消息下傳給物理鍵盤設備。當有按鍵動作發(fā)生時,irp_mj_read消息在完成后就會調

3、用指定的完成例程,這時就可以在完成例程中讀出鍵盤動作的內容,或者修改這些信息,以實現(xiàn)按鍵的映射。鍵盤設備過濾設備irp_mj_read設置完成例程完成讀掃描碼標準的按鍵掃描碼和ascii碼沒有直接的對應關系,大部分按鍵的掃描碼為一個字節(jié);部分功能鍵為兩個字節(jié),且都以0xe0為高字節(jié)。但實驗中發(fā)現(xiàn),irp中返回的按鍵信息和標準的掃描碼并不全等。在keyboard_input_data結構中,makecode字段僅包含了一個字節(jié)的編碼,還要同時參照flags字段的內容才能判斷出按鍵的掃描碼。下表是keyboard_input_data結構中兩個字段的內容與其所代表的按鍵動作的對應關系。當flags

4、=0或1時,說明按下的按鍵是掃描碼為一個字節(jié)的按鍵;若flags=2或3,則說明按下的是掃描碼為兩個字節(jié)的按鍵,而makecode中只保留掃描碼的低字節(jié)。flagsmakecode動作0等于掃描碼按下1等于掃描碼松開2掃描碼的低字節(jié)按下3掃描碼的低字節(jié)松開若使用指定的內容改寫返回值中的keyboard_input_data結構,就可以改變按鍵的作用,實現(xiàn)按鍵映射的功能。除了irp_mj_read以外,對于其他發(fā)送給鍵盤設備的消息,到達過濾驅動設備時就可以不做處理,直接下傳給鍵盤設備,以保證系統(tǒng)的正常工作。在完成例程中將每次捕獲得到的掃描碼保存起來,應用程序每隔一定的時間(100ms)讀取一次并

5、將其清空,再根據(jù)掃描碼查表得到相應按鍵的名稱,這樣就可以做到在應用程序中實時的顯示鍵盤動作。用戶在應用程序中設定好按鍵映射的對應關系后,可以通過irp_mj_device_control消息將映射關系發(fā)送給過濾驅動程序,還是在完成例程中實現(xiàn)按鍵的映射替代。2、 模塊的劃分、實現(xiàn)及說明具體實現(xiàn)分為驅動程序和應用程序兩大部分。驅動程序用c和windowsxp ddk實現(xiàn),應用程序通過vc+ 6.0基于mfc實現(xiàn)。在調試和測試中使用了drivermonitor和dbgview等工具。下面分別介紹其中主要部分的實現(xiàn):(一)驅動程序部分1. device_extension的定義/定義設備擴展對象typ

6、edef struct _device_extension pdriver_object pdriver;/對應的驅動pdevice_object pdevice;/驅動對應的設備對象pdevice_object pkbdevice;/掛接到的鍵盤設備unicode_string ustrdevicename;/設備名稱unicode_string ustrsymlinkname;/符號鏈接名ulong irppendingcount;/運行中的irp數(shù)量ulong lastscancode;/最近獲得的鍵盤掃描碼ulong setcode2;/按鍵映射規(guī)則:setcode0->setc

7、ode1 device_extension, *pdevice_extension;2. driverentry主要任務是填寫majorfunction數(shù)組、設置卸載例程,并調用createdevice函數(shù)。對所關心的一些消息分別設置回調函數(shù),為其他消息設置通用處理函數(shù)。/通用事件處理例程for (i=0; i<=irp_mj_maximum_function;i+)pdriverobject->majorfunctioni = keyfilter_dispatchgeneral;/指定卸載驅動例程pdriverobject->driverunload = keyfilter

8、_unload;/捕獲irp_mj_read消息pdriverobject->majorfunctionirp_mj_read = keyfilter_dispatchread;/與應用程序通訊pdriverobject->majorfunctionirp_mj_device_control = keyfilter_deviceiocontrol;pdriverobject->majorfunctionirp_mj_create = keyfilter_onfilecreate;pdriverobject->majorfunctionirp_mj_close = key

9、filter_onclose;3. dispatchgeneral對于不關心的那些消息,返回成功值并傳遞給下一層的鍵盤設備,本層不作處理。/將消息傳遞到下一個單元iocopycurrentirpstacklocationtonext(pirp);/將irp下發(fā)給鍵盤設備status = iocalldriver(pdevext->pkbdevice, pirp);return status;4. createdevice建立設備對象,初始化device_extension結構,建立符號鏈接,將過濾驅動設備掛接到物理鍵盤設備之上。/設備名稱rtlinitunicodestring(&

10、;devname, l"devicekeyfilterdriver");/要掛接的設備rtlinitunicodestring(&hookdevname, l"devicekeyboardclass0");/符號鏈接rtlinitunicodestring(&symlinkname,l"?keyfilterdriver");/建立鍵盤類設備status = iocreatedevice(pdriverobject,/驅動程序對象sizeof(device_extension),/要求的設備擴展的大小&devna

11、me,/設備名稱file_device_keyboard,/設備的類型0,/指示可刪除介質、只讀等。false,/非獨占訪問方式&hookpdeviceobject);/返回的設備對象if(!nt_success(status)/創(chuàng)建設備失敗,輸出調試信息dbgprint("keyfilter: keyboard hook failed to create device!n");return status;/對設備進行必要的初始化hookpdeviceobject->flags |= do_buffered_io;pdevext = (pdevice_exte

12、nsion)hookpdeviceobject->deviceextension;pdevext->pdevice = hookpdeviceobject;pdevext->pdriver = pdriverobject;pdevext->ustrdevicename = devname;pdevext->ustrsymlinkname = symlinkname;pdevext->irppendingcount = 0;pdevext->setcode0 = pdevext->setcode1 = 0;/掛接過濾設備到devicekeyboar

13、dclass0設備的上層status = ioattachdevice(hookpdeviceobject, &hookdevname, &kbddevice);if(!nt_success(status)/連接失敗,輸出調試信息dbgprint("keyfilter: connect with keyboard failed!n");/刪除設備iodeletedevice(hookpdeviceobject);return status;pdevext->pkbdevice = kbddevice;/創(chuàng)建符號鏈接status = iocreatesy

14、mboliclink(&symlinkname,&devname);if(!nt_success(status)dbgprint("keyfilter: create symboliclink failed!n");iodeletedevice(hookpdeviceobject);return status;5. dispatchread在收到irp_mj_read的irp后,為其設置指定的完成例程readcomplete,然后再將irp發(fā)送給物理鍵盤設備。/獲取當前irp包堆棧指針currentirpstack = iogetcurrentirpstac

15、klocation(pirp);/傳遞到下一個單元iocopycurrentirpstacklocationtonext(pirp);/設置完成例程iosetcompletionroutine(pirp, keyfilter_readcomplete, pdeviceobject, true, true, true);/將irp下發(fā)給鍵盤設備status = iocalldriver(pdevext->pkbdevice, pirp);6. readcomplete在irp完成時會調用readcomplete例程,此時用keyboard_input_data結構讀取irp中的返回值,得到

16、按鍵事件的掃描碼并保存。同時若符合按鍵映射規(guī)則,則改寫irp中的返回值,實現(xiàn)按鍵的替換。/獲取當前irp包堆棧指針pirpsp = iogetcurrentirpstacklocation(pirp);if(nt_success(pirp->iostatus.status)/獲得按鍵數(shù)據(jù)keydata = pirp->associatedirp.systembuffer;dbgprint("flag: %d code:0x%04xn", keydata->flags,keydata->makecode);/根據(jù)flags和makecode字段生成掃描

17、碼switch(keydata->flags)case 0:case 1:keycode = keydata->makecode;break;case 2:case 3:keycode = 0xe000 + keydata->makecode;break;case 4:case 5:keycode = 0xe100 + keydata->makecode;break;default:keycode = 0;break;/實現(xiàn)按鍵映射if(keycode = pdevext->setcode0)keycode = pdevext->setcode1;/寫回ir

18、pkeydata->makecode = (ushort)keycode;/只記錄鍵盤按下事件if(keydata->flags=0 | keydata->flags=2 | keydata->flags=4)pdevext->lastscancode = keycode;7. deviceiocontrol實現(xiàn)與應用程序之間的通信。當應用程序通過deviceiocontrol讀掃描碼時,利用irp中的iostatus.information字段返回一個ulong類型的掃描碼。當應用程序設定按鍵映射規(guī)則時,同樣使用deviceiocontrol通過系統(tǒng)內存緩沖區(qū)傳

19、遞兩個ulong型的掃描碼到pdevext->setcode數(shù)組中。/得到當前堆棧currentirpstack = iogetcurrentirpstacklocation(pirp);/得到控制碼iocontrolcode = currentirpstack->parameters.deviceiocontrol.iocontrolcode;switch (iocontrolcode)case read_scancode:/讀掃描碼if(pdevext->lastscancode)dbgprint("read_scancode 0x%04xn",pde

20、vext->lastscancode);info = pdevext->lastscancode;pdevext->lastscancode = 0;break;case set_code:/設定按鍵映射pbuffer = (ulong *)pirp->associatedirp.systembuffer;pdevext->setcode0 = *pbuffer;pbuffer+;pdevext->setcode1 = *pbuffer;info = 1;break;/完成irpstatus = status_success;pirp->iostatu

21、s.status = status;pirp->iostatus.information = info;iocompleterequest(pirp, io_no_increment);return status;(2) 應用程序部分使用mfc實現(xiàn)應用界面,在程序啟動時打開過濾驅動設備。/打開設備m_hdevice = createfile(".keyfilterdriver",generic_read | generic_write,0,null,open_existing,file_attribute_normal,null);if (m_hdevice = in

22、valid_handle_value)cstring str;str.format("獲得設備驅動句柄失敗,錯誤代碼:%d", getlasterror();messagebox(str, "錯誤");exit(0);開辟新的工作線程,實現(xiàn)定時(100ms)讀取捕獲到的鍵盤掃描碼,將掃描碼翻譯成按鍵名稱,并按時間順序將按鍵動作顯示在listbox中。while(1)deviceiocontrol(m_hdevice, read_scancode, null, 0, null, 0, &info, null);if(info)time=ctime:

23、getcurrenttime(); sprintf(mess,"%s code:0x%04x %sn",time.format("%h:%m:%s"),info,codename(info);plistbox1->addstring(mess);plistbox1->setcursel(plistbox1->getcount()-1);sleep(100);設定按鍵映射規(guī)則時,通過deviceiocontrol將兩個dword類型的掃描碼通過系統(tǒng)緩沖io的方式傳遞給驅動程序。getdlgitemtext(idc_edit1,mess,8

24、);sscanf(mess,"0x%x",&code0);getdlgitemtext(idc_edit2,mess,8);sscanf(mess,"0x%x",&code1);if(code0>0xe000 | code1>0xe000)messagebox("請輸入小于0xe000的編碼!");return;deviceiocontrol(m_hdevice, set_code, code, sizeof(code), null, 0, &info, null);3、 所遇到的問題及解決方法鍵盤

25、過濾驅動的卸載問題。在使用常規(guī)的驅動卸載步驟時,會發(fā)生系統(tǒng)藍屏重啟的故障。通過分析和查閱相關資料,終于得出了解決的辦法。由于irm_mj_read是異步的,在給irp_mj_read設置了完成例程的情況下,該irp完成后會調用過濾驅動所指定的完成例程,使得有了處理返回數(shù)據(jù)的機會。但也正是因為這樣,當動態(tài)御載了鍵盤過濾驅動,也就卸載掉了完成例程,而之后的再次按鍵動作在完成了這個irp后還是會調用那個已經(jīng)不存在了的完成例程,因而引發(fā)錯誤。同理可知,在安裝過濾驅動時,就已經(jīng)有一個irp在鍵盤設備驅動中等待按鍵了,而該irp并沒有被設置完成例程。因此可知,在驅動運行之后的第一個按鍵動作是不會被截獲的。在實驗中的確證實了這個推想。動態(tài)卸載的實現(xiàn),是在設備擴展對象中加入一個irppendingcount計數(shù)器,用來記錄正在運行中的

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論