天天看點

Window XP驅動開發(八) WDK源碼中 usbView 例子的編譯及說明

轉載請标明是引用于 http://blog.csdn.net/chenyujing1234 

歡迎大家提出意見,一起讨論!

示例代碼: http://download.csdn.net/detail/chenyujing1234/4352191

Window XP驅動開發(八) WDK源碼中 usbView 例子的編譯及說明

1、編譯過程

步驟一、加入.h .c .rc檔案

将D:\WINDDK\7600.16385.1\src\usb\usbview下的檔案加入到VS2005中建立的工程中。

(方法參考 http://blog.csdn.net/chenyujing1234/article/details/7565364)

Window XP驅動開發(八) WDK源碼中 usbView 例子的編譯及說明
步驟二、加.h .cpp .rc的連接配接目錄與lib

.h

D:\WINDDK\7600.16385.1\inc\api;D:\WINDDK\7600.16385.1\Debuggers\winext\manifest

-----------------------------------------------------------------------------------------------------------------------------

 .lib

D:\WINDDK\7600.16385.1\lib\wxp\i386

kernel32.lib user32.lib gdi32.lib comctl32.lib cfgmgr32.lib  setupapi.lib

-----------------------------------------------------------------------------------------------------------------------------------------

.rc

D:\WINDDK\7600.16385.1\Debuggers\winext\manifest;D:\WINDDK\3790.1830\inc\wxp

定義預處理器定義: WINNT

Window XP驅動開發(八) WDK源碼中 usbView 例子的編譯及說明
步驟三、修改usbview.rc檔案

(1)屏蔽掉第26行  //#include <common.ver>

不然編譯通過,但報錯 error RC2104: undefined keyword or key name: VER_FILEFLAGSMASK

Window XP驅動開發(八) WDK源碼中 usbView 例子的編譯及說明

(2)屏蔽掉第78 79行

#ifndef WINNT

    //LTEXT           "Version",IDC_STATIC,55,45,24,8

    //LTEXT           VER_PRODUCTVERSION_STR,IDC_STATIC,87,45,33,8

#endif

不然報錯

VER_PRODUCTVERSION_STR未定義

==========================================================================================================

編譯通過了.   ^-^

2、分析源碼

(1)WinMain做使能指定堆的特征,然後就是建立視窗了

int WINAPI
WinMain (
    __in HINSTANCE hInstance,
    __in_opt HINSTANCE hPrevInstance,
    __in LPSTR lpCmdLine,
    __in int nCmdShow
)
{
    MSG     msg;
    HACCEL  hAccel;

	// 使能指定堆的特征
    HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);

    ghInstance = hInstance;

    

    ghSplitCursor = LoadCursor(ghInstance,
                               MAKEINTRESOURCE(IDC_SPLIT));

    if (!ghSplitCursor)
    {
        OOPS();
        return 0;
    }

    hAccel = LoadAccelerators(ghInstance,
                              MAKEINTRESOURCE(IDACCEL));

    if (!hAccel)
    {
        OOPS();
        return 0;
    }

    if (!CreateTextBuffer())
    {
        return 0;
    }

    if (!CreateMainWindow(nCmdShow))
    {
        return 0;
    }

    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(ghMainWnd,
                                  hAccel,
                                  &msg) &&
            !IsDialogMessage(ghMainWnd,
                             &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    DestroyTextBuffer();

    CHECKFORLEAKS();

    return 1;
}
           

(2)在初始化視窗裡向系統注冊了兩個通知:USB插入通知,HUB裝置通知; 然後就是調用RefreshTree();來重新整理樹Hub清單

BOOL
USBView_OnInitDialog (
    HWND    hWnd,
    HWND    hWndFocus,
    LPARAM  lParam
)
{
    HFONT                           hFont;
    HIMAGELIST                      himl;
    HICON                           hicon;
    DEV_BROADCAST_DEVICEINTERFACE   broadcastInterface;


    // 注冊當USB被插入的通知 
    broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;

    memcpy( &(broadcastInterface.dbcc_classguid),
            &(GUID_CLASS_USB_DEVICE),
            sizeof(struct _GUID));

    gNotifyDevHandle = RegisterDeviceNotification(hWnd,
                                                  &broadcastInterface,
                                                  DEVICE_NOTIFY_WINDOW_HANDLE);

    // 注冊Hub 通知
    memcpy( &(broadcastInterface.dbcc_classguid),
            &(GUID_CLASS_USBHUB),
            sizeof(struct _GUID));

    gNotifyHubHandle = RegisterDeviceNotification(hWnd,
                                                  &broadcastInterface,
                                                  DEVICE_NOTIFY_WINDOW_HANDLE);

    //end add

    ghTreeWnd = GetDlgItem(hWnd, IDC_TREE);

    //added
    if ((himl = ImageList_Create(15, 15,
                                 FALSE, 2, 0)) == NULL)
    {
        OOPS();
    }

    hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_ICON));
    giGoodDevice = ImageList_AddIcon(himl, hicon);

    hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_BADICON));
    giBadDevice = ImageList_AddIcon(himl, hicon);

    hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_COMPUTER));
    giComputer = ImageList_AddIcon(himl, hicon);

    hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_HUB));
    giHub = ImageList_AddIcon(himl, hicon);

    hicon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_NODEVICE));
    giNoDevice = ImageList_AddIcon(himl, hicon);


    TreeView_SetImageList(ghTreeWnd, himl, TVSIL_NORMAL);
    // end add


    ghEditWnd = GetDlgItem(hWnd, IDC_EDIT);

    ghStatusWnd = GetDlgItem(hWnd, IDC_STATUS);

    ghMainMenu = GetMenu(hWnd);

    if (ghMainMenu == NULL)
    {
        OOPS();
    }

    hFont  = CreateFont(13,  8, 0, 0,
                        400, 0, 0, 0,
                        0,   1, 2, 1,
                        49,  TEXT("Courier"));

    SendMessage(ghEditWnd,
                WM_SETFONT,
                (WPARAM) hFont,
                0);

	//  重新整理Hub清單
    RefreshTree();

    return FALSE;
}
           

 (3)

