如何根據驅動程序及其安裝文件來訪問該設備呢(Visual C++ or C++ Builder均可以)

First of all,我要講一下Windows對每檢測到一個新設備的處理過程:
1.首先Windows將各種設備分成不同的設備類,比如說USB Storage存儲類設備,而這些類設備都有一個GUID,它們位於註冊表中HKEY_LOCAL_MACHINE/ControlSet001/Control/Class下,在這個鍵下你看到的以128位長度結點名稱爲結點都是設備類。
2.當檢測到一個新設備時,Windows OS就會到KEY_LOCAL_MACHINE/ControlSet001下去搜索,如果此類設備已經註冊,那麼就此子鍵下增加一個子鍵,這個子鍵的名稱是順序遞增的,如果當前該類設備中最大子鍵名稱爲0005,那麼新設備的就是0006,0000,0001等就是設備的序列號。如果發現這個設備沒有註冊,那麼OS就會以該設備對應的驅動程序安裝文件.inf中的ClassGuid爲名稱來創建一個鍵,並將此被檢測到的設備的序列號爲0,在該鍵下創建一個子鍵,並且命名爲0000來存儲該設備的相關信息,之所以命名爲0000,因爲該設備是該類設備的第一個。
3.有些設備,如我們常用的COM1,COM2,當我們要訪問它時可以用CreateFile("COM1"。。。)就可以打開串口,這裏的COM1,COM2是符號名,有些設備也用到了符號名,比如說有些USB設備虛擬成一個COM口,如COM3,COM4,COM5等,在程序中我們只需要對COM3,COM4,COM5進行訪問,就相當對該設備進行訪問。
在沒有符號名的情況下,我們如何根據設備驅動程序以及設備安裝文件.inf來對設備進行訪問呢?我們可以這樣:
1.首先,我們在這個設備的符號名中找到設備類的ClassGuid,這是一定可以找到的。
2.然後我們到HKEY_LOCAL_MACHINE/ControlSet001/Control/Class下去找這個設備類,在找到後,我們再找它的子鍵,找到該設備對應的序列號,如它到底是0000還是0001,在得到這兩個數據即ClassGuid和設備序列號後,就好辦了。
下面我寫一段代碼,用來訪問我機器上的一USB設備,並在listbox中列出當前機器上此設備類下的所有設備。

extern "C"
{
#include "setupapi.h"
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   //First of all,I will enumurate all the devices under the specified deviceclass
   HKEY m_hKey,m_hSubKey;
   long m_lResult=0;//using for return value
   int m_nKeyIndex=0,m_nValueIndex=0;
   char cKeyName[255],cValue[255];
   unsigned char pbData[255];
   BOOL bOutter=TRUE,bInter=TRUE;
   char *cRoot="SYSTEM//ControlSet001//Control//Class//{4D36E96D-E325-11CE-BFC1-08002BE10318}";
   AnsiString m_sAttached("");
   m_lResult=::RegOpenKeyEx(HKEY_LOCAL_MACHINE,cRoot,0,KEY_ALL_ACCESS,&m_hKey);
   if(m_lResult!=ERROR_SUCCESS) return FALSE;
   //Enum Keys
   while(bOutter){
   m_lResult=::RegEnumKey(m_hKey,m_nKeyIndex,cKeyName,255);
   bInter=TRUE;
   if(m_lResult!=ERROR_SUCCESS) bOutter=FALSE;
   else{
   m_lResult=::RegOpenKeyEx(m_hKey,cKeyName,0,KEY_ALL_ACCESS,&m_hSubKey);
   if(m_lResult!=ERROR_SUCCESS){
   ::RegCloseKey(m_hKey);
   return FALSE;}
   while(bInter){
   unsigned long m_nDataSize=255;
   unsigned long m_nValueNameSize=255;
   unsigned long m_nType;
   m_lResult=::RegEnumValue(m_hSubKey,m_nValueIndex,cValue,&m_nValueNameSize,0,&m_nType,pbData,&m_nDataSize);
   if(m_lResult!=ERROR_SUCCESS)  bInter=FALSE;
    else{
     if(!strcmp(cValue,"AttachedTo")){
      m_sAttached=(AnsiString)(char*)pbData;
     }
     if(!strcmp(cValue,"DriverDesc")){
      m_lstDevice->Items->Add((AnsiString)(char*)pbData+"  "+m_sAttached);
     }
     m_nValueIndex++;
    }
   }
   m_nValueIndex=0;
   m_nKeyIndex++;
   
  }
 }
 ::RegCloseKey(m_hKey);
 ::RegCloseKey(m_hSubKey);
   
  file://Next Step,I will access one of the device.I know its device serialno:0001
  DWORD ReqLength;
  DWORD Flags=DIGCF_PRESENT|DIGCF_DEVICEINTERFACE;
  GUID CardGuid={4D36E96D-E325-11CE-BFC1-08002BE10318};
  HANDLE hCard=0;
  PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceDetailData;
     SP_DEVICE_INTERFACE_DATA        DeviceInterfaceData;
     DeviceInterfaceData.cbSize=sizeof(SP_DEVICE_INTERFACE_DATA);
     hCard=SetupDiGetClassDevs(&CardGuid,NULL,NULL,Flags);
     if(hCard==INVALID_HANDLE_VALUE){
     ::MessageBox(0,"Invalid Parameters!","Error",MB_OK|MB_ICONERROR);
         return;}
     BOOL status=SetupDiEnumDeviceInterfaces(hCard,NULL,&CardGuid,Index,&DeviceInterfaceData,&ReqLength,
 NULL);//Index即設備的序號,這裏的Index爲1.
 if(!status){
  ::MessageBox(0,"Failed to enumurate the specified
 device!","Error",MB_OK+MB_ICONERROR);
         ::CloseHandle(hCard);
         return;}
 SetupDiGetInterfaceDeviceDetail(hCard,&DeviceInterfaceData,NULL,0,&ReqLength,NULL);
 DeviceDetailData=(PSP_INTERFACE_DEVICE_DETAIL_DATA)new char[ReqLength];
 if(DeviceDetailData){
  ::MessageBox("ERROR NOT ENOUGH MEMORY!","Error",MB_OK+MB_ICONERROR);
         ::CloseHandle(hCard);
         return;}
         status=SetupDiGetInterfaceDeviceDetail(hCard,&DeviceInterfaceData,DeviceDetailData,ReqLength,&ReqLength,NULL);
         if(!status){
  ::MessageBox(0,"Failed to get interface detailed data","Error",MB_OK+MB_ICONERROR);
         delete DeviceDetailData;
         DeviceDetailData=NULL;
         return;}
        ShowMessage(DeviceDetailData->DevicePath());//在這裏得到DevicePath就像得到符號名一樣,那麼接着下來,你你就可以象對串口操作一樣來寫程序,即是說:
        HANDLE hUSB=::CreateFile(DeviceDetailData.DevicePath(),..............);
        file://ReadFile,WriteFile and so on.....
}

所有以file:爲前綴的地方都是註釋部分,特此聲明,以免誤解,這是CSDN文檔編輯器自動加的。
因最近一直在忙於學習驅動開發,現正在用DriverStudio進行開發一個USB Modem的驅動程序,有一點學習心得,特此交流一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章