引用于 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;
-
-
-
- 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);
-
-
- memcpy( &(broadcastInterface.dbcc_classguid),
- &(GUID_CLASS_USBHUB),
- sizeof(struct _GUID));
-
- gNotifyHubHandle = RegisterDeviceNotification(hWnd,
- &broadcastInterface,
- DEVICE_NOTIFY_WINDOW_HANDLE);
-
-
-
- ghTreeWnd = GetDlgItem(hWnd, IDC_TREE);
-
-
- 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);
-
-
-
- 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);
-
-
- RefreshTree();
-
- return FALSE;
- }
(3)
- VOID RefreshTree (VOID)
- {
- TCHAR statusText[128];
- ULONG devicesConnected;
-
-
-
-
-
- TreeView_SelectItem(ghTreeWnd, NULL);
-
-
-
- SetWindowText(ghEditWnd, _T(""));
-
-
-
- if (ghTreeRoot)
- {
- WalkTree(ghTreeRoot, CleanupItem, 0);
-
- TreeView_DeleteAllItems(ghTreeWnd);
-
- ghTreeRoot = NULL;
- }
-
-
-
- ghTreeRoot = AddLeaf(TVI_ROOT, 0, _T("My Computer"), ComputerIcon);
-
- if (ghTreeRoot != NULL)
- {
-
-
- EnumerateHostControllers(ghTreeRoot, &devicesConnected);
-
-
-
-
- WalkTree(ghTreeRoot, ExpandItem, 0);
-
-
-
- _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当前的内容。
-
-
- if (ghTreeRoot)
- {
- WalkTree(ghTreeRoot, CleanupItem, 0);
-
- TreeView_DeleteAllItems(ghTreeWnd);
-
- ghTreeRoot = NULL;
- }
WalkTree是一个不好理解的函数,它是一个递归函数,在两个地方递归:
对于上面代码,它首先会递归调用来找到ghTreeRoot的孩子节点,然后调用CleanupItem函数;
然后对ghTreeWnd调用CleanupItem函数;
最后会递归调用找到ghTreeRoot的弟兄节点,然后调用CleanupItem函数;
(2、4)创建根树节点
ghTreeRoot = AddLeaf(TVI_ROOT, 0, _T("My Computer"), ComputerIcon);
(2、5)枚举所有的USB总线并填充入树中
-
-
- 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);
-
-
- hHCDev = CreateFile(HCName,
- GENERIC_WRITE,
- FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL);
-
-
-
-
-
- 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)
- {
-
-
- 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,
- NULL,
- NULL,
- _T("RootHub")
- ) == 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, SetupDiEnumDeviceInterfacesconstrains the enumeration to the interfaces that are supported by the specified device. If this parameter isNULL, 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 bySetupDiEnumDeviceInfo .
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 completedSP_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 (hHCDev != INVALID_HANDLE_VALUE)
- {
- leafName = deviceDetailData->DevicePath;
-
-
- EnumerateHostController(hTreeParent,
- hHCDev,
- leafName);
-
- CloseHandle(hHCDev);
- }
(2、6)扩展所有的树节点
-
-
- 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);