Window XP驱动开发(八) WDK源码中 usbView 例子的编译及说明

 

转载请标明是引用于 http://blog.csdn.net/chenyujing1234 

欢迎大家提出意见,一起讨论!

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

 

 

1、编译过程

步骤一、加入.h .c .rc文件

将D:\WINDDK\7600.16385.1\src\usb\usbview下的文件加入到VS2005中新建的工程中。

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

 

步骤二、加.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

 

步骤三、修改usbview.rc文件

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

不然编译通过,但报错 error RC2104: undefined keyword or key name: VER_FILEFLAGSMASK

 

(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做了以下几件事:

21)用TreeTreeView_SelectIItem宏来清除TreeView中的选项。

目的是当树被毁坏时,控件不会try to constantly "shift" the selection to another item

22)清除编辑框控件;

23)毁坏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);
    }
}


 


24)创建根树节点

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


25)枚举所有的USB总线并填充入树中

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


EnumerateHostControllers做了以下事情:

251)重复试主控制器并尽力打开它们;

如果打得开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

2511)分配一个结构体保存关于主控制器的信息

 

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));


 

2512)为此主控制器获得驱动的主名字

 driverKeyName = GetHCDDriverKeyName(hHCDev);


 

2513)它果它已经在枚举的主控制器列表中,那么就不枚举了

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;
}



 

2514)为主控制器获得设备的id

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




 

2515)增加此控制器到设备树中

 

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



添加后返回HTREEITEM类型。

2516)把这个主控制器加入到已枚举的主控制器列表中;

2517)获得这个主控制器的root hub的名字,然后根据(2515)中返回的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);
	}
}



 

252)现在用新的GUIO迭代主控制器(与(251)的操作有点类似)

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可以获得更多错误信息

2521)根据(252)的返回的的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.

2522)根据(2521)得到的设备信息来获得设备接口的详细信息

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);



2523)根据(2522)得到的详细信息中的名称来打开设备,度枚举出主控制器

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);
}



26)扩展所有的树节点

  

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


 

27)用已连接的设备的ID号来更新状态行。

 

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



 

 

 

 

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
The USB Device Tree Viewer, short UsbTreeView is based upon the Microsoft "USBView" sample application found in the Windows Driver Development Kits and now standalone at GitHub. But it is source code only, there is no executable for end users provided. Meanwhile USBView comes as executables as part of the "Debugging Tools für Windows", see here: USBView. UsbTreeView started with the USBView source code from the DDK for Server 2003. Here are the improvements I've done: Informations from the Windows Device Management are collected and matched with the found USB devices; Therefore UsbTreeView can show the child devices, including drive letters and COM-ports Window position is saved Background color and font of the right pane can be set (the font shown in the screenshots is DOSLike 7) Text output rearranged Keeps the tree item selection over refresh way more descriptors are decoded, as Audio 2.0 Hexdump of the descriptors can be shown Safe removal, device restart and port restart Extended USB information available under Windows 8 (taken from the latest USBView sample application) Extended information about host controllers Enumeration of the USB devices accelerated and independent from the treeview Failed USB requests are re-tried in the background, e.g. if a USB mouse was moved while requesting its properties Toolbar with jump-lists for easily finding devices in complex trees TreeView with handmade 16x16 icons, USBView used 32x32 icons scaled down to 15x15 many minor improvements With V3.0 No more enumeration of all devices on arrival and removal of a USB device Search function (not full text, only things like device ID, drive letter, volume name etc) Some new Keyboard shortcuts (Alt+D to open the drives list, Alt+O the Others list, Alt+S to focus the search edit, Alt+Left/Right to cycle thru the search hits Options not to expand empty hubs or hub with only empty hubs attached Options to jump to arrived and removed devices Option to expand tree items to make selected

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值