夢織未來Windows驅動編程 第03課 驅動的編程規範

来源:http://www.cnblogs.com/linuxxiaoyu/archive/2016/07/14/5668153.html
-Advertisement-
Play Games

最近根據夢織未來論壇的驅動教程學習了一下Windows下的驅動編程,做個筆記備忘。這是第03課《驅動的編程規範》。驅動部分包括基本的驅動卸載函數、驅動打開關閉讀取寫入操作最簡單的分發常式。代碼如下: 1 //CreateDevice.c 2 //2016.07.14 3 4 #include "nt ...


最近根據夢織未來論壇的驅動教程學習了一下Windows下的驅動編程,做個筆記備忘。這是第03課《驅動的編程規範》。

驅動部分包括基本的驅動卸載函數、驅動打開關閉讀取寫入操作最簡單的分發常式。代碼如下:

  1 //CreateDevice.c
  2 //2016.07.14
  3 
  4 #include "ntddk.h"
  5 
  6 //驅動卸載函數Self
  7 VOID MyDriverUnload(PDRIVER_OBJECT pDriverObject)
  8 { 
  9     UNICODE_STRING usSymName;
 10     RtlInitUnicodeString(&usSymName, L"\\??\\FirstDevice");
 11     
 12     //先刪除符號鏈接,後刪除設備對象
 13     if (pDriverObject->DeviceObject != NULL)
 14     {
 15         IoDeleteSymbolicLink(&usSymName);                //刪除符號鏈接
 16         IoDeleteDevice(pDriverObject->DeviceObject);    //刪除設備對象
 17         KdPrint(("Delete Device Sucess."));
 18     }
 19 }
 20 
 21 //創建設備函數Self
 22 NTSTATUS CreateDevice(PDRIVER_OBJECT pDriverObject)
 23 {
 24     NTSTATUS Status;
 25     UNICODE_STRING usDevName;
 26     UNICODE_STRING usSymName;
 27     PDEVICE_OBJECT pDevObj;        //設備對象,用於指向創建的設備
 28     
 29     //DDK API    為UNICODE_STRING賦值的函數
 30     RtlInitUnicodeString(&usDevName, L"\\Device\\FirstDevice");
 31     
 32     //創建設備函數API    創建設備"\\Device\\FirstDevice"
 33     //設備創建後,會返回給pDevObj,同時給pDriverObject->DeviceObject賦值
 34     //The IoCreateDevice routine creates a device object for use by a driver.
 35     /*
 36         NTSTATUS IoCreateDevice(
 37         _In_     PDRIVER_OBJECT  DriverObject,
 38         _In_     ULONG           DeviceExtensionSize,
 39         _In_opt_ PUNICODE_STRING DeviceName,
 40         _In_     DEVICE_TYPE     DeviceType,
 41         _In_     ULONG           DeviceCharacteristics,
 42         _In_     BOOLEAN         Exclusive,
 43         _Out_    PDEVICE_OBJECT  *DeviceObject
 44         );
 45     */
 46     Status = IoCreateDevice(pDriverObject,         
 47                             0, 
 48                             &usDevName, 
 49                             FILE_DEVICE_UNKNOWN, 
 50                             FILE_DEVICE_SECURE_OPEN, 
 51                             TRUE, 
 52                             &pDevObj);
 53     if (!NT_SUCCESS(Status))    //檢查返回值
 54     {
 55         return Status;
 56     }
 57     
 58     //DO_BUFFERED_IO or DO_DIRECT_IO 
 59     //Specifies the type of buffering that is used by the I/O manager for I/O requests that are sent to the device stack. 
 60     //Higher-level drivers OR this member with the same value as the next-lower driver in the stack, except possibly for highest-level drivers.
 61     pDevObj->Flags |= DO_BUFFERED_IO;
 62     
 63     RtlInitUnicodeString(&usSymName, L"\\??\\FirstDevice");
 64     
 65     //The IoCreateSymbolicLink routine sets up a symbolic link between a device object name and a user-visible name for the device.
 66     /*
 67         NTSTATUS IoCreateSymbolicLink(
 68         _In_ PUNICODE_STRING SymbolicLinkName,
 69         _In_ PUNICODE_STRING DeviceName
 70         );
 71     */
 72     Status = IoCreateSymbolicLink(&usSymName, &usDevName);    //DDK API    創建符號鏈接
 73     if (!NT_SUCCESS(Status))
 74     {
 75         IoDeleteDevice(pDevObj);    //刪除設備對象
 76         return Status;
 77     }
 78     
 79     return STATUS_SUCCESS; 
 80 }
 81 
 82 //打開設備的函數
 83 NTSTATUS CreateCompleteRoutine(PDRIVER_OBJECT pDriverObject, PIRP pIrp)
 84 {
 85     NTSTATUS Status;
 86     
 87     Status = STATUS_SUCCESS;
 88     
 89     KdPrint(("Create"));
 90     
 91     //A driver sets an IRP's I/O status block to indicate the final status of an I/O request, before calling IoCompleteRequest for the IRP.
 92     
 93     //This is the completion status, either STATUS_SUCCESS if the requested operation was completed successfully or an informational, warning, or error STATUS_ XXX value.
 94     //For more information, see Using NTSTATUS values.
 95     pIrp->IoStatus.Status = Status;
 96     //This is the completion status, either STATUS_SUCCESS if the requested operation was completed successfully or an informational, warning, or error STATUS_ XXX value. 
 97     //For more information, see Using NTSTATUS values.
 98     pIrp->IoStatus.Information = 0;
 99     
100     //The IoCompleteRequest routine indicates that the caller has completed all processing for a given I/O request and is returning the given IRP to the I/O manager.
101     //IO_NO_INCREMENT 不再往下層傳遞
102     IoCompleteRequest(pIrp, IO_NO_INCREMENT);
103     return Status;
104 }
105 
106 //關閉設備的函數
107 NTSTATUS CloseCompleteRoutine(PDRIVER_OBJECT pDriverObject, PIRP pIrp)
108 {
109     NTSTATUS Status;
110 
111     Status = STATUS_SUCCESS;
112 
113     KdPrint(("Close"));
114 
115     pIrp->IoStatus.Status = Status;
116     pIrp->IoStatus.Information = 0;
117 
118     IoCompleteRequest(pIrp, IO_NO_INCREMENT);
119     return Status;
120 }
121 
122 //讀取設備的函數
123 NTSTATUS ReadCompleteRoutine(PDRIVER_OBJECT pDriverObject, PIRP pIrp)
124 {
125     NTSTATUS Status;
126 
127     Status = STATUS_SUCCESS;
128 
129     KdPrint(("Read"));
130 
131     pIrp->IoStatus.Status = Status;
132     pIrp->IoStatus.Information = 0;
133 
134     IoCompleteRequest(pIrp, IO_NO_INCREMENT);
135     return Status;
136 }
137 
138 //寫入設備的函數
139 NTSTATUS WriteCompleteRoutine(PDRIVER_OBJECT pDriverObject, PIRP pIrp)
140 {
141     NTSTATUS Status;
142 
143     Status = STATUS_SUCCESS;
144 
145     KdPrint(("Write"));
146 
147     pIrp->IoStatus.Status = Status;
148     pIrp->IoStatus.Information = 0;
149 
150     IoCompleteRequest(pIrp, IO_NO_INCREMENT);
151     return Status;
152 }
153 
154 //驅動程式入口函數
155 NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath)
156 {
157     //輸出信息
158     //DbgPrint("1111");
159 
160     
161     NTSTATUS Status;
162     Status = CreateDevice(pDriverObject);    //創建設備對象和符號鏈接
163     if (!NT_SUCCESS(Status))
164     {
165         KdPrint(("Create Device Failed."));
166     } else {
167         KdPrint(("Create Device Sucess."));
168         KdPrint(("%wZ", pRegistryPath));
169     }
170         
171     //打開關閉讀取寫入的分發常式賦值
172     pDriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)CreateCompleteRoutine;    //打開設備
173     pDriverObject->MajorFunction[IRP_MJ_CLOSE]    = (PDRIVER_DISPATCH)CloseCompleteRoutine;    //關閉設備
174     pDriverObject->MajorFunction[IRP_MJ_READ]    = (PDRIVER_DISPATCH)ReadCompleteRoutine;    //讀取設備
175     pDriverObject->MajorFunction[IRP_MJ_WRITE]    = (PDRIVER_DISPATCH)WriteCompleteRoutine;    //寫入設備
176     
177     //驅動卸載函數賦值
178     pDriverObject->DriverUnload = MyDriverUnload;
179 
180     return STATUS_SUCCESS;
181 }
CreateDevice.c

 

