604 lines
18 KiB
C++
604 lines
18 KiB
C++
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORP., 1993-1995
|
|
* TITLE: USBPOPUP.CPP
|
|
* VERSION: 1.0
|
|
* AUTHOR: jsenior
|
|
* DATE: 10/28/1998
|
|
*
|
|
********************************************************************************
|
|
*
|
|
* CHANGE LOG:
|
|
*
|
|
* DATE REV DESCRIPTION
|
|
* ---------- ------- ----------------------------------------------------------
|
|
* 10/28/1998 jsenior Original implementation.
|
|
*
|
|
*******************************************************************************/
|
|
#include "UsbPopup.h"
|
|
#include "PropPage.h"
|
|
#include "debug.h"
|
|
#include "usbutil.h"
|
|
|
|
UINT CALLBACK
|
|
UsbPopup::StaticDialogCallback(HWND Hwnd,
|
|
UINT Msg,
|
|
LPPROPSHEETPAGE Page)
|
|
{
|
|
UsbPopup *that;
|
|
|
|
switch (Msg) {
|
|
case PSPCB_CREATE:
|
|
return TRUE; // return TRUE to continue with creation of page
|
|
|
|
case PSPCB_RELEASE:
|
|
that = (UsbPopup*) Page->lParam;
|
|
DeleteChunk(that);
|
|
delete that;
|
|
|
|
return 0; // return value ignored
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
USBINT_PTR APIENTRY UsbPopup::StaticDialogProc(IN HWND hDlg,
|
|
IN UINT uMessage,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam)
|
|
{
|
|
UsbPopup *that;
|
|
|
|
that = (UsbPopup *) UsbGetWindowLongPtr(hDlg, USBDWLP_USER);
|
|
|
|
if (!that && uMessage != WM_INITDIALOG)
|
|
return FALSE; //DefDlgProc(hDlg, uMessage, wParam, lParam);
|
|
|
|
switch (uMessage) {
|
|
|
|
case WM_COMMAND:
|
|
return that->OnCommand(HIWORD(wParam),
|
|
LOWORD(wParam),
|
|
(HWND) lParam);
|
|
|
|
case WM_TIMER:
|
|
return that->OnTimer();
|
|
case WM_INITDIALOG:
|
|
that = (UsbPopup *) lParam;
|
|
UsbSetWindowLongPtr(hDlg, USBDWLP_USER, (USBLONG_PTR) that);
|
|
that->hWnd = hDlg;
|
|
|
|
return that->OnInitDialog(hDlg);
|
|
|
|
case WM_NOTIFY:
|
|
return that->OnNotify(hDlg, (int) wParam, (LPNMHDR) lParam);
|
|
case WM_DEVICECHANGE:
|
|
return that->OnDeviceChange(hDlg, wParam, (PDEV_BROADCAST_HDR)lParam);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return that->ActualDialogProc(hDlg, uMessage, wParam, lParam);
|
|
}
|
|
|
|
BOOL
|
|
UsbPopup::OnCommand(INT wNotifyCode,
|
|
INT wID,
|
|
HWND hCtl)
|
|
{
|
|
switch (wID) {
|
|
case IDOK:
|
|
EndDialog(hWnd, wID);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL UsbPopup::OnNotify(HWND hDlg, int nID, LPNMHDR pnmh)
|
|
{
|
|
|
|
switch (nID) {
|
|
case IDC_LIST_CONTROLLERS:
|
|
if (pnmh->code == NM_DBLCLK) {
|
|
//
|
|
// Display properties on this specific device on double click
|
|
//
|
|
UsbPropertyPage::DisplayPPSelectedListItem(hDlg, hListDevices);
|
|
}
|
|
return TRUE;
|
|
case IDC_TREE_HUBS:
|
|
if (pnmh->code == NM_DBLCLK) {
|
|
//
|
|
// Display properties on this specific device on double click
|
|
//
|
|
UsbPropertyPage::DisplayPPSelectedTreeItem(hDlg, hTreeDevices);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
UsbPopup::CustomDialog(
|
|
DWORD DialogBoxId,
|
|
DWORD IconId,
|
|
DWORD FormatStringId,
|
|
DWORD TitleStringId)
|
|
{
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Make sure the device hasn't gone away.
|
|
//
|
|
if (UsbItem::UsbItemType::Empty == deviceItem.itemType) {
|
|
return FALSE;
|
|
}
|
|
|
|
TCHAR buf[MAX_PATH];
|
|
TCHAR formatString[MAX_PATH];
|
|
LoadString(gHInst,
|
|
FormatStringId,
|
|
formatString,
|
|
MAX_PATH);
|
|
UsbSprintf(buf, formatString, deviceItem.configInfo->deviceDesc.c_str());
|
|
LoadString(gHInst, TitleStringId, formatString, MAX_PATH);
|
|
|
|
pun->SetBalloonRetry(-1, -1, 0);
|
|
pun->SetIconInfo(LoadIcon(gHInst, MAKEINTRESOURCE(IDI_USB)), formatString);
|
|
pun->SetBalloonInfo(formatString, buf, IconId);
|
|
|
|
//
|
|
// Query me every 2 seconds.
|
|
//
|
|
hr = pun->Show(this, 2000);
|
|
|
|
pun->Release();
|
|
|
|
if (S_OK == hr) {
|
|
if (-1 == DialogBoxParam(gHInst,
|
|
MAKEINTRESOURCE(DialogBoxId),
|
|
NULL,
|
|
StaticDialogProc,
|
|
(LPARAM) this)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) UsbPopup::AddRef()
|
|
{
|
|
return InterlockedIncrement(&RefCount);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) UsbPopup::Release()
|
|
{
|
|
if (InterlockedDecrement(&RefCount))
|
|
return RefCount;
|
|
|
|
// delete this;
|
|
return 0;
|
|
}
|
|
|
|
HRESULT UsbPopup::QueryInterface(REFIID iid, void **ppv)
|
|
{
|
|
if ((iid == IID_IUnknown) || (iid == IID_IQueryContinue)) {
|
|
*ppv = (void *)(IQueryContinue *)this;
|
|
}
|
|
else {
|
|
*ppv = NULL; // null the out param
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
UsbPopup::QueryContinue()
|
|
{
|
|
USB_NODE_CONNECTION_INFORMATION connectionInfo;
|
|
ULONG nBytes;
|
|
HANDLE hHubDevice;
|
|
String hubName = HubAcquireInfo->Buffer;
|
|
|
|
//
|
|
// Try to open the hub device
|
|
//
|
|
hHubDevice = GetHandleForDevice(hubName);
|
|
|
|
if (hHubDevice == INVALID_HANDLE_VALUE) {
|
|
return S_FALSE;
|
|
}
|
|
|
|
//
|
|
// Find out if we still have an underpowered device attached .
|
|
//
|
|
nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION);
|
|
ZeroMemory(&connectionInfo, nBytes);
|
|
connectionInfo.ConnectionIndex = ConnectionNotification->ConnectionNumber;
|
|
|
|
if ( !DeviceIoControl(hHubDevice,
|
|
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
|
|
&connectionInfo,
|
|
nBytes,
|
|
&connectionInfo,
|
|
nBytes,
|
|
&nBytes,
|
|
NULL)) {
|
|
return S_FALSE;
|
|
}
|
|
|
|
CloseHandle(hHubDevice);
|
|
|
|
switch (ConnectionNotification->NotificationType) {
|
|
case InsufficentBandwidth:
|
|
return connectionInfo.ConnectionStatus == DeviceNotEnoughBandwidth ? S_OK : S_FALSE;
|
|
case EnumerationFailure:
|
|
return connectionInfo.ConnectionStatus == DeviceFailedEnumeration ? S_OK : S_FALSE;
|
|
case InsufficentPower:
|
|
return connectionInfo.ConnectionStatus == DeviceNotEnoughPower ? S_OK : S_FALSE;
|
|
case OverCurrent:
|
|
return connectionInfo.ConnectionStatus == DeviceCausedOvercurrent ? S_OK : S_FALSE;
|
|
case ModernDeviceInLegacyHub:
|
|
return connectionInfo.ConnectionStatus == DeviceConnected ? S_OK : S_FALSE;
|
|
case HubNestedTooDeeply:
|
|
return connectionInfo.ConnectionStatus == DeviceHubNestedTooDeeply ? S_OK : S_FALSE;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
void
|
|
UsbPopup::Make(PUSB_CONNECTION_NOTIFICATION vUsbConnectionNotification,
|
|
LPTSTR strInstanceName)
|
|
{
|
|
ULONG result;
|
|
HRESULT hr;
|
|
String hubName;
|
|
|
|
InstanceName = strInstanceName;
|
|
|
|
ConnectionNotification = vUsbConnectionNotification;
|
|
|
|
result = WmiOpenBlock((LPGUID) &GUID_USB_WMI_STD_DATA,
|
|
0,
|
|
&WmiHandle);
|
|
|
|
if (result != ERROR_SUCCESS) {
|
|
goto UsbPopupMakeError;
|
|
}
|
|
|
|
hWnd = GetDesktopWindow();
|
|
|
|
InitCommonControls();
|
|
|
|
//
|
|
// Get the hub name and from that, get the name of the device to display in
|
|
// the dialog and display it.
|
|
// We'll use the port number which the device is attached to. This is:
|
|
// ConnectionNotification->ConnectionNumber;
|
|
HubAcquireInfo = GetHubName(WmiHandle,
|
|
strInstanceName,
|
|
ConnectionNotification);
|
|
if (!HubAcquireInfo) {
|
|
goto UsbPopupMakeError;
|
|
}
|
|
|
|
hubName = HubAcquireInfo->Buffer;
|
|
|
|
//
|
|
// Make sure that the condition still exists.
|
|
//
|
|
if (S_FALSE == QueryContinue()) {
|
|
USBTRACE((_T("Erorr does not exist anymore. Exitting.\n")));
|
|
goto UsbPopupMakeError;
|
|
}
|
|
|
|
if (!deviceItem.GetDeviceInfo(hubName,
|
|
ConnectionNotification->ConnectionNumber)) {
|
|
goto UsbPopupMakeError;
|
|
}
|
|
|
|
if (!IsPopupStillValid()) {
|
|
//
|
|
// We already saw the error for this device. Usbhub is being
|
|
// repetitive.
|
|
//
|
|
goto UsbPopupMakeError;
|
|
}
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
|
if (FAILED(hr)) {
|
|
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
|
|
}
|
|
if (FAILED(hr)) {
|
|
goto UsbPopupMakeError;
|
|
}
|
|
hr = CoCreateInstance(CLSID_UserNotification, NULL, CLSCTX_ALL,
|
|
IID_PPV_ARG(IUserNotification, &pun));
|
|
|
|
if (!FAILED(hr)) {
|
|
CustomDialogWrap();
|
|
}
|
|
|
|
CoUninitialize();
|
|
|
|
UsbPopupMakeError:
|
|
USBTRACE((_T("UsbPopupMakeError\n")));
|
|
if (WmiHandle != INVALID_HANDLE_VALUE) {
|
|
WmiCloseBlock(WmiHandle);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
UsbPopup::OnInitDialog(HWND HWnd)
|
|
{
|
|
hWnd = HWnd;
|
|
HANDLE hExclamation;
|
|
HICON hIcon;
|
|
|
|
if (RegisterForDeviceReattach) {
|
|
//
|
|
// Try to open the hub device
|
|
//
|
|
String hubName = HubAcquireInfo->Buffer;
|
|
HANDLE hHubDevice = GetHandleForDevice(hubName);
|
|
|
|
if (hHubDevice != INVALID_HANDLE_VALUE) {
|
|
//
|
|
// Register for notification for when the device is re-attached. We want
|
|
// to do this before we see the device get detached because we are polling
|
|
// and may miss the re-attach if we register when the device is removed.
|
|
//
|
|
// Allocate configuration information structure and get config mgr info
|
|
//
|
|
ConfigInfo = new UsbConfigInfo();
|
|
AddChunk(ConfigInfo);
|
|
if (ConfigInfo) {
|
|
String driverKeyName = GetDriverKeyName(hHubDevice,
|
|
ConnectionNotification->ConnectionNumber);
|
|
|
|
if (!driverKeyName.empty()) {
|
|
GetConfigMgrInfo(driverKeyName, ConfigInfo); // ISSUE: leak, jsenior, 4/19/00
|
|
} else {
|
|
USBWARN((_T("Couldn't get driver key name. Error: (%x)."), GetLastError()));
|
|
}
|
|
|
|
CHAR guidBuf[MAX_PATH];
|
|
DEV_BROADCAST_DEVICEINTERFACE devInterface;
|
|
DWORD len = MAX_PATH;
|
|
if (CM_Get_DevNode_Registry_PropertyA(ConfigInfo->devInst,
|
|
CM_DRP_CLASSGUID,
|
|
NULL,
|
|
guidBuf,
|
|
&len,
|
|
0) == CR_SUCCESS) {
|
|
|
|
ZeroMemory(&devInterface, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
|
|
if (StrToGUID(guidBuf, &devInterface.dbcc_classguid)) {
|
|
devInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
|
|
devInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
|
|
|
hNotifyArrival =
|
|
RegisterDeviceNotification( HWnd,
|
|
&devInterface,
|
|
DEVICE_NOTIFY_WINDOW_HANDLE);
|
|
|
|
if (!hNotifyArrival){
|
|
USBWARN((_T("RegisterDeviceNotification failure (%x)."), GetLastError()));
|
|
}
|
|
} else {
|
|
USBWARN((_T("GUID conversion didn't work.")));
|
|
}
|
|
USBWARN((_T("GUID data: %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x"),
|
|
devInterface.dbcc_classguid.Data1,
|
|
devInterface.dbcc_classguid.Data2,
|
|
devInterface.dbcc_classguid.Data3,
|
|
devInterface.dbcc_classguid.Data4[0],
|
|
devInterface.dbcc_classguid.Data4[1],
|
|
devInterface.dbcc_classguid.Data4[2],
|
|
devInterface.dbcc_classguid.Data4[3],
|
|
devInterface.dbcc_classguid.Data4[4],
|
|
devInterface.dbcc_classguid.Data4[5],
|
|
devInterface.dbcc_classguid.Data4[6],
|
|
devInterface.dbcc_classguid.Data4[7]));
|
|
} else {
|
|
//
|
|
// If this fails, we need to default to the old functionality!
|
|
// ISSUE: jsenior
|
|
//
|
|
}
|
|
}
|
|
CloseHandle(hHubDevice);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the Icon to an exclamation mark
|
|
//
|
|
if (NULL == (hIcon = LoadIcon(NULL, (LPTSTR) IDI_EXCLAMATION)) ||
|
|
NULL == (hExclamation = GetDlgItem(hWnd, IDC_ICON_POWER))) {
|
|
return FALSE;
|
|
}
|
|
SendMessage((HWND) hExclamation, STM_SETICON, (WPARAM) hIcon, NULL);
|
|
|
|
//
|
|
// Get a persistent handle to the tree view control
|
|
//
|
|
if (NULL == (hTreeDevices = GetDlgItem(HWnd, IDC_TREE_HUBS))) {
|
|
return FALSE;
|
|
}
|
|
|
|
TreeView_SetImageList(hTreeDevices, ImageList.ImageList(), TVSIL_NORMAL);
|
|
|
|
return Refresh();
|
|
}
|
|
|
|
PUSB_ACQUIRE_INFO
|
|
UsbPopup::GetHubName(WMIHANDLE WmiHandle,
|
|
UsbString InstanceName,
|
|
PUSB_CONNECTION_NOTIFICATION ConnectionNotification)
|
|
{
|
|
ULONG res, size;
|
|
PUSB_ACQUIRE_INFO usbAcquireInfo;
|
|
|
|
//
|
|
// zero all the vars, get the controllers name
|
|
//
|
|
size = ConnectionNotification->HubNameLength * sizeof(WCHAR)
|
|
+ sizeof(USB_ACQUIRE_INFO);
|
|
usbAcquireInfo = (PUSB_ACQUIRE_INFO) LocalAlloc(LMEM_ZEROINIT, size);
|
|
if (!usbAcquireInfo) {
|
|
USBERROR((_T("Acquire info allocation failed.")));
|
|
return NULL;
|
|
}
|
|
usbAcquireInfo->NotificationType = AcquireHubName;
|
|
usbAcquireInfo->TotalSize = size;
|
|
|
|
res = WmiExecuteMethod(WmiHandle,
|
|
InstanceName.c_str(),
|
|
AcquireHubName,
|
|
size,
|
|
usbAcquireInfo,
|
|
&size,
|
|
usbAcquireInfo
|
|
);
|
|
|
|
if (res != ERROR_SUCCESS) {
|
|
usbAcquireInfo = (PUSB_ACQUIRE_INFO) LocalFree(usbAcquireInfo);
|
|
}
|
|
return usbAcquireInfo;
|
|
}
|
|
|
|
BOOLEAN
|
|
UsbPopup::GetBusNotification(WMIHANDLE WmiHandle,
|
|
PUSB_BUS_NOTIFICATION UsbBusNotification)
|
|
{
|
|
ULONG res, size;
|
|
|
|
memset(UsbBusNotification, 0, sizeof(USB_BUS_NOTIFICATION));
|
|
UsbBusNotification->NotificationType = AcquireBusInfo;
|
|
size = sizeof(USB_BUS_NOTIFICATION);
|
|
|
|
res = WmiExecuteMethod(WmiHandle,
|
|
InstanceName.c_str(),
|
|
AcquireBusInfo,
|
|
size,
|
|
UsbBusNotification,
|
|
&size,
|
|
UsbBusNotification
|
|
);
|
|
|
|
if (res != ERROR_SUCCESS) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
PUSB_ACQUIRE_INFO
|
|
UsbPopup::GetControllerName(WMIHANDLE WmiHandle,
|
|
UsbString InstanceName)
|
|
{
|
|
ULONG res, size;
|
|
USB_BUS_NOTIFICATION usbBusNotification;
|
|
PUSB_ACQUIRE_INFO usbAcquireInfo;
|
|
|
|
memset(&usbBusNotification, 0, sizeof(USB_BUS_NOTIFICATION));
|
|
usbBusNotification.NotificationType = AcquireBusInfo;
|
|
size = sizeof(USB_BUS_NOTIFICATION);
|
|
|
|
res = WmiExecuteMethod(WmiHandle,
|
|
InstanceName.c_str(),
|
|
AcquireBusInfo,
|
|
size,
|
|
&usbBusNotification,
|
|
&size,
|
|
&usbBusNotification
|
|
);
|
|
|
|
if (res != ERROR_SUCCESS) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// zero all the vars, get the controllers name
|
|
//
|
|
size = usbBusNotification.ControllerNameLength * sizeof(WCHAR)
|
|
+ sizeof(USB_ACQUIRE_INFO);
|
|
usbAcquireInfo = (PUSB_ACQUIRE_INFO) LocalAlloc(LMEM_ZEROINIT, size);
|
|
usbAcquireInfo->NotificationType = AcquireControllerName;
|
|
usbAcquireInfo->TotalSize = size;
|
|
|
|
|
|
res = WmiExecuteMethod(WmiHandle,
|
|
InstanceName.c_str(),
|
|
AcquireControllerName,
|
|
size,
|
|
usbAcquireInfo,
|
|
&size,
|
|
usbAcquireInfo
|
|
);
|
|
|
|
if (res != ERROR_SUCCESS) {
|
|
usbAcquireInfo = (PUSB_ACQUIRE_INFO) LocalFree(usbAcquireInfo);
|
|
}
|
|
return usbAcquireInfo;
|
|
}
|
|
|
|
BOOL
|
|
UsbPopup::OnDeviceChange(HWND hDlg,
|
|
WPARAM wParam,
|
|
PDEV_BROADCAST_HDR devHdr)
|
|
{
|
|
PDEV_BROADCAST_DEVICEINTERFACE devInterface =
|
|
(PDEV_BROADCAST_DEVICEINTERFACE) devHdr;
|
|
USBTRACE((_T("Device change notification, type %x."), wParam));
|
|
switch (wParam) {
|
|
case DBT_DEVICEARRIVAL:
|
|
USBTRACE((_T("Device arrival.")));
|
|
if (devHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
|
|
USBTRACE((_T("Device: %s"),devInterface->dbcc_name));
|
|
// New device arrival.
|
|
// Compare the device description of this puppy to that of the one
|
|
// that we have.
|
|
//
|
|
if (devInterface->dbcc_name == ConfigInfo->deviceDesc &&
|
|
deviceState == DeviceDetachedError) {
|
|
USBTRACE((_T("Device name match on arrival!")));
|
|
//
|
|
// The device has been reattached!
|
|
//
|
|
deviceState = DeviceReattached;
|
|
Refresh();
|
|
}
|
|
}
|
|
break;
|
|
case DBT_DEVICEREMOVECOMPLETE:
|
|
USBTRACE((_T("Device removal.")));
|
|
if (devHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
|
|
USBTRACE((_T("Device: %s"),devInterface->dbcc_name));
|
|
// New device arrival.
|
|
// Compare the device description of this puppy to that of the one
|
|
// that we have.
|
|
//
|
|
if (devInterface->dbcc_name == ConfigInfo->deviceDesc &&
|
|
deviceState == DeviceAttachedError) {
|
|
USBTRACE((_T("Device name match on remove!")));
|
|
//
|
|
// The device has been reattached!
|
|
//
|
|
deviceState = DeviceDetachedError;
|
|
Refresh();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|