VOID RefreshTree (VOID)
{
    TCHAR  statusText[128];
    ULONG devicesConnected;
 
    // Clear the selection of the TreeView, so that when the tree is
    // destroyed, the control won't try to constantly "shift" the
    // selection to another item.
    //
    TreeView_SelectItem(ghTreeWnd, NULL);
 
    // Clear the edit control
    //
    SetWindowText(ghEditWnd, _T(""));
 
    // Destroy the current contents of the TreeView
    //
    if (ghTreeRoot)
    {
        WalkTree(ghTreeRoot, CleanupItem, 0);
 
        TreeView_DeleteAllItems(ghTreeWnd);
 
        ghTreeRoot = NULL;
    }
 
    // Create the root tree node
    //
    ghTreeRoot = AddLeaf(TVI_ROOT, 0, _T("My Computer"), ComputerIcon);
 
    if (ghTreeRoot != NULL)
    {
        // Enumerate all USB buses and populate the tree
        //
        EnumerateHostControllers(ghTreeRoot, &devicesConnected);
 
        //
        // Expand all tree nodes
        //
        WalkTree(ghTreeRoot, ExpandItem, 0);
 
        // Update Status Line with number of devices connected
        //
        _stprintf_s(statusText, sizeof(statusText)/sizeof(statusText[0]), _T("Devices Connected: %d   Hubs Connected: %d"),
                 devicesConnected, TotalHubs);
        SetWindowText(ghStatusWnd, statusText);
    }
    else
    {
        OOPS();
    }
 
}
           

從以上代碼可以看出RefreshTree做了以下幾件事:

(2、1)用Tree的TreeView_SelectIItem宏來清除TreeView中的選項。

目的是當樹被毀壞時,控件不會try to constantly "shift" the selection to another item。

(2、2)清除編輯框控件;

(2、3)毀壞TreeView目前的内容。

// Destroy the current contents of the TreeView
    //
    if (ghTreeRoot)
    {
        WalkTree(ghTreeRoot, CleanupItem, 0);
 
        TreeView_DeleteAllItems(ghTreeWnd);
 
        ghTreeRoot = NULL;
    }
           

WalkTree是一個不好了解的函數,它是一個遞歸函數,在兩個地方遞歸:

對于上面代碼,它首先會遞歸調用來找到ghTreeRoot的孩子節點,然後調用CleanupItem函數;

然後對ghTreeWnd調用CleanupItem函數;

最後會遞歸調用找到ghTreeRoot的弟兄節點,然後調用CleanupItem函數;

