Windows api實現 虛擬光碟機

2021-09-24 03:22:39 字數 4838 閱讀 6756

我在注釋裡已經大致講了每個引數的作用。這裡只作些必要的補充。

lpfilename 在這裡用的是 \\.\\minicd 這個是裝置的符號名。是在驅動裡使用iocreatesymboliclink 建立的。主要用於使用者層程式訪問驅動用的。注:符號名稱和裝置名是不同的(從iocreatesymboliclink就可以看出來,其實符號名就類似於裝置的乙個鏈結,這個鏈結是給使用者層程式使用的)。當然這裡不明白也不要緊。在這裡只知道怎麼用的就行了。

dwdesiredaccess 訪問許可權可以是 generic_read(唯讀) generic_write(只寫)

或者 generic_read | generic_write 讀寫

dwsharemode 共享模式 主要是用於其它程式也使用這個物件時設定共享的方式。這裡設定的是file_share_read。也就是其它程序仍然可以對這個裝置進行讀。

lpsecurityattributes 標誌預設就可以了。只要用於設定許可權用的。很多api都用到這個。例如要實現關機,你就必須講你當前程序的安全屬性設定成允許關機的許可權才可以實現關機。否則普通的使用者層程序的安全許可權是無法使用exitwindows這個函式的。

dwcreationdisposition 建立方式,設定一些諸如檔案不存在是建立還是返回錯誤等的一些方式而已。當然如果是建立裝置的不存在剛才講的這些問題。設定成open_existing 即可。就是如果驅動沒有安裝就返回失敗。

其它兩個預設即可,是些額外的屬性和標誌設定。對於建立檔案,這裡可以設定諸如唯讀等的額外屬性或者標誌等。和dwdesiredaccess的區別是dwdesiredaccess的許可權是執行時的許可權。而這裡設定的是檔案自身的許可權。當然對裝置來講不需要這兩個屬性。傳0即可

裝置建立成功後,就要和 裝置通訊了。和裝置通訊(就是和驅動通訊)要用到deviceiocontrol (主要用於一些自定義的或者擴充套件的操作,一般性的讀和寫有專門的例程)在minicd.exe 裡這個引數的呼叫是這樣的

wchar outbuffer[501] = l"mf:\\developetool\\sql2000sp4.iso";

dword buffersize = 0x3ea;

deviceiocontrol(

device,

0x22008,

null,

0,outbuffer,

sizeof(outbuffer),

&buffersize,

null)

如果這個執行成功後。光碟機已經被虛擬出來了。

分析minicd.sys得知 在irp_mj_device_control例程裡接收到的指令碼是0x22008時。做的事情其實很簡單。

1.使用iocreatedevice 建立乙個名為 minicd+碟符索引 的裝置 例如 如果是m盤則 建立了個minicd12的裝置 其中12 就是(m-a)的值。裝置型別為 file_device_unknown 型的,一般虛擬裝置都是這種型別

2.使用 iocreatesymboliclink 建立乙個 符號 鏈結 和 這個裝置關聯起來 。 符號鏈結 的名字 為 你要建立的碟符名。

如要建立 m盤,則符號名為 m 。 當使用此函式時,符號名若為 a-z 則系統會自動通知 資源管理器 建立相應的碟符。

當然 這個函式是在驅動層使用的。在使用者層有乙個 和他類似的函式,也可以實現同樣的功能。就是

definedosdevice(

__in          dword dwflags,

__in          lpctstr lpdevicename,

__in          lpctstr lptargetpath

);其中第二個引數 就是 符號名 (如果符號為 a-z 則同樣的系統會自動通知資源管理器建立相應的碟符)

其中第三個引數 是裝置名 

經過上面兩步。就已經建立了 相應的 碟符,而且系統會將對於此碟符的所有操作指令(例如 讀資料,寫資料等等)全部發給 他所關聯的裝置。也就是前面講的諸如minicd12 這樣的裝置。而發給裝置其實就是發給建立裝置的驅動(乙個驅動可建立多個裝置)。所以系統會把對於新建立的碟符的所有操作都發給由minicd.sys所對應的驅動物件。並準確分發到驅動的各個例程。因此,此時只要在minicd.sys的各例程中對所發過來的操作指令進行模擬。並按規定返回相應的資料即可實現虛擬了。例如。當對碟符進行雙擊檢視等操作時,其實,系統會將此操作包裝成乙個irp。並傳送給 minicd.sys裡的 irp_mj_read 例程。這樣你只須在這個例程裡,分析 irp 裡的 指令,並對 iso檔案進行操作,並將得到的結果返回給作業系統就行了      

雖然到這裡,虛擬的工作已經做完了。但要想正常工作還得使用   

broadcastsystemmessage 向系統廣播訊息 

在minicd.exe 的實際呼叫是這樣的 

dev_broadcast_volume minicd;

minicd.dbcv_size = 0x00000012;

minicd.dbcv_devicetype = 0x00000002;

minicd.dbcv_reserved = 0x00000001;

