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

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、驅(qū)動(dòng)程序設(shè)計(jì)課程大作業(yè)鍵盤過濾驅(qū)動(dòng)程序設(shè)計(jì)班級(jí):姓名: 學(xué)號(hào):2009年2月11日一、主要設(shè)計(jì)思路目標(biāo):鍵盤過濾驅(qū)動(dòng)。利用驅(qū)動(dòng)分層機(jī)制,使用過濾驅(qū)動(dòng)捕獲鍵盤的掃描碼并保存下來;應(yīng)用程序定時(shí)訪問驅(qū)動(dòng)程序取回掃描碼,轉(zhuǎn)換成相應(yīng)的按鍵名稱并顯示;通過應(yīng)用程序設(shè)定按鍵映射,應(yīng)用程序?qū)⒅噶顐魉徒o驅(qū)動(dòng)程序,以實(shí)現(xiàn)將指定的按鍵消息轉(zhuǎn)換成其他按鍵。應(yīng)用程序驅(qū)動(dòng)程序顯示按鍵設(shè)置映射讀掃描碼設(shè)置映射捕獲掃描碼 鍵盤過濾驅(qū)動(dòng)是工作在異步模式下的。系統(tǒng)為了得到一個(gè)按鍵操作,首先要發(fā)送一個(gè)irp_mj_read消息到驅(qū)動(dòng)的設(shè)備棧,驅(qū)動(dòng)收到這個(gè)irp后,會(huì)一直保持這個(gè)irp為未確定(pending)態(tài),因?yàn)楫?dāng)時(shí)并沒有按鍵

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

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

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

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

6、_device_extension pdriver_object pdriver;/對(duì)應(yīng)的驅(qū)動(dòng)pdevice_object pdevice;/驅(qū)動(dòng)對(duì)應(yīng)的設(shè)備對(duì)象pdevice_object pkbdevice;/掛接到的鍵盤設(shè)備unicode_string ustrdevicename;/設(shè)備名稱unicode_string ustrsymlinkname;/符號(hào)鏈接名ulong irppendingcount;/運(yùn)行中的irp數(shù)量ulong lastscancode;/最近獲得的鍵盤掃描碼ulong setcode2;/按鍵映射規(guī)則:setcode0-setcode1 device_exte

