在開發驅動程式有些注意事項說明如下...
資料型態 :
用 C 語言或者 C++ 語言開發時, 字元變數, Short 整數, Long 整數都有自己的標準資料類型. DDK 對這些資列結構進行了封裝. 在驅動程式中, 既可以使用 C 語言的類型定義, 也可以使用 DDK 提供的類型定義, 下表列出了 C 語言的資料類型和 DDK 中對應的資料類型 :
在 C 語言中, 整數類型有 8 位元, 16 位, 32位 三種類型, 而在 DDK 中又新添了一種 64 位元的長整數. 這種 64 位元整數只有無符號形式, 表示範圍從 0 ~ 2^63, 用 LONGLONG 類型表示. 64 位元整數不是標準 C 語言定義的, 只有微軟的編譯器才識別這種類型. 64 位元整數的常量前面是一個數字, 後面加上 i64 結尾, 如 :
LONGLONG llValue = 100i64;
這種 64 位元整數支援加減乘除等運算. 除了 LONGLONG 之外, DDK 還提供一種 64 位元整數的表示方法, 即 LARGE_INTEGER 資料結構. 其區別是 LONGLONG 是基本的資料, 而 LARGE_INTEGER 是資料結構, 其定義如下 :
LARGE_INTEGER 是個聯合體, 這種設計非常巧妙. 聯合體中的三個元素可以認定是 LARGE_INTEGER 的三個定義. 其中 :
(1) LARGE_INTEGER 可以認定是由兩個部分組成. 一個是低 32 位元的整數 LowPart , 一個是高 32 位元整數 HightPart. 在 little endian 的情況下, 低 32 位元數字在前, 高 32 位元數字在後. 如果將這個 64 位數指定為 100, 可以這樣寫 :
- LARGE_INTEGER LargeValue;
- LargeValue.LowPart = 100;
- LargeValue.HighPart = 0;
- LARGE_INTEGER LargeValue;
- LargeValue.QuadPart = 100i64;
DDK 大部分函式的返回數值型別是 NTSTATUS 類型, 查看 DDK.h 檔, 可以看到 :
NTSTATUS 的定義和 LONG 等價. 為了函式的形式統一, 所有函式返回值都是 NTSTATUS 類型. NTSTATUS 就是一個 32 位元整數, 其每位元都有著不同的含意 :
在執行完內核函式後, 應該查看函式返回狀態, 如果狀態碼高位為 0, 無論其他位置是否設置, 該狀態碼代表成功. 絕對不能用狀態碼與 0 比較來判斷操作是否成功, 而應該使用NT_SUCCESS 巨集. 用法如下 :
- status = Foo(...);
- if(NT_SUCCESS(status))
- {
- // 該函式執行成功
- }
在驅動程式中, 對記憶體的操作要格外小心. 如果某段記憶體是唯讀, 而驅動程式試圖去操作會導致系統的崩潰. 同樣當某段記憶體是不可讀的情況下, 而驅動程式試圖去讀, 也會造成系統的崩潰.
DDK 提供了兩個函式, 說明程式設計師在不知道某段記憶體是否可讀寫的情況下, 試探這段記憶體可讀性. 這兩個函式分別是 ProbeForRead 和 ProbeForWrite.
參數說明 :
參數說明 :
這兩個函式不是返回該段記憶體是否可讀寫, 而是當不可讀寫的時候引發一個異常 (Exception). 這個異常需要用到微軟編譯器提供的 "結構化異常" 處理辦法.
結構化異常處理 (try-except 區塊) :
結構化異常 是微軟編譯器提供的獨特處理機制, 這種處理方式在一定程度上在出現錯誤的情況下, 免於程式崩潰. 為了說明結構化異常, 有兩個概念要說明.
這種向更外一層尋找異常處理的機制, 被稱為回捲. 一般異常處理是透過 try-except 區塊來處理 :
- __try
- {
- }
- __except(filter_value)
- {
- }
ProbeForRead 和 ProbeForWrite 函式可以和 try-except 區塊配合, 用來檢查某段記憶體是否可讀寫. 下面列出一段範例, 這段程式探測空指標的位址是否可以寫. 這會引發一個異常, 程式碼用 try-except 處理異常 :
除了讀寫記憶體外, try-except 區塊還可以處理一些異常. DDK 提供了一些函式觸發異常, 可以根據需求使用這些函式 :
結構化異常處理 (try-finally 區塊) :
結構化異常還有另一種使用方法, 就是利用 try-finally 區塊, 強迫函式在退出前執行一段程式碼 :
上段程式碼的 __try{} 區塊中, 無論執行什麼程式碼, 在程式退出該函式前都會執行 __finally{} 區塊中的程式碼. 這樣的目的是在退出前需要執行一些資源回收的工作, 而資源回收程式碼的最佳位置就是放在這個區塊中.
使用巨集注意的地方 :
DDK 提供了大量的巨集, 在使用這些巨集時候, 要注意一種錯誤發生, 這就是 "側效" (Side Effect). 巨集一般由多行組成, 如下面的形式, 其中 "\" 代表換行 :
- #define PRINT(msg) KdPrint(("===================\n"));\
- KdPrint(msg);\
- KdPrint(("===================\n"));
- if(bRet)
- {
- Foo();
- }
- if(bRet) Foo();
- if(bRet) PRINT(msg);
- if(bRet) KdPrint(("===================\n"));
- KdPrint(msg);
- KdPrint(("===================\n"));
斷言 :
在驅動程式開發中, 還有一個技巧, 就是使用 "斷言(ASSERT)". 在驅動程式使用 "斷言" 一般是透過使用 ASSERT 巨集, 例如 :
- NTSTATUS Foo(PCHAR* str)
- {
- ASSERT(str!=NULL); // 斷言
- // 對 str 操作
- }
沒有留言:
張貼留言