minicd.dbcv_unitmask = 0x00001000;

minicd.dbcv_flags = 0x0002;

pdev_broadcast_volume pminicd = &minicd;

broadcastsystemmessage(

bsf_ignorecurrenttask, 

bsm_allcomponents, 

wm_devicechange, 

0x8000, //dbt_devicearrival

(lparam)pminicd);

這個函式的原型

long broadcastsystemmessage(     

dword dwflags, // 標誌值,用於設定一些廣播方式

lpdword lpdwrecipients, // 指定訊息的接收者

uint uimessage, // 訊息號(訊息型別)

wparam wparam, // 擴充套件訊息的資訊

lparam lparam // 一般根據wparam的不同傳不同

);這個函式其實沒什麼好講的。和經常使用的sendmessage 等訊息處理函式沒什麼區別。在這裡只根據實際的引數作些說明。

在minicd.exe 裡使用這個函時 

dwflags 傳的是 bsf_ignorecurrenttask 就是訊息不發給自己。

lpdwrecipients是 bsm_allcomponents 就是向所有的元件廣播訊息,主要是向 windows資源管理器廣播了。

uimessage是 wm_devicechange 也就是講訊息型別是 裝置改變 訊息。這個訊息是系統的內部訊息。

wparam 是 0x8000 你也可以直接寫dbt_devicearrival.不過要引用一下dbt.h標頭檔案 就是裝置已經到達的意思。

lparam 是乙個 dev_broadcast_volume 型別的指標,dev_broadcast_volume 型別是對 dev_broadcast_hdr的擴充套件。定義如下

typedef struct _dev_broadcast_volume dev_broadcast_volume, 

*pdev_broadcast_volume;

dev_broadcast_hdr 的定義如下

typedef struct _dev_broadcast_hdr dev_broadcast_hdr, 

*pdev_broadcast_hdr;

其中dbch_size 指示這個結構的大小。如果是用在擴充套件結構中,其實就是此結構大小加上擴充套件結構其它部分的大小之和,其實也就是擴充套件結構的大小了。如在這裡 

dev_broadcast_volume minicd;

minicd.dbch_size = 0x00000012; 是 0x12 也就是18個位元組。這明顯是 dev_broadcast_volume 的大小。

dbch_devicetype 是指 裝置型別 。使用的是什麼擴充套件結構裝置型別就是什麼。在這裡使用的是 dev_broadcast_volume 故而是 dbt_devtyp_volume(0x2)

dbch_reserved 保留使用的。這裡 設定 為 0x1

這是 dev_broadcast_hdr 的結構介紹,所有的擴充套件其的結構的第一項必須是 dev_broadcast_hdr 所以我們看 dev_broadcast_volume的定義的前三項和 dev_broadcast_hdr 是一樣的。只是名字不同而已。

下面再介紹一下。dev_broadcast_volume 擴充套件的兩個屬性。看 dev_broadcast_volume的第四項。

dbcv_unitmask 這一項很重要。具體的意思不好解釋。應該類似於網路裡的掩碼。這是乙個整型值。也就是說有32位。從右往左數。每一位都對映乙個碟符。如果右邊第乙個位為0

的話,就是指a盤。依次類推,第二個就是b盤。

還記得這句話不

wchar outbuffer[501] = l"mf:\\developetool\\sql2000sp4.iso";

從前面介紹知道,我們要對映的碟符是m盤。那麼自然應該是在 m減去a 的那個位上是1. 那麼實際上也就是 1 << (m-a) 也就是 2 的 (m-a) 次冪。所以為了測試,當時並沒有使用公式計算。只是硬寫了乙個 minicd.dbcv_unitmask = 0x00001000 進去。 很明顯 0x1000 就是 2 的 (m-a)=12 次冪。 

最後一項 dbcv_flags 可以有兩個選擇

dbtf_media

0x0001

dbtf_net

0x0002

這裡選擇 dbtf_net 直接 寫 0x0002 如果要寫dbtf_net 需要引用 dbt.h

Windows API實現視窗居中

如下 居中視窗 int scrwidth,scrheight rect rect scrwidth getsystemmetrics sm cxscreen scrheight getsystemmetrics sm cyscreen getwindowrect hwnd,rect setwindo...

QT 呼叫Windows API實現關機

以前自己不知道怎麼定時關機,於是用qt寫了個程式來實現。關鍵有兩條 1.得到定時開始到現在的時間差 2.如何實現關閉計算機的功能 實現計算機關閉可以使用windows api解決。這裡需要qt creator安裝目錄下的mingw include的windows.h,倘若是用的vc編譯器,使用vc裡...

Windows API實現檔案的查詢

在實際應用,經常要用到檔案的查詢,在前面,我們給大家介紹了如何用cfilefind類實現檔案的遍歷以及如何用列表控制項顯示。這裡,我們主要介紹一下如何使用windows api來實現檔案的查詢。1 findfirstfile 它有兩個引數,第乙個是要查詢的檔名,第二個是儲存查詢到的資訊,型別為win...