應用層採用了MFC創建了一個視窗,視窗有三個按鈕:Create、Read、Write。界面如下:

 

其中Create按鈕的處理函數如下:

 1 void CCheckMyDriverDlg::OnCreateButton()
 2 {
 3     // TODO: 在此添加控制項通知處理程式代碼
 4     HANDLE hFile = CreateFileW(L"\\\\.\\FirstDevice", 
 5                 FILE_ALL_ACCESS, 
 6                 0, 
 7                 NULL,
 8                 OPEN_EXISTING,
 9                 FILE_ATTRIBUTE_NORMAL,
10                 NULL);
11     if (hFile == INVALID_HANDLE_VALUE)
12     {
13         AfxMessageBox (L"Open Device Failed.");
14         return;
15     }
16 
17     CloseHandle (hFile);
18 }

 

Read按鈕的處理函數如下:

 1 void CCheckMyDriverDlg::OnReadButton()
 2 {
 3     // TODO: 在此添加控制項通知處理程式代碼
 4     HANDLE hFile = CreateFileW(L"\\\\.\\FirstDevice", 
 5         FILE_ALL_ACCESS, 
 6         0, 
 7         NULL,
 8         OPEN_EXISTING,
 9         FILE_ATTRIBUTE_NORMAL,
10         NULL);
11     if (hFile == INVALID_HANDLE_VALUE)
12     {
13         AfxMessageBox (L"Open Device Failed.");
14         return;
15     }
16 
17     wchar_t Buffer[MAX_PATH] = {0};
18     DWORD len = 0;
19     if (!ReadFile (hFile, Buffer, MAX_PATH-1, &len, NULL))
20     {
21         AfxMessageBox (L"Read Device Failed.");
22         return;
23     }
24 
25     CloseHandle (hFile);
26 
27 }

 