VOID
CleanupItem (
    HWND      hTreeWnd,
    HTREEITEM hTreeItem
)
{
    TV_ITEM tvi;
    PVOID   info;
 
    tvi.mask = TVIF_HANDLE | TVIF_PARAM;
    tvi.hItem = hTreeItem;
 
    TreeView_GetItem(hTreeWnd,
                     &tvi);
 
    info = (PVOID)tvi.lParam;
 
    if (info)
    {
        PTSTR                               DriverKey = NULL;
        PUSB_NODE_INFORMATION               HubInfo = NULL;
        PUSB_HUB_CAPABILITIES               HubCaps = NULL;
        PUSB_HUB_CAPABILITIES_EX            HubCapsEx = NULL;
        PTSTR                               HubName = NULL;
        PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfoEx = NULL;
        PUSB_DESCRIPTOR_REQUEST             ConfigDesc = NULL;
        PSTRING_DESCRIPTOR_NODE             StringDescs = NULL;
 
        switch (*(PUSBDEVICEINFOTYPE)info)
        {
            case HostControllerInfo:
                //
                // Remove this host controller from the list of enumerated
                // host controllers.
                //
                RemoveEntryList(&((PUSBHOSTCONTROLLERINFO)info)->ListEntry);
 
                DriverKey = ((PUSBHOSTCONTROLLERINFO)info)->DriverKey;
                break;
 
            case RootHubInfo:
                HubInfo = ((PUSBROOTHUBINFO)info)->HubInfo;
                HubName = ((PUSBROOTHUBINFO)info)->HubName;
                HubCaps = ((PUSBROOTHUBINFO)info)->HubCaps;
                HubCapsEx = ((PUSBROOTHUBINFO)info)->HubCapsEx;
                break;
 
            case ExternalHubInfo:
                HubInfo = ((PUSBEXTERNALHUBINFO)info)->HubInfo;
                HubName = ((PUSBEXTERNALHUBINFO)info)->HubName;
                HubCaps = ((PUSBROOTHUBINFO)info)->HubCaps;
                HubCapsEx = ((PUSBROOTHUBINFO)info)->HubCapsEx;
                ConnectionInfoEx = ((PUSBEXTERNALHUBINFO)info)->ConnectionInfo;
                ConfigDesc = ((PUSBEXTERNALHUBINFO)info)->ConfigDesc;
                StringDescs = ((PUSBEXTERNALHUBINFO)info)->StringDescs;
                break;
 
            case DeviceInfo:
                ConnectionInfoEx = ((PUSBDEVICEINFO)info)->ConnectionInfo;
                ConfigDesc = ((PUSBDEVICEINFO)info)->ConfigDesc;
                StringDescs = ((PUSBDEVICEINFO)info)->StringDescs;
                break;
        }
 
        if (DriverKey)
        {
            FREE(DriverKey);
        }
 
        if (HubInfo)
        {
            FREE(HubInfo);
        }
 
        if (HubName)
        {
            FREE(HubName);
        }
 
        if (HubCaps)
        {
            FREE(HubCaps);
        }
 
        if (HubCapsEx)
        {
            FREE(HubCapsEx);
        }
 
        if (ConfigDesc)
        {
            FREE(ConfigDesc);
        }
 
        if (StringDescs)
        {
            PSTRING_DESCRIPTOR_NODE Next;
 
            do {
 
                Next = StringDescs->Next;
                FREE(StringDescs);
                StringDescs = Next;
 
            } while (StringDescs);
        }
 
        if (ConnectionInfoEx)
        {
            FREE(ConnectionInfoEx);
        }
 
        FREE(info);
    }
}

           

(2、4)建立根樹節點

ghTreeRoot = AddLeaf(TVI_ROOT, 0, _T("My Computer"), ComputerIcon);

Window XP驅動開發(八) WDK源碼中 usbView 例子的編譯及說明

(2、5)枚舉所有的USB總線并填充入樹中

// Enumerate all USB buses and populate the tree
//
EnumerateHostControllers(ghTreeRoot, &devicesConnected);
           

EnumerateHostControllers做了以下事情:

(2、5、1)重複試主要制器并盡力打開它們;

如果打得開HCD裝置,那麼再去枚舉主要制器。

for (HCNum = 0; HCNum < NUM_HCS_TO_CHECK; HCNum++)
{
	_stprintf_s(HCName, sizeof(HCName)/sizeof(HCName[0]), _T("\\\\.\\HCD%d"), HCNum);

		   // 打開HCD裝置
	hHCDev = CreateFile(HCName,
						GENERIC_WRITE,
						FILE_SHARE_WRITE,
						NULL,
						OPEN_EXISTING,
						0,
						NULL);

	// If the handle is valid, then we've successfully opened a Host
	// Controller.  Display some info about the Host Controller itself,
	// then enumerate the Root Hub attached to the Host Controller.
	//
	if (hHCDev != INVALID_HANDLE_VALUE)
	{
		leafName = HCName + _tcslen(_T("\\\\.\\")) - _tcslen(_T(""));

				   // 枚舉主要制器
		EnumerateHostController(hTreeParent,
								hHCDev,
								leafName);

		CloseHandle(hHCDev);
	}
}
           

