转载请标明是引用于 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.libsetupapi.lib
-----------------------------------------------------------------------------------------------------------------------------------------
.rc
D:\WINDDK\7600.16385.1\Debuggers\winext\manifest;
D:\WINDDK\3790.1830\inc\wxp
定义预处理器定义: WINNT
步骤三、修改usbview.rc文件 (1)屏蔽掉第26行//#include
不然编译通过,但报错 error RC2104: undefined keyword or key name: VER_FILEFLAGSMASK
(2)屏蔽掉第78 79行
#ifndef WINNT
//LTEXT"Version",IDC_STATIC,55,45,24,8
//LTEXTVER_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
)
{
MSGmsg;
HACCELhAccel;
// 使能指定堆的特征
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 (
HWNDhWnd,
HWNDhWndFocus,
LPARAMlParam
)
{
HFONThFont;
HIMAGELISThiml;
HICONhicon;
DEV_BROADCAST_DEVICEINTERFACEbroadcastInterface;
// 注册当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 addghTreeWnd = 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 addghEditWnd = 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)
{
TCHARstatusText[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: %dHubs 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 (
HWNDhTreeWnd,
HTREEITEM hTreeItem
)
{
TV_ITEM tvi;
PVOIDinfo;
tvi.mask = TVIF_HANDLE | TVIF_PARAM;
tvi.hItem = hTreeItem;
TreeView_GetItem(hTreeWnd,
&tvi);
info = (PVOID)tvi.lParam;
if (info)
{
PTSTRDriverKey = NULL;
PUSB_NODE_INFORMATIONHubInfo = NULL;
PUSB_HUB_CAPABILITIESHubCaps = NULL;
PUSB_HUB_CAPABILITIES_EXHubCapsEx = NULL;
PTSTRHubName = NULL;
PUSB_NODE_CONNECTION_INFORMATION_EX ConnectionInfoEx = NULL;
PUSB_DESCRIPTOR_REQUESTConfigDesc = NULL;
PSTRING_DESCRIPTOR_NODEStringDescs = 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);
(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
{
USBDEVICEINFOTYPEDeviceInfoType;
LIST_ENTRYListEntry;
PTSTRDriverKey;
ULONGVendorID;
ULONGDeviceID;
ULONGSubSysID;
ULONGRevision;
} 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)增加此控制器到设备树中
【window|Window XP驱动开发(八) WDK源码中 usbView 例子的编译及说明】
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 = https://www.it610.com/article/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: %dHubs Connected: %d"),
devicesConnected, TotalHubs);
SetWindowText(ghStatusWnd, statusText);
推荐阅读
- window API一天一练之共享内存
- app|利用XP实现自动定时关机
- window|Window XP驱动开发(十) 驱动程序的基本结构
- Android|android8.0源码下载
- 《Android开发艺术探索》|Window和WindowManager--《Android开发艺术探索》阅读笔记——第八章
- 软硬件使用|删除XP自带的massage(在“运行”执行就好了)
- web前端|JavaScript之局部变量变为全局变量
- 网络类|Windows Server 2012 R2 服务器安装与配置