/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name: USBVIEW.C
Abstract: This is the GUI goop for the USBVIEW application.
Environment: user mode
Revision Hist: 04-25-97 : created
Todo: Save/restore WinPos/Divider, menu switches
--*/
//*****************************************************************************
// I N C L U D E S
//*****************************************************************************
#include <windows.h>
#include <basetyps.h>
#include <windowsx.h>
#include <shlwapi.h>
#include <devguid.h>
#include <setupapi.h>
#include <initguid.h>
#include <devioctl.h>
#include <usbioctl.h>
#include <dbt.h>
#include "usbview.h"
//*****************************************************************************
// D E F I N E S
//*****************************************************************************
// window control defines
//
#define SIZEBAR 0
#define WINDOWSCALEFACTOR 15
//*****************************************************************************
// G L O B A L S P R I V A T E T O T H I S F I L E
//*****************************************************************************
HINSTANCE ghInstance;
HWND ghMainWnd;
HMENU ghMainMenu;
HWND ghTreeWnd;
HWND ghEditWnd;
HWND ghStatusWnd;
HCURSOR ghSplitCursor;
BOOL gbButtonDown = FALSE;
HTREEITEM ghTreeRoot = NULL;
struct _CONFIG Config;
HDEVNOTIFY gNotifyDevHandle;
HDEVNOTIFY gNotifyHubHandle;
//*****************************************************************************
//
// WalkTree()
//
//*****************************************************************************
static VOID WalkTree (
HTREEITEM hTreeItem,
LPFNTREECALLBACK lpfnTreeCallback,
DWORD dwRefData
)
{
if (hTreeItem)
{
// Recursively call WalkTree on the node's first child.
//
WalkTree(TreeView_GetChild(ghTreeWnd, hTreeItem),
lpfnTreeCallback,
dwRefData);
//
// Call the lpfnCallBack on the node itself.
//
(*lpfnTreeCallback)(ghTreeWnd, hTreeItem);
//
//
// Recursively call WalkTree on the node's first sibling.
//
WalkTree(TreeView_GetNextSibling(ghTreeWnd, hTreeItem),
lpfnTreeCallback,
dwRefData);
}
}
//*****************************************************************************
//
// ExpandItem()
//
//*****************************************************************************
static VOID ExpandItem (
HWND hTreeWnd,
HTREEITEM hTreeItem
)
{
//
// Make this node visible.
//
TreeView_Expand(hTreeWnd, hTreeItem, TVE_EXPAND);
}
#if DBG
//*****************************************************************************
//
// Oops()
//
//*****************************************************************************
void Oops(LPCTSTR File,ULONG Line) {
TCHAR s[256];
wnsprintf(s,elemof(s), T("File: %s, Line %d"), File, Line);
MessageBox(ghMainWnd, s, T("Assertion failed!"), MB_OK);
}
#endif
//*****************************************************************************
//
// ResizeWindows()
//
// Handles resizing the two child windows of the main window. If
// bSizeBar is true, then the sizing is happening because the user is
// moving the bar. If bSizeBar is false, the sizing is happening
// because of the WM_SIZE or something like that.
//
//*****************************************************************************
static void ResizeWindows(BOOL bSizeBar, int BarLocation) {
RECT MainClientRect;
RECT MainWindowRect;
RECT TreeWindowRect;
RECT StatusWindowRect;
int xdiv; // the moveable divider
int ydiv; // the fixed border to the status window
HDWP dwp;
// Is the user moving the bar?
//
if (!bSizeBar) {
SendMessage(ghStatusWnd,WM_SIZE,0,0);
BarLocation = Config.BarLocation;
}
GetClientRect(ghMainWnd, &MainClientRect);
GetWindowRect(ghStatusWnd, &StatusWindowRect);
ydiv=MainClientRect.bottom-StatusWindowRect.bottom+StatusWindowRect.top;
// Make sure the bar is in a OK location
if (bSizeBar) {
if (BarLocation < GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR) return;
if ((MainClientRect.right - BarLocation) < GetSystemMetrics(SM_CXSCREEN)/WINDOWSCALEFACTOR) return;
}
// Save the bar location
Config.BarLocation = BarLocation;
dwp=BeginDeferWindowPos(2);
// Resize the tree window
dwp=DeferWindowPos(dwp,ghTreeWnd,0,0,0,BarLocation,ydiv,SWP_NOZORDER);
// Get the size of the window (in case move window failed
GetWindowRect(ghTreeWnd, &TreeWindowRect);
GetWindowRect(ghMainWnd, &MainWindowRect);
xdiv = TreeWindowRect.right-MainWindowRect.left+SIZEBAR;
// Move the edit window with respect to the tree window
dwp=DeferWindowPos(dwp,ghEditWnd,0,xdiv,0,MainClientRect.right-xdiv,ydiv,SWP_NOZORDER);
EndDeferWindowPos(dwp);
}
//*****************************************************************************
// AboutDlgProc()
//*****************************************************************************
static INT_PTR CALLBACK AboutDlgProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
case WM_INITDIALOG: return TRUE;
case WM_COMMAND: switch (LOWORD(wParam)) {
case IDOK:
case IDCANCEL: EndDialog(Wnd,0); break;
}break;
}
return FALSE;
}
//*****************************************************************************
// DestroyTree()
//*****************************************************************************
static VOID DestroyTree () {
// 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);
// Destroy the current contents of the TreeView
if (ghTreeRoot) {
WalkTree(ghTreeRoot, CleanupItem, 0);
TreeView_DeleteAllItems(ghTreeWnd);
ghTreeRoot = NULL;
}
}
//*****************************************************************************
// RefreshTree()
//*****************************************************************************
static void RefreshTree() {
TCHAR s[128]; // string
// 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
LoadString(ghInstance,2,s,elemof(s)); //"My Computer" - should be loaded from elsewhere!!
ghTreeRoot = AddLeaf(TVI_ROOT,0,0,"%s",s);
if (ghTreeRoot) {
int devicesConnected;
TCHAR t[128]; // template
// 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
LoadString(ghInstance,3,t,elemof(t)); //"Devices Connected: %d Hubs Connected: %d"
wnsprintf(s,elemof(s),t,devicesConnected,TotalHubs);
SetWindowText(ghStatusWnd,s);
}else OOPS();
}
void LoadConfig() {
HKEY key;
if (!RegOpenKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\usbview"),0,KEY_QUERY_VALUE,&key)) {
DWORD size=sizeof(Config);
RegQueryValueEx(key,T("Config"),NULL,NULL,(BYTE*)&Config,&size);
RegCloseKey(key);
}
}
void SaveConfig() {
HKEY key;
if (!RegCreateKeyEx(HKEY_CURRENT_USER,T("Software\\h#s\\usbview"),0,NULL,0,KEY_SET_VALUE,NULL,&key,NULL)) {
TCHAR s[128];
int len=LoadString(ghInstance,1,s,elemof(s))+1; //"USB tree view"
RegSetValueEx(key,NULL,0,REG_SZ,(BYTE*)s,len*sizeof(TCHAR)); // write a human-readable description
RegSetValueEx(key,T("Config"),0,REG_BINARY,(BYTE*)&Config,sizeof(Config));
RegCloseKey(key);
}
}
//*****************************************************************************
// Update the GUI for changing flags
//*****************************************************************************
void ConfigChanged(BYTE mask) {
if (mask&CFLAG_AUTOREFRESH) CheckMenuItem(ghMainMenu,17,Config.flags&CFLAG_AUTOREFRESH?MF_CHECKED:MF_UNCHECKED);
if (mask&CFLAG_CONFIGDESC) CheckMenuItem(ghMainMenu,18,Config.flags&CFLAG_CONFIGDESC?MF_CHECKED:MF_UNCHECKED);
if (mask&CFLAG_ENUM_NAME) CheckMenuItem(ghMainMenu,19,Config.flags&CFLAG_ENUM_NAME?MF_CHECKED:MF_UNCHECKED);
if (mask&CFLAG_ENUM_GUID) CheckMenuItem(ghMainMenu,20,Config.flags&CFLAG_ENUM_GUID?MF_CHECKED:MF_UNCHECKED);
if (mask&(CFLAG_CONFIGDESC|CFLAG_ENUM_NAME|CFLAG_ENUM_GUID)) RefreshTree();
}
//*****************************************************************************
// USBView_OnInitDialog()
//*****************************************************************************
static BOOL USBView_OnCreate(HWND Wnd, LPCREATESTRUCT cs) {
HFONT hFont;
HIMAGELIST himl;
DEV_BROADCAST_DEVICEINTERFACE broadcastInterface;
SP_CLASSIMAGELIST_DATA cid;
int iComputer, iUSB; // image indices
ghTreeWnd = CreateWindowEx(WS_EX_CLIENTEDGE,WC_TREEVIEW,T(""),
WS_VISIBLE|WS_CHILD|WS_TABSTOP|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT,
0,0,0,0,Wnd,(HMENU)1,ghInstance,NULL);
ghEditWnd = CreateWindowEx(WS_EX_CLIENTEDGE,WC_EDIT,T(""),
WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_HSCROLL|WS_VSCROLL|ES_MULTILINE|ES_READONLY,
0,0,0,0,Wnd,(HMENU)2,ghInstance,NULL);
ghStatusWnd=CreateWindowEx(0,STATUSCLASSNAME,T(""),
WS_VISIBLE|WS_CHILD|SBARS_SIZEGRIP,
0,0,0,0,Wnd,(HMENU)3,ghInstance,NULL);
ghMainMenu= GetMenu(Wnd);
// Register to receive notification when a USB device is plugged in.
broadcastInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
broadcastInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
broadcastInterface.dbcc_classguid=GUID_CLASS_USB_DEVICE;
gNotifyDevHandle = RegisterDeviceNotification(Wnd,&broadcastInterface,DEVICE_NOTIFY_WINDOW_HANDLE);
// Now register for Hub notifications.
broadcastInterface.dbcc_classguid=GUID_CLASS_USBHUB;
gNotifyHubHandle = RegisterDeviceNotification(Wnd,&broadcastInterface,DEVICE_NOTIFY_WINDOW_HANDLE);
//end add
//added
himl=ImageList_Create(16,16,ILC_MASK,6,1);
if (!himl) OOPS();
cid.cbSize=sizeof(cid);
if (!SetupDiGetClassImageList(&cid)) OOPS();
if (!SetupDiGetClassImageIndex(&cid,(LPGUID)&GUID_DEVCLASS_COMPUTER,&iComputer)) OOPS();
if (!SetupDiGetClassImageIndex(&cid,(LPGUID)&GUID_DEVCLASS_USB,&iUSB)) OOPS();
ImageList_AddIcon(himl,ImageList_GetIcon(cid.ImageList,iComputer,0)); // Index 0: Tree root (Monitor)
ImageList_AddIcon(himl,ImageList_GetIcon(cid.ImageList,iUSB,0)); // Index 1: Host Controller
ImageList_AddIcon(himl,LoadImage(ghInstance,MAKEINTRESOURCE(1),IMAGE_ICON,16,16,LR_SHARED)); // Index 2: Port without device
ImageList_AddIcon(himl,LoadImage(ghInstance,MAKEINTRESOURCE(2),IMAGE_ICON,16,16,LR_SHARED)); // Index 3: Port with device
ImageList_AddIcon(himl,LoadImage(ghInstance,MAKEINTRESOURCE(3),IMAGE_ICON,16,16,LR_SHARED)); // Index 4: Port's device is a HUB
ImageList_AddIcon(himl,LoadImage(0,IDI_WARNING,IMAGE_ICON,16,16,LR_SHARED)); // Index 5: Error
SetupDiDestroyClassImageList(&cid);
TreeView_SetImageList(ghTreeWnd,himl,TVSIL_NORMAL);
TreeView_SetIndent(ghTreeWnd,0); // less waste of space?
// end add
ConfigChanged(0xFF);
if (!ghMainMenu) OOPS();
hFont=CreateFont(13,8,0,0,400,0,0,0,0,1,2,1,49,T("Courier"));
SendMessage(ghEditWnd,WM_SETFONT,(WPARAM)hFont,0);
RefreshTree();
return TRUE;
}
//*****************************************************************************
// USBView_OnClose()
//*****************************************************************************
static void USBView_OnClose(HWND Wnd) {
WINDOWPLACEMENT wp;
wp.length=sizeof(wp);
if (GetWindowPlacement(Wnd,&wp)) {
Config.WinPos.left =(short)wp.rcNormalPosition.left;
Config.WinPos.top =(short)wp.rcNormalPosition.top;
Config.WinPos.right =(short)wp.rcNormalPosition.right;
Config.WinPos.bottom=(short)wp.rcNormalPosition.bottom;
Config.showCmd=wp.showCmd;
}
UnregisterDeviceNotification(gNotifyDevHandle);
UnregisterDeviceNotification(gNotifyHubHandle);
DestroyTree();
PostQuitMessage(0);
}
//*****************************************************************************
// USBView_OnCommand()
//*****************************************************************************
static void USBView_OnCommand(HWND Wnd, int id, HWND hwndCtl, UINT codeNotify) {
switch (id) {
case 17:
Config.flags^=CFLAG_AUTOREFRESH;
ConfigChanged(CFLAG_AUTOREFRESH);
break;
case 18:
Config.flags^=CFLAG_CONFIGDESC;
ConfigChanged(CFLAG_CONFIGDESC);
break;
case 19:
Config.flags^=CFLAG_ENUM_NAME; // then ensure one enumeration flag is ON
if (!(Config.flags&(CFLAG_ENUM_NAME|CFLAG_ENUM_GUID))) Config.flags|=CFLAG_ENUM_GUID;
ConfigChanged(CFLAG_ENUM_NAME|CFLAG_ENUM_GUID);
break;
case 20:
Config.flags^=CFLAG_ENUM_GUID; // then ensure one enumeration flag is ON
if (!(Config.flags&(CFLAG_ENUM_NAME|CFLAG_ENUM_GUID))) Config.flags|=CFLAG_ENUM_NAME;
ConfigChanged(CFLAG_ENUM_NAME|CFLAG_ENUM_GUID);
break;
case 9:
DialogBox(ghInstance,MAKEINTRESOURCE(9),Wnd,AboutDlgProc);
break;
case 7:
SendMessage(Wnd,WM_CLOSE,0,0);
break;
case 8:
RefreshTree();
break;
}
}
//*****************************************************************************
// USBView_OnLButtonDown()
//*****************************************************************************
static void USBView_OnLButtonDown(HWND Wnd, BOOL fDoubleClick, int x, int y, UINT keyFlags) {
gbButtonDown = TRUE;
SetCapture(Wnd);
}
//*****************************************************************************
// USBView_OnLButtonUp()
//*****************************************************************************
static void USBView_OnLButtonUp(HWND Wnd, int x, int y, UINT keyFlags) {
gbButtonDown = FALSE;
ReleaseCapture();
}
//*****************************************************************************
// USBView_OnMouseMove()
//*****************************************************************************
void USBView_OnMouseMove(HWND hWnd, int x, int y, UINT keyFlags) {
SetCursor(ghSplitCursor);
if (gbButtonDown) ResizeWindows(TRUE, x);
}
//*****************************************************************************
// USBView_OnSize();
//*****************************************************************************
static void USBView_OnSize(HWND hWnd, UINT state, int cx, int cy) {
ResizeWindows(FALSE, 0);
}
//*****************************************************************************
// USBView_OnNotify()
//*****************************************************************************
static LRESULT USBView_OnNotify(HWND hWnd, int DlgItem, LPNMHDR lpNMHdr) {
if (lpNMHdr->code == TVN_SELCHANGED) {
HTREEITEM hTreeItem = ((NM_TREEVIEW *)lpNMHdr)->itemNew.hItem;
if (hTreeItem) {
UpdateEditControl(ghEditWnd,ghTreeWnd,hTreeItem);
}
}
return 0;
}
//*****************************************************************************
// USBView_OnDeviceChange()
//*****************************************************************************
static BOOL USBView_OnDeviceChange(HWND hwnd, UINT uEvent, DWORD dwEventData) {
if (Config.flags&CFLAG_AUTOREFRESH) switch (uEvent) {
case DBT_DEVICEARRIVAL:
case DBT_DEVICEREMOVECOMPLETE: RefreshTree(); break;
}
return TRUE;
}
//*****************************************************************************
// MainWndProc()
//*****************************************************************************
static INT_PTR CALLBACK MainWndProc(HWND Wnd,UINT Msg,WPARAM wParam,LPARAM lParam) {
switch (Msg) {
HANDLE_MSG(Wnd, WM_CREATE, USBView_OnCreate);
HANDLE_MSG(Wnd, WM_CLOSE, USBView_OnClose);
HANDLE_MSG(Wnd, WM_COMMAND, USBView_OnCommand);
HANDLE_MSG(Wnd, WM_LBUTTONDOWN, USBView_OnLButtonDown);
HANDLE_MSG(Wnd, WM_LBUTTONUP, USBView_OnLButtonUp);
HANDLE_MSG(Wnd, WM_MOUSEMOVE, USBView_OnMouseMove);
HANDLE_MSG(Wnd, WM_SIZE, USBView_OnSize);
HANDLE_MSG(Wnd, WM_NOTIFY, USBView_OnNotify);
HANDLE_MSG(Wnd, WM_DEVICECHANGE, USBView_OnDeviceChange);
}
return DefWindowProc(Wnd,Msg,wParam,lParam);
}
//*****************************************************************************
// AddLeaf()
//*****************************************************************************
extern HTREEITEM AddLeaf(HTREEITEM hTreeParent, LPARAM lParam, int iImage, LPCSTR lpszText,...) {
TCHAR szBuffer[1024];
va_list list;
TV_INSERTSTRUCT tvins;
HTREEITEM hti;
// added for tree view icons
PUSB_NODE_CONNECTION_INFORMATION_EX ConnectInfo = NULL;
if (lParam) ConnectInfo = ((PUSBDEVICEINFO)lParam)->ConnectionInfo;
// end add
va_start(list, lpszText);
#ifdef UNICODE
{WCHAR t[256];
MultiByteToWideChar(CP_ACP,0,lpszText,-1,t,elemof(t));
wvsprintf(szBuffer,t,list);
}
#else
wvsprintf(szBuffer,lpszText,list);
#endif
ZeroMemory(&tvins,sizeof(tvins));
// Set the parent item
tvins.hParent = hTreeParent;
tvins.hInsertAfter = TVI_LAST;
// pszText and lParam members are valid
tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
// Set the text of the item.
tvins.item.pszText = szBuffer;
// Set the user context item
tvins.item.lParam = lParam;
// Add the item to the tree-view control.
hti = TreeView_InsertItem(ghTreeWnd, &tvins);
// added
tvins.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvins.item.hItem = hti;
tvins.item.iImage = tvins.item.iSelectedImage = iImage;
/*
if (!ConnectInfo) {
if (!(lstrcmpA("My Computer",lpszText))) {
tvins.item.iImage = tvins.item.iSelectedImage = giComputer;
}else{
//it is the host controller
}
}else{
if (ConnectInfo->DeviceIsHub) { // Device is a Hub!!
tvins.item.iImage = tvins.item.iSelectedImage = giHub;
}
if (!ConnectInfo->CurrentConfigurationValue) {
tvins.item.iImage = tvins.item.iSelectedImage = giBadDevice;
if (NoDeviceConnected == ConnectInfo->ConnectionStatus) { // Empty Port
tvins.item.iImage = tvins.item.iSelectedImage = giNoDevice;
}
}
}
*/
TreeView_SetItem(ghTreeWnd, &tvins.item);
return hti;
}
//*****************************************************************************
// CreateMainWindow()
//*****************************************************************************
static BOOL CreateMainWindow() {
RECT rc;
WNDCLASSEX wc;
TCHAR title[64];
ZeroMemory(&wc,sizeof(wc));
wc.cbSize=sizeof(wc);
wc.style=CS_DBLCLKS;
wc.lpszClassName=T("USBVIEW");
wc.lpszMenuName=MAKEINTRESOURCE(1);
wc.lpfnWndProc=MainWndProc;
wc.hIcon=LoadIcon(ghInstance,MAKEINTRESOURCE(1));
wc.hbrBackground=(HBRUSH)(COLOR_MENU+1);
wc.hIconSm=LoadImage(ghInstance,MAKEINTRESOURCE(1),IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),LR_SHARED);
RegisterClassEx(&wc);
InitCommonControls();
LoadString(ghInstance,1,title,elemof(title));
ghMainWnd = CreateWindowEx(0,T("USBVIEW"),title,WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
0,0,ghInstance,NULL);
// ghMainWnd = CreateDialog(ghInstance,
// MAKEINTRESOURCE(1),
// NULL,
// MainDlgProc);
if (!ghMainWnd) {
OOPS();
return FALSE;
}
if (Config.showCmd) {
WINDOWPLACEMENT wp;
wp.length=sizeof(wp);
if (GetWindowPlacement(ghMainWnd,&wp)) {
wp.rcNormalPosition.left =Config.WinPos.left;
wp.rcNormalPosition.top =Config.WinPos.top;
wp.rcNormalPosition.right =Config.WinPos.right;
wp.rcNormalPosition.bottom=Config.WinPos.bottom;
// wp.showCmd=Config.showCmd;
SetWindowPlacement(ghMainWnd,&wp);
}
}else{
GetWindowRect(ghMainWnd, &rc);
Config.BarLocation = (short)((rc.right - rc.left) / 3);
}
// ResizeWindows(FALSE, 0);
ShowWindow(ghMainWnd,Config.showCmd?Config.showCmd:SW_SHOWDEFAULT);
return TRUE;
}
//*****************************************************************************
// WinMain()
//*****************************************************************************
void WINAPI WinMainCRTStartup() {
MSG msg;
HACCEL hAccel;
WORD ver;
ghInstance = GetModuleHandle(NULL);
ghSplitCursor = LoadCursor(0,IDC_SIZEWE);
if (!ghSplitCursor) OOPS();
hAccel = LoadAccelerators(ghInstance,MAKEINTRESOURCE(1));
if (!hAccel) OOPS();
Config.flags=0x0F;
ver=(WORD)GetVersion();
ver=ver<<8|ver>>8; // swap bytes: major = HIGH, minor = LOW
if (ver>=0x501) Config.flags=0x0B; // with WinXP, remove EnumName method by default
LoadConfig(); // ... otherwise, two trees will appear
UsbIdsLoad(T("usb.ids"));
if (!CreateTextBuffer()) return;
if (!CreateMainWindow()) return;
while (GetMessage(&msg,0,0,0)) {
if (TranslateAccelerator(ghMainWnd,hAccel,&msg)) continue;
if (IsDialogMessage(ghMainWnd,&msg)) continue; // handle TAB key
TranslateMessage(&msg);
DispatchMessage(&msg);
}
DestroyTextBuffer();
SaveConfig();
CHECKFORLEAKS();
ExitProcess((UINT)msg.wParam);
}
Detected encoding: ASCII (7 bit) | 2
|