USB端口的控制 ( 积分: 50 )

  • 主题发起人 主题发起人 moonshiny
  • 开始时间 开始时间
M

moonshiny

Unregistered / Unconfirmed
GUEST, unregistred user!
我想在程序中控制USB端口或者是USB存储设备的启用与禁用,请高手赐教!
 
我想在程序中控制USB端口或者是USB存储设备的启用与禁用,请高手赐教!
 
一点旧资料,你参看一下吧

抓取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檔案
dwData:Pointer;
Result:LongInt;
end;

所以,我們可以將這個資料格式加入到前一篇文章提到的Test程式中!!
說了這麼多,現在回到主題: &quot;如何確認USB裝置已經完成安裝或移除呢??&quot;

這就要依賴TWMDeviceChange.Event這個變數了!!
在MS的相關資料可以得知

當 TWMDeviceChange.Event 為(十六進位值 = $8000)時,表示硬體裝置完成安裝!!
當 TWMDeviceChange.Event 為(十六進位值 = $8004)時,表示硬體裝置已經移除!!

所以,我們可以再將這兩個Event以及TWMDeviceChange的定義整理成以下的程式碼

type

TWMDeviceChange = record
Msg:Cardinal;
Event :UINT; //UINT = LongWord; ==>參考Windows.pas檔案
dwData:Pointer;
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檔案
dwData:Pointer;
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,說了這麼多;休息一下吧!!....
 
后退
顶部