一点旧资料,你参看一下吧
抓取USB大量儲存裝置的方法Part 1( for Win2000)
http://delphi.ktop.com.tw/topic.asp?topic_Id=39813
http://delphi.ktop.com.tw/topic.asp?topic_Id=39830
http://delphi.ktop.com.tw/topic.asp?topic_Id=39850
http://delphi.ktop.com.tw/topic.asp?topic_Id=40017
1.當裝上USB大量儲存裝置時,以下的機碼值會有以下的變化
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/USBSTOR
會多出這一個Key "Enum"變成
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/USBSTOR/Enum
在以上這個機碼,你只能使用OpenKeyReadOnly()來進行資料讀取
另外,在Enum這個Key底下有幾個值可以參考
A: Count -->目前機器上有幾個USB大量儲存裝置
B: 數字值,例如
0 USB/Vid_090x&Pid_1142/7&1b1f5133&0&2
0:表示該USB大量儲存裝置安裝的順序
USB/Vid_090x&Pid_1142/7&1b1f5133&0&2 :為該裝置的
DeviceID
現在,讓我們來觀察DeviceID ==> USB/Vid_090x&Pid_1142/7&1b1f5133&0&2
其中,
Vid_090x&Pid_1142 :Vid090x 為製造廠商編號
Pid_1142 為該裝置的產品編號
7&1b1f5133&0&2 :為您的機器上面,USB插座的編號
所以,我們對這一串資料(USB/Vid_090x&Pid_1142/7&1b1f5133&0&2)
綜合前面說明的部分作以下的解釋:
目前,您的機器上有Enum/Count個USB大量儲存裝置提供服務(Services)
;該裝置的資訊為
0(第一個USB大量儲存裝置),
製造廠商編號 Vid_090x
產品編號 Pid_1142
目前的位置在編號(7&1b1f5133&0&2)插座上
附上實作函式給大家參考
//取得USB大量儲存裝置的函式
//DeviceID (ProductKey)
//USB插座編號 (SlotID)
//儲存裝置編號 (EnumNo)
procedure Get_Current_USBSTOR_Info(var ProductKey,SlotID:string;var
EnumNo:integer);
var ct,Vid_Pos,i:integer;
reg:TRegistry;
HardWareKeyStr:string;
FindSlotID:boolean;
begin
HardWareKeyStr := '';
ProductKey := '';
SlotID := '';
FindSlotID := FALSE;
reg := TRegistry.Create;
reg.RootKey := HKEY_LOCAL_MACHINE;
if(reg.OpenKeyReadOnly('SYSTEM/CurrentControlSet/Services/USBSTOR/Enum') =
TRUE)then
begin
ct := 0;
ct := reg.ReadInteger('Count');
if(ct > 0)then
begin
EnumNo := ct-1;
HardWareKeyStr := reg.ReadString(IntToStr(ct-1));
end;//if...end!!
Vid_Pos := Pos('Vid_',HardWareKeyStr);
if(Vid_Pos > 0)then
for i := Vid_Pos to Length(HardWareKeyStr) do
begin
if(HardWareKeyStr
= '/')then
begin
FindSlotID := TRUE;
Continue;
end//if...end!!
else
if(FindSlotID = TRUE)then SlotID := SlotID+HardWareKeyStr
else ProductKey := ProductKey+HardWareKeyStr;
end;//for...i...end!!
end;//if...end!!
reg.CloseKey;
reg.Free;
end;
抓取USB大量儲存裝置的方法Part 2( for Win2000)
針對Part 1 的實作函式
//取得USB大量儲存裝置的函式
//DeviceID (ProductKey)
//USB插座編號 (SlotID)
//儲存裝置編號 (EnumNo)
procedure Get_Current_USBSTOR_Info(var ProductKey,SlotID:string;var
EnumNo:integer);
var ct,Vid_Pos,i:integer;
reg:TRegistry;
HardWareKeyStr:string;
FindSlotID:boolean;
begin
HardWareKeyStr := '';
ProductKey := '';
SlotID := '';
FindSlotID := FALSE;
reg := TRegistry.Create;
reg.RootKey := HKEY_LOCAL_MACHINE;
if(reg.OpenKeyReadOnly('SYSTEM/CurrentControlSet/Services/USBSTOR/Enum') =
TRUE)then
begin
ct := 0;
ct := reg.ReadInteger('Count');
if(ct > 0)then
begin
EnumNo := ct-1;
HardWareKeyStr := reg.ReadString(IntToStr(ct-1));
end;//if...end!!
Vid_Pos := Pos('Vid_',HardWareKeyStr);
if(Vid_Pos > 0)then
for i := Vid_Pos to Length(HardWareKeyStr) do
begin
if(HardWareKeyStr = '/')then
begin
FindSlotID := TRUE;
Continue;
end//if...end!!
else
if(FindSlotID = TRUE)then SlotID := SlotID+HardWareKeyStr
else ProductKey := ProductKey+HardWareKeyStr;
end;//for...i...end!!
end;//if...end!!
reg.CloseKey;
reg.Free;
end;
現在,讓我們來看一看;自己的電腦上有使用過哪幾種USB大量儲存裝置
(包含了随身碟,及使用USB外接盒的硬碟)
各位是否發現,在HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Enum機碼中
儲存了曾經在這台機器上使用過的USB大量儲存裝置的資料
現在,讓我們再更詳細地來看其中包含了哪些訊息(參考下圖)
上圖中,紅色方框的部分為該裝置曾經使用過的USB插座
例如:
裝置 Disk&VenEZ_Disk&Prod_MassStorage_Disk&Rev
就曾經使用過兩個USB插座(6&4e63deb&0)和(7&1274702d&0)
所以,配合Part1中說明的部分,我們就可以取得現有USB大量儲存裝置的相關資料了!!
抓取USB大量儲存裝置的方法Part 3-1 CallBack 程式寫法
以下為一個CallBack程式的撰寫方法,先暖暖身;準備進行'激烈'的Part 3
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
//定義CallBack物件與VCL物件在CallBack狀況發生時,
//Callback物件要呼叫VCL物件做處理的procedure 連結函式樣板!!
TCallBackOBJLinkVCLProc = procedure(var Msg:TMessage) of Object;
//定義CallBack物件
TWinCallBackOBJ = Object
//-----------------------------------------------------------------------
FWinProcCallBackHandle:HWND; //給OS 進行CallBack時使用的Event handle
FVCLProc:TCallBackOBJLinkVCLProc; //給VCL物件進行處理的連結(Event Link)
//-----------------------------------------------------------------------
procedure CreateOBJ; //進行初始化的函式
procedure DestroyOBJ; //進行釋放初始化資源的函式
procedure WinProc(var Msg:TMessage);//給OS CallBack時使用的procedure
end;
TForm1 = class(TForm)
ListBox1: TListBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FWinCallBackOBJ:TWinCallBackOBJ;//宣告TForm1擁有一個TWinCallBackOBJ !!
procedure Execute_When_CallBack_Is_Triggered(var Msg:TMessage);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=====================================================================
//TWinCallBackOBJ.
procedure TWinCallBackOBJ.CreateOBJ;
begin
self.FWinProcCallBackHandle := 0;
//向OS要求配置一個Event Handle !!
//也就是說,一有風吹草動;OS 要通知本物件進行相關處理!!
self.FWinProcCallBackHandle := AllocateHWnd(self.WinProc);
end;
procedure TWinCallBackOBJ.DestroyOBJ;
begin
//釋放先前配置的Event Handle !! (PS. 有借有還,記得喔!!)
DeallocateHWnd(self.FWinProcCallBackHandle);
self.FWinProcCallBackHandle := 0;
end;
procedure TWinCallBackOBJ.WinProc(var Msg: TMessage);
begin
//將訊息傳給要攔截訊息的VCL物件!!
if(Assigned(self.FVCLProc))then self.FVCLProc(Msg);
end;
//=====================================================================
//TForm1.
procedure TForm1.Execute_When_CallBack_Is_Triggered(var Msg:TMessage);
begin
with Msg do
if(Msg = WM_ACTIVATEAPP)then
ListBox1.Items.Add('MessageID : $'+IntToHex(Msg,4));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
self.FWinCallBackOBJ.FVCLProc := self.Execute_When_CallBack_Is_Triggered;
self.FWinCallBackOBJ.CreateOBJ;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
self.FWinCallBackOBJ.DestroyOBJ;
end;
end.
抓取USB大量儲存裝置的方法Part 3-2 Windows硬體設備異動偵測
主題 :
CallBack物件元件化與Windows硬體設備異動偵測
現在,我們將3-1的CallBack物件予以元件化
unit UWinCallBackOBJ;
interface
uses
SysUtils, Windows, Classes, Messages;
type
//定義CallBack VCL物件與其它VCL物件在CallBack狀況發生時,
//Callback VCL物件要呼叫其它VCL物件做處理的procedure 連結函式樣板!!
TCallBackOBJLinkVCLProc = procedure(var Msg:TMessage) of Object;
TWinCallBackOBJ = class(TComponent)
private
{ Private declarations }
FWinProcCallBackHandle:HWND; //給OS 進行CallBack時使用的 Event handle
FVCLProc:TCallBackOBJLinkVCLProc; //給VCL物件進行處理的連結(Event Link)
procedure WinProc(var Msg:TMessage);//給OS CallBack時使用的procedure
protected
{ Protected declarations }
public
{ Public declarations }
Constructor Create(AOwner:TComponent); Override;
Destructor Destroy; Override;
published
{ Published declarations }
property OnOsCallBack:TCallBackOBJLinkVCLProc read FVCLProc write
FVCLProc;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Win32', [TWinCallBackOBJ]);
end;
//TWinCallBackOBJ.
Constructor TWinCallBackOBJ.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
self.FWinProcCallBackHandle := 0;
//向OS要求配置一個Event Handle !!
//也就是說,一有風吹草動;OS 要通知本物件進行相關處理!!
self.FWinProcCallBackHandle := AllocateHWnd(self.WinProc);
end;
Destructor TWinCallBackOBJ.Destroy;
begin
//釋放先前配置的Event Handle !! (PS. 有借有還,記得喔!!)
DeallocateHWnd(self.FWinProcCallBackHandle);
self.FWinProcCallBackHandle := 0;
inherited Destroy;
end;
procedure TWinCallBackOBJ.WinProc(var Msg: TMessage);
begin
//將訊息傳給要攔截訊息的VCL物件!!
if(Assigned(self.FVCLProc))then self.FVCLProc(Msg);
end;
end.
OK !! 如此一來,我們就有自訂的CallBack介面元件了!!
接下來我們要討論的是Windows硬體設備異動偵測
讓我們參考下面的這一段程式碼
//將訊息傳給要攔截訊息的VCL物件!!
if(Assigned(self.FVCLProc))then self.FVCLProc(Msg);
在Delphi中,我們可以看到Msg變數的定義
...啊....給它有點辛苦....!!
根據查詢的結果,我們可以得知;當USB設備有異動時;
CallBack元件會得到一個Msg.Mag = WM_DEVICECHANGE 的訊息
現在,我們來做個練習;參考以下的程式碼(記得要安裝剛才的CallBack元件喔!!)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, UWinCallBackOBJ;
type
TForm1 = class(TForm)
WinCallBackOBJ1: TWinCallBackOBJ;
Memo1: TMemo;
procedure WinCallBackOBJ1OsCallBack(var Msg: TMessage);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.WinCallBackOBJ1OsCallBack(var Msg: TMessage);
begin
case Msg.Msg of
WM_DEVICECHANGE:
begin
self.Memo1.Lines.Add('USB 裝置異動!!')
end;
end;//case...end!!
end;
end.
執行這個程式,我們會得到以下的結果
抓取USB大量儲存裝置的方法Part 3-3
如何確認裝置已經完成安裝或移除呢??
接下來我們要如何確認硬體裝置已經完成安裝或移除呢??
首先,讓我們來觀察Delphi的Messages.pas這個檔案
以 WM_ACTIVE 訊息來說,在Delphi進行訊息攔截的程式樣板如下
procedure TForm1.GetActiveMessage(var Msg:TWMActivate);
begin
case Msg.Active of
WA_INACTIVE:
begin
end;
WA_ACTIVE:
begin
end;
WA_CLICKACTIVE:
begin
end;
end;//case...end!!
end;
看到以上的程式碼之後,會產生一個疑問就是 " TWMActivate " 這個資料格式(注意
!!),是從哪裡來的??
讓我們來查看Messages.pas 這一段 Source Code
TWMActivate = packed record
Msg: Cardinal;
Active: Word; { WA_INACTIVE, WA_ACTIVE, WA_CLICKACTIVE }
Minimized: WordBool;
ActiveWindow: HWND;
Result: Longint;
end;
原來在 Delphi中早就針對Windows Message 處理的需求幫我們把大部分的
Message ID <-----> 參數的傳遞方式由C++轉為Delphi的Code
(請參考前一篇文章中說明的 Msg 參數的結構 !!)
所以才會有以下的codeing方式....很方便吧!!
case Msg.Active of
WA_INACTIVE:
begin
end;
WA_ACTIVE:
begin
end;
WA_CLICKACTIVE:
begin
end;
end;//case...end!!
然而,百密仍有一疏;(我個人認為,這可能是OS一直在更新的原因;當然,函式庫會來不
及更新吧??
如果有新的Patch應該會更新吧?? ^O^ )
在Delphi7的SourceCode(Messages.pas)中,卻沒有TWMDeviceChange這個資料格式;
OK,沒關係 , 雙手是萬能的;經過查詢之後,我們可以將WM_DEVICECHANGE訊息
轉到以下的資料格式中...
TWMDeviceChange = record
Msg:Cardinal;
Event :UINT; //UINT = LongWord; ==>參考Windows.pas檔案
dwDataointer;
Result:LongInt;
end;
所以,我們可以將這個資料格式加入到前一篇文章提到的Test程式中!!
說了這麼多,現在回到主題: "如何確認USB裝置已經完成安裝或移除呢??"
這就要依賴TWMDeviceChange.Event這個變數了!!
在MS的相關資料可以得知
當 TWMDeviceChange.Event 為(十六進位值 = $8000)時,表示硬體裝置完成安裝!!
當 TWMDeviceChange.Event 為(十六進位值 = $8004)時,表示硬體裝置已經移除!!
所以,我們可以再將這兩個Event以及TWMDeviceChange的定義整理成以下的程式碼
type
TWMDeviceChange = record
Msg:Cardinal;
Event :UINT; //UINT = LongWord; ==>參考Windows.pas檔案
dwDataointer;
Result:LongInt;
end;
Const
DBT_DEVICEARRIVAL = $8000; //硬體裝置完成安裝
DBT_DEVICEREMOVECOMPLETE = $8004; //硬體裝置已經移除
現在,我們可以將上一篇的Test程式修改成為以下的程式碼(配合之前的WinCallBack
介面元件!!)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, UWinCallBackOBJ;
type
TForm1 = class(TForm)
WinCallBackOBJ1: TWinCallBackOBJ;
Memo1: TMemo;
procedure WinCallBackOBJ1OsCallBack(var Msg: TMessage);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TWMDeviceChange = record
Msg:Cardinal;
Event :UINT; //UINT = LongWord; ==>參考Windows.pas檔案
dwDataointer;
Result:LongInt;
end;
Const
DBT_DEVICEARRIVAL = $8000; //硬體裝置完成安裝
DBT_DEVICEREMOVECOMPLETE = $8004; //硬體裝置已經移除
procedure TForm1.WinCallBackOBJ1OsCallBack(var Msg: TMessage);
begin
case Msg.Msg of
WM_DEVICECHANGE:
begin
self.Memo1.Lines.Add('USB 裝置異動!!');
case TWMDeviceChange(Msg).Event of
DBT_DEVICEARRIVAL:
begin
self.Memo1.Lines.Add('USB 裝置安裝完成!!');
end;
DBT_DEVICEREMOVECOMPLETE:
begin
self.Memo1.Lines.Add('USB 裝置已經移除!!');
end;
end;//case...end!!
end;
end;//case...end!!
end;
end.
OK,說了這麼多;休息一下吧!!....