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

下載本文檔

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

文檔簡(jiǎn)介

1、驅(qū)動(dòng)程序設(shè)計(jì) 課程大作業(yè)驅(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

2、)態(tài),因?yàn)楫?dāng)時(shí)并沒有按鍵操作。直到一個(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)

3、用指定的完成例程,這時(shí)就可以在完成例程中讀出鍵盤動(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

4、=0或1時(shí),說明按下的按鍵是掃描碼為一個(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)讀取一次并

5、將其清空,再根據(jù)掃描碼查表得到相應(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ì)象typ

6、edef struct _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->setc

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

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

9、filter_onclose;3. dispatchgeneral對(duì)于不關(guān)心的那些消息,返回成功值并傳遞給下一層的鍵盤設(shè)備,本層不作處理。/將消息傳遞到下一個(gè)單元iocopycurrentirpstacklocationtonext(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(&

10、;devname, l"devicekeyfilterdriver");/要掛接的設(shè)備rtlinitunicodestring(&hookdevname, l"devicekeyboardclass0");/符號(hào)鏈接rtlinitunicodestring(&symlinkname,l"?keyfilterdriver");/建立鍵盤類設(shè)備status = iocreatedevice(pdriverobject,/驅(qū)動(dòng)程序?qū)ο髎izeof(device_extension),/要求的設(shè)備擴(kuò)展的大小&devna

11、me,/設(shè)備名稱file_device_keyboard,/設(shè)備的類型0,/指示可刪除介質(zhì)、只讀等。false,/非獨(dú)占訪問方式&hookpdeviceobject);/返回的設(shè)備對(duì)象if(!nt_success(status)/創(chuàng)建設(shè)備失敗,輸出調(diào)試信息dbgprint("keyfilter: keyboard hook failed to create device!n");return status;/對(duì)設(shè)備進(jìn)行必要的初始化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;/掛接過濾設(shè)備到devicekeyboar

13、dclass0設(shè)備的上層status = ioattachdevice(hookpdeviceobject, &hookdevname, &kbddevice);if(!nt_success(status)/連接失敗,輸出調(diào)試信息dbgprint("keyfilter: connect with keyboard failed!n");/刪除設(shè)備iodeletedevice(hookpdeviceobject);return status;pdevext->pkbdevice = kbddevice;/創(chuàng)建符號(hào)鏈接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后,為其設(shè)置指定的完成例程readcomplete,然后再將irp發(fā)送給物理鍵盤設(shè)備。/獲取當(dāng)前irp包堆棧指針currentirpstack = iogetcurrentirpstac

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

16、按鍵事件的掃描碼并保存。同時(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->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;/實(shí)現(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實(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ū)傳

19、遞兩個(gè)ulong型的掃描碼到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",pde

20、vext->lastscancode);info = pdevext->lastscancode;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->iostatu

21、s.status = status;pirp->iostatus.information = info;iocompleterequest(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 = in

22、valid_handle_value)cstring str;str.format("獲得設(shè)備驅(qū)動(dòng)句柄失敗,錯(cuò)誤代碼:%d", getlasterror();messagebox(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:

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);設(shè)定按鍵映射規(guī)則時(shí),通過deviceiocontrol將兩個(gè)dword類型的掃描碼通過系統(tǒng)緩沖io的方式傳遞給驅(qū)動(dòng)程序。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("請(qǐng)輸入小于0xe000的編碼!");return;deviceiocontrol(m_hdevice, set_code, code, sizeof(code), null, 0, &info, null);3、 所遇到的問題及解決方法鍵盤

25、過濾驅(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)行中的

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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)論