7、nsion, *pdevice_extension;2. driverentry主要任務(wù)是填寫majorfunction數(shù)組、設(shè)置卸載例程,并調(diào)用createdevice函數(shù)。對(duì)所關(guān)心的一些消息分別設(shè)置回調(diào)函數(shù),為其他消息設(shè)置通用處理函數(shù)。/通用事件處理例程for (i=0; imajorfunctioni = keyfilter_dispatchgeneral;/指定卸載驅(qū)動(dòng)例程pdriverobject-driverunload = keyfilter_unload;/捕獲irp_mj_read消息pdriverobject-majorfunctionirp_mj_read = keyfi

8、lter_dispatchread;/與應(yīng)用程序通訊pdriverobject-majorfunctionirp_mj_device_control = keyfilter_deviceiocontrol;pdriverobject-majorfunctionirp_mj_create = keyfilter_onfilecreate;pdriverobject-majorfunctionirp_mj_close = keyfilter_onclose;3. dispatchgeneral對(duì)于不關(guān)心的那些消息,返回成功值并傳遞給下一層的鍵盤設(shè)備,本層不作處理。/將消息傳遞到下一個(gè)單元iocop

9、ycurrentirpstacklocationtonext(pirp);/將irp下發(fā)給鍵盤設(shè)備status = iocalldriver(pdevext-pkbdevice, pirp);return status;4. createdevice建立設(shè)備對(duì)象,初始化device_extension結(jié)構(gòu),建立符號(hào)鏈接,將過濾驅(qū)動(dòng)設(shè)備掛接到物理鍵盤設(shè)備之上。/設(shè)備名稱rtlinitunicodestring(&devname, ldevicekeyfilterdriver);/要掛接的設(shè)備rtlinitunicodestring(&hookdevname, ldevicekeyboardcla

10、ss0);/符號(hào)鏈接rtlinitunicodestring(&symlinkname,l?keyfilterdriver);/建立鍵盤類設(shè)備status = iocreatedevice(pdriverobject,/驅(qū)動(dòng)程序?qū)ο髎izeof(device_extension),/要求的設(shè)備擴(kuò)展的大小&devname,/設(shè)備名稱file_device_keyboard,/設(shè)備的類型0,/指示可刪除介質(zhì)、只讀等。false,/非獨(dú)占訪問方式&hookpdeviceobject);/返回的設(shè)備對(duì)象if(!nt_success(status)/創(chuàng)建設(shè)備失敗,輸出調(diào)試信息dbgprint(keyfi

11、lter: keyboard hook failed to create device!n);return status;/對(duì)設(shè)備進(jìn)行必要的初始化hookpdeviceobject-flags |= do_buffered_io;pdevext = (pdevice_extension)hookpdeviceobject-deviceextension;pdevext-pdevice = hookpdeviceobject;pdevext-pdriver = pdriverobject;pdevext-ustrdevicename = devname;pdevext-ustrsymlinkna

12、me = symlinkname;pdevext-irppendingcount = 0;pdevext-setcode0 = pdevext-setcode1 = 0;/掛接過濾設(shè)備到devicekeyboardclass0設(shè)備的上層status = ioattachdevice(hookpdeviceobject, &hookdevname, &kbddevice);if(!nt_success(status)/連接失敗,輸出調(diào)試信息dbgprint(keyfilter: connect with keyboard failed!n);/刪除設(shè)備iodeletedevice(hookpde

13、viceobject);return status;pdevext-pkbdevice = kbddevice;/創(chuàng)建符號(hào)鏈接status = iocreatesymboliclink(&symlinkname,&devname);if(!nt_success(status)dbgprint(keyfilter: create symboliclink failed!n);iodeletedevice(hookpdeviceobject);return status;5. dispatchread在收到irp_mj_read的irp后,為其設(shè)置指定的完成例程readcomplete,然后再將i

14、rp發(fā)送給物理鍵盤設(shè)備。/獲取當(dāng)前irp包堆棧指針currentirpstack = iogetcurrentirpstacklocation(pirp);/傳遞到下一個(gè)單元iocopycurrentirpstacklocationtonext(pirp);/設(shè)置完成例程iosetcompletionroutine(pirp, keyfilter_readcomplete, pdeviceobject, true, true, true);/將irp下發(fā)給鍵盤設(shè)備status = iocalldriver(pdevext-pkbdevice, pirp);6. readcomplete在irp

15、完成時(shí)會(huì)調(diào)用readcomplete例程,此時(shí)用keyboard_input_data結(jié)構(gòu)讀取irp中的返回值,得到按鍵事件的掃描碼并保存。同時(shí)若符合按鍵映射規(guī)則,則改寫irp中的返回值,實(shí)現(xiàn)按鍵的替換。/獲取當(dāng)前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-mak

16、ecode);/根據(jù)flags和makecode字段生成掃描碼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;/實(shí)現(xiàn)按鍵映射if(keycode = pdevext-setcode0)keycode = pdevext-setcode1

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

18、pdevext-setcode數(shù)組中。/得到當(dāng)前堆棧currentirpstack = iogetcurrentirpstacklocation(pirp);/得到控制碼iocontrolcode = currentirpstack-parameters.deviceiocontrol.iocontrolcode;switch (iocontrolcode)case read_scancode:/讀掃描碼if(pdevext-lastscancode)dbgprint(read_scancode 0x%04xn,pdevext-lastscancode);info = pdevext-last

19、scancode;pdevext-lastscancode = 0;break;case set_code:/設(shè)定按鍵映射pbuffer = (ulong *)pirp-associatedirp.systembuffer;pdevext-setcode0 = *pbuffer;pbuffer+;pdevext-setcode1 = *pbuffer;info = 1;break;/完成irpstatus = status_success;pirp-iostatus.status = status;pirp-iostatus.information = info;iocompletereque

20、st(pirp, io_no_increment);return status;(2) 應(yīng)用程序部分使用mfc實(shí)現(xiàn)應(yīng)用界面,在程序啟動(dòng)時(shí)打開過濾驅(qū)動(dòng)設(shè)備。/打開設(shè)備m_hdevice = createfile(.keyfilterdriver,generic_read | generic_write,0,null,open_existing,file_attribute_normal,null);if (m_hdevice = invalid_handle_value)cstring str;str.format(獲得設(shè)備驅(qū)動(dòng)句柄失敗,錯(cuò)誤代碼:%d, getlasterror();messa

21、gebox(str, 錯(cuò)誤);exit(0);開辟新的工作線程,實(shí)現(xiàn)定時(shí)(100ms)讀取捕獲到的鍵盤掃描碼,將掃描碼翻譯成按鍵名稱,并按時(shí)間順序?qū)存I動(dòng)作顯示在listbox中。while(1)deviceiocontrol(m_hdevice, read_scancode, null, 0, null, 0, &info, null);if(info)time=ctime:getcurrenttime(); sprintf(mess,%s code:0x%04x %sn,time.format(%h:%m:%s),info,codename(info);plistbox1-addstrin

22、g(mess);plistbox1-setcursel(plistbox1-getcount()-1);sleep(100);設(shè)定按鍵映射規(guī)則時(shí),通過deviceiocontrol將兩個(gè)dword類型的掃描碼通過系統(tǒng)緩沖io的方式傳遞給驅(qū)動(dòng)程序。getdlgitemtext(idc_edit1,mess,8);sscanf(mess,0x%x,&code0);getdlgitemtext(idc_edit2,mess,8);sscanf(mess,0x%x,&code1);if(code00xe000 | code10xe000)messagebox(請(qǐng)輸入小于0xe000的編碼!);retu

23、rn;deviceiocontrol(m_hdevice, set_code, code, sizeof(code), null, 0, &info, null);3、 所遇到的問題及解決方法鍵盤過濾驅(qū)動(dòng)的卸載問題。在使用常規(guī)的驅(qū)動(dòng)卸載步驟時(shí),會(huì)發(fā)生系統(tǒng)藍(lán)屏重啟的故障。通過分析和查閱相關(guān)資料,終于得出了解決的辦法。由于irm_mj_read是異步的,在給irp_mj_read設(shè)置了完成例程的情況下,該irp完成后會(huì)調(diào)用過濾驅(qū)動(dòng)所指定的完成例程,使得有了處理返回?cái)?shù)據(jù)的機(jī)會(huì)。但也正是因?yàn)檫@樣,當(dāng)動(dòng)態(tài)御載了鍵盤過濾驅(qū)動(dòng),也就卸載掉了完成例程,而之后的再次按鍵動(dòng)作在完成了這個(gè)irp后還是會(huì)調(diào)用那個(gè)已經(jīng)不存在了的完成例程,因而引發(fā)錯(cuò)誤。同理可知,在安裝過濾驅(qū)動(dòng)時(shí),就已經(jīng)有一個(gè)irp在鍵盤設(shè)備驅(qū)動(dòng)中等待按鍵了,而該irp并沒有被設(shè)置完成例程。因此可知,在驅(qū)動(dòng)運(yùn)行之后的第一個(gè)按鍵動(dòng)作是不會(huì)被截獲的。在實(shí)驗(yàn)中的確證實(shí)了這個(gè)推想。動(dòng)態(tài)卸載的實(shí)現(xiàn),是在設(shè)備擴(kuò)展對(duì)象中加入一個(gè)irppendingcount計(jì)數(shù)器,用來記錄正在運(yùn)行中的(pending狀態(tài))irp數(shù)量。當(dāng)收到一個(gè)irm_mj_read時(shí)

溫馨提示

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

評(píng)論

0/150

提交評(píng)論