EnumerateHostController:

(2、5、1、1)配置設定一個結構體儲存關于主要制器的資訊

typedef struct _USBHOSTCONTROLLERINFO
{
    USBDEVICEINFOTYPE                   DeviceInfoType;
 
    LIST_ENTRY                          ListEntry;
 
    PTSTR                               DriverKey;
 
    ULONG                               VendorID;
 
    ULONG                               DeviceID;
 
    ULONG                               SubSysID;
 
    ULONG                               Revision;
 
} USBHOSTCONTROLLERINFO, *PUSBHOSTCONTROLLERINFO;
           
 hcInfo = (PUSBHOSTCONTROLLERINFO)ALLOC(sizeof(USBHOSTCONTROLLERINFO));      

(2、5、1、2)為此主要制器獲得驅動的主名字

 driverKeyName = GetHCDDriverKeyName(hHCDev);      

(2、5、1、3)它果它已經在枚舉的主要制器清單中,那麼就不枚舉了

listEntry = EnumeratedHCListHead.Flink;
 
while (listEntry != &EnumeratedHCListHead)
{
	hcInfoInList = CONTAINING_RECORD(listEntry,
									 USBHOSTCONTROLLERINFO,
									 ListEntry);

				   // 已經在清單中
	if (_tcscmp(driverKeyName, hcInfoInList->DriverKey) == 0)
	{
		// Already on the list, exit
		//
		FREE(driverKeyName);
		FREE(hcInfo);
		return;
	}

	listEntry = listEntry->Flink;
}
           

(2、5、1、4)為主要制器獲得裝置的id串

deviceDesc = DriverNameToDeviceDesc(driverKeyName, FALSE);
 
if (deviceDesc)
{
	leafName = deviceDesc;
}
else
{
	OOPS();
}
           

(2、5、1、5)增加此控制器到裝置樹中

hHCItem = AddLeaf(hTreeParent,
				  (LPARAM)hcInfo,
				  leafName,
				  GoodDeviceIcon);
           

添加後傳回HTREEITEM類型。

(2、5、1、6)把這個主要制器加入到已枚舉的主要制器清單中;

(2、5、1、7)獲得這個主要制器的root hub的名字,然後根據(2、5、1、5)中傳回的HTREEITEM變量來枚舉root hub;

rootHubName = GetRootHubName(hHCDev);
 
if (rootHubName != NULL)
{
	if (EnumerateHub(hHCItem,
				 rootHubName,
				 NULL,      // ConnectionInfo
				 NULL,      // ConfigDesc
				 NULL,      // StringDescs
				 _T("RootHub")  // DeviceDesc
				) == FALSE)
	{
		FREE(rootHubName);
	}
}
           

(2、5、2)現在用新的GUIO疊代主要制器(與(2、5、1)的操作有點類似)

deviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER,
                                     NULL,
                                     NULL,
                                     (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
           

HDEVINFO

  SetupDiGetClassDevs(

  const GUID* ClassGuid,

  PCTSTR Enumerator,

  HWND hwndParent,

  DWORD Flags

  );

參數說明  

輸入參數:

  PGUIDClassGuid

  在建立裝置清單的時候提供一個指向GUID的指針。如果設定了标志DIGCF_ALLCLASSES,則這個參數可以忽略,且清單結果中包括所有已經安裝的裝置類别。

  PCTSTREnumerator

  提供包含裝置執行個體的枚舉系統資料庫分支下的鍵名,可以通過它擷取裝置資訊。如果這個參數沒有指定,則要從整個枚舉樹中擷取所有裝置執行個體的裝置資訊。

  HWNDhwndParent

  提供頂級視窗的句柄,所有使用者接口可以使用它來與成員聯系。

  DWORDFlags

  提供在裝置資訊結構中使用的控制選項。可以是以下數值:

  DIGCF_PRESENT - 隻傳回目前存在的裝置。

  DIGCF_ALLCLASSES - 傳回所有已安裝的裝置。如果這個标志設定了,ClassGuid參數将被忽略。

  DIGCF_PROFILE - 隻傳回目前硬體配置檔案中的裝置。

  DIGCF_DEVICEINTERFACE - 傳回所有支援的裝置。

  DIGCF_DEFAULT - 隻傳回與系統預設裝置相關的裝置。

傳回值

  HDEVINFO

  如果函數運作成功,傳回裝置資訊結構的句柄,該結構包含與指定參數比對的所有已安裝裝置。如果失敗,則傳回INVALID_HANDLE_VALUE。調用GetLastError可以獲得更多錯誤資訊。

(2、5、2、1)根據(2、5、2)的傳回的的HDEVINFO枚舉出所有USB裝置的資訊。

for (index=0;
	 SetupDiEnumDeviceInterfaces(deviceInfo,
								 0,
								 (LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER,
								 index,
								 &deviceInfoData);
           

SetupDiEnumDeviceInterfaces為系統的API,它用于:

枚舉出被包含在裝置資訊集裡的接口。

BOOL SetupDiEnumDeviceInterfaces(
  _In_      HDEVINFO DeviceInfoSet,
  _In_opt_  PSP_DEVINFO_DATA DeviceInfoData,
  _In_      const GUID *InterfaceClassGuid,
  _In_      DWORD MemberIndex,
  _Out_     PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData
);
           

Parameters

DeviceInfoSet [in]

A pointer to a device information set that contains the device interfaces for which to return information. This handle is typically returned by SetupDiGetClassDevs .

DeviceInfoData [in, optional]

A pointer to an SP_DEVINFO_DATA structure that specifies a device information element in DeviceInfoSet. This parameter is optional and can be NULL. If this parameter is specified, SetupDiEnumDeviceInterfaces constrains the enumeration to the interfaces that are supported by the specified device. If this parameter is NULL, repeated calls to SetupDiEnumDeviceInterfaces return information about the interfaces that are associated with all the device information elements in DeviceInfoSet. This pointer is typically returned by SetupDiEnumDeviceInfo .

InterfaceClassGuid [in]

A pointer to a GUID that specifies the device interface class for the requested interface.

MemberIndex [in]

A zero-based index into the list of interfaces in the device information set. The caller should call this function first with MemberIndex set to zero to obtain the first interface. Then, repeatedly increment MemberIndex and retrieve an interface until this function fails and GetLastError returns ERROR_NO_MORE_ITEMS.

If DeviceInfoData specifies a particular device, the MemberIndex is relative to only the interfaces exposed by that device.

DeviceInterfaceData [out]

A pointer to a caller-allocated buffer that contains, on successful return, a completed SP_DEVICE_INTERFACE_DATA structure that identifies an interface that meets the search parameters. The caller must set DeviceInterfaceData.cbSize to sizeof(SP_DEVICE_INTERFACE_DATA) before calling this function.

(2、5、2、2)根據(2、5、2、1)得到的裝置資訊來獲得裝置接口的詳細資訊

SetupDiGetDeviceInterfaceDetail(deviceInfo,
                                            &deviceInfoData,
                                            NULL,
                                            0,
                                            &requiredLength,
                                            NULL);
 
deviceDetailData = GlobalAlloc(GPTR, requiredLength);

deviceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

		   // 獲得裝置接口的詳細資訊
SetupDiGetDeviceInterfaceDetail(deviceInfo,
								&deviceInfoData,
								deviceDetailData,
								requiredLength,
								&requiredLength,
								NULL);
           

(2、5、2、3)根據(2、5、2、2)得到的詳細資訊中的名稱來打開裝置,度枚舉出主要制器

hHCDev = CreateFile(deviceDetailData->DevicePath,
                                GENERIC_WRITE,
                                FILE_SHARE_WRITE,
                                NULL,
                                OPEN_EXISTING,
                                0,
                                NULL);
 
// If the handle is valid, then we've successfully opened a Host
// Controller.  Display some info about the Host Controller itself,
// then enumerate the Root Hub attached to the Host Controller.
//
if (hHCDev != INVALID_HANDLE_VALUE)
{
	leafName = deviceDetailData->DevicePath;

				   // 枚舉主要制器
	EnumerateHostController(hTreeParent,
							hHCDev,
							leafName);

	CloseHandle(hHCDev);
}
           

(2、6)擴充所有的樹節點

// Expand all tree nodes
//
WalkTree(ghTreeRoot, ExpandItem, 0);
           

(2、7)用已連接配接的裝置的ID号來更新狀态行。

_stprintf_s(statusText, sizeof(statusText)/sizeof(statusText[0]), _T("Devices Connected: %d   Hubs Connected: %d"),
                 devicesConnected, TotalHubs);
SetWindowText(ghStatusWnd, statusText);