Write按鈕的處理函數如下:

 1 void CCheckMyDriverDlg::OnWriteButton()
 2 {
 3     // TODO: 在此添加控制項通知處理程式代碼
 4     HANDLE hFile = CreateFileW(L"\\\\.\\FirstDevice", 
 5         FILE_ALL_ACCESS, 
 6         0, 
 7         NULL,
 8         OPEN_EXISTING,
 9         FILE_ATTRIBUTE_NORMAL,
10         NULL);
11     if (hFile == INVALID_HANDLE_VALUE)
12     {
13         AfxMessageBox (L"Open Device Failed.");
14         return;
15     }
16 
17     wchar_t Buffer[MAX_PATH] = L"What The Fuck, Man ?";
18     DWORD len;
19     if (!WriteFile (hFile, Buffer, MAX_PATH, &len, NULL))
20     {
21         AfxMessageBox (L"Write Device Failed.");
22         return;
23     }
24 
25     CloseHandle (hFile);
26 
27 }

 

 

 以下為操作部分:

將生成的FirstDevice.sys文件複製到XP虛擬機下,使用驅動載入工具InstDrv安裝並啟動驅動後,在Dbgview工具內有如下輸出信息:

並能夠找到相應註冊表,使用WinObj工具查看設備對象\\Device\\FirstDevice:

然後查看符號鏈接\\??\\FirstDevice:

 

使用InstDrv停止此驅動時輸出:

 

 期間並未出現藍屏問題

 

安裝驅動程式後,使用上面寫的MFC程式CheckMyDriver.exe,點擊Create按鈕後,輸出

 

點擊Read按鈕後,輸出:

 

點擊Write按鈕後,輸出:

 

 

 以上操作均為出現藍屏。本課結束。

 

由於本人剛開始學習驅動程式,實力有限,可能對於某些地方的理解並不正確,希望大家能提出意見建議,共同學習,共同進步。

最後謝謝大家的支持。

2016-07-14 14:58:13


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在前一篇博文數據壓縮簡要的基礎上,我希望把數據壓縮評估自動化。於是有了這篇博文。 白皮書推薦對符合如下條件的大型表和索引使用頁壓縮: 表或索引的掃描操作占到所有操作的75%及以上時 表或索引的更新操作占到所有操作的20%及以下時 註意,這是白皮書中的結論和建議,只做參考,最為最佳實踐的考慮點之一。 ...
  • 如果需要進行SQl Server下的SQL性能優化,需要準備以下內容: 一、SQL查詢分析器設置: 1、開啟實際執行計劃跟蹤。 2、每次執行需優化SQL前,帶上清除緩存的設置SQL。 平常在進行SQL Server性能優化時,為了確保真實還原性能問題,我們需要關閉SQL Server自身的執行計劃及 ...
  • 今天剛好需要刪除redis里的db2里的數據,我找了一下,發現這篇內容幫助我解決了問題,記錄一下。 Redis 中有刪除單個 Key 的指令 DEL,但好像沒有批量刪除 Key 的指令,不過我們可以藉助 Linux 的 xargs 指令來完成這個動作。 代碼如下: redis-cli keys “* ...
  • SQL 不同於與其他編程語言的最明顯特征是處理代碼的順序。在大數編程語言中,代碼按編碼順序被處理,但是在SQL語言中,第一個被處理的子句是FROM子句,儘管SELECT語句第一個出現,但是幾乎總是最後被處理。 每個步驟都會產生一個虛擬表,該虛擬表被用作下一個步驟的輸入。這些虛擬表對調用者(客戶端應用 ...
  • 其中tablename為表的名稱,num為要設置的新的自動遞增值,此時再Insert一條數據,自動遞增值即為num,不過num必須要大於等於現在已有的自動遞增值,否則SQL語句會執行成功,但是實際上不起作用。 ...
  • 1. 決定壓縮哪些對象 通過sp_estimate_data_compression_savings 評估在ROW和PAGE壓縮時分別節省的空間量。 表包含如下數據模式時,會有較好的壓縮效果: 數字類型的列和固定長度的字元類型數據,但兩者的大多數值都不會用到此類型的所有位元組。如INT列的值大多數少於 ...
  • 在Linux中無論是管理系統還是在Linux環境下編程,內嵌的手冊man都是一個很好用的工具,“Linux下不懂得就找man”(man是manual的意思)。本文將介紹我所知道的所有關於man的知識(這麼說也是為了後續如果有所補充的話,能夠更加完備)。 一、man手冊的組成 man涉及的內容廣泛,另 ...
  • 最近剛接觸Linux,整理了一些常用的命令和快捷鍵 Tab補全命令 當命令記不清了,輸入記得的前幾個用Tab就可以將該命令自動補全。 啟動tomcat服務用$startup.sh 停止tomcat服務通$shtdown.sh,請註意,$符一般已有的,只需要$後面的命令行就可以啦。 查看埠使用狀態n ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...