Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

603 lines
18 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1993-1995
  4. * TITLE: USBPOPUP.CPP
  5. * VERSION: 1.0
  6. * AUTHOR: jsenior
  7. * DATE: 10/28/1998
  8. *
  9. ********************************************************************************
  10. *
  11. * CHANGE LOG:
  12. *
  13. * DATE REV DESCRIPTION
  14. * ---------- ------- ----------------------------------------------------------
  15. * 10/28/1998 jsenior Original implementation.
  16. *
  17. *******************************************************************************/
  18. #include "UsbPopup.h"
  19. #include "PropPage.h"
  20. #include "debug.h"
  21. #include "usbutil.h"
  22. UINT CALLBACK
  23. UsbPopup::StaticDialogCallback(HWND Hwnd,
  24. UINT Msg,
  25. LPPROPSHEETPAGE Page)
  26. {
  27. UsbPopup *that;
  28. switch (Msg) {
  29. case PSPCB_CREATE:
  30. return TRUE; // return TRUE to continue with creation of page
  31. case PSPCB_RELEASE:
  32. that = (UsbPopup*) Page->lParam;
  33. DeleteChunk(that);
  34. delete that;
  35. return 0; // return value ignored
  36. default:
  37. break;
  38. }
  39. return TRUE;
  40. }
  41. USBINT_PTR APIENTRY UsbPopup::StaticDialogProc(IN HWND hDlg,
  42. IN UINT uMessage,
  43. IN WPARAM wParam,
  44. IN LPARAM lParam)
  45. {
  46. UsbPopup *that;
  47. that = (UsbPopup *) UsbGetWindowLongPtr(hDlg, USBDWLP_USER);
  48. if (!that && uMessage != WM_INITDIALOG)
  49. return FALSE; //DefDlgProc(hDlg, uMessage, wParam, lParam);
  50. switch (uMessage) {
  51. case WM_COMMAND:
  52. return that->OnCommand(HIWORD(wParam),
  53. LOWORD(wParam),
  54. (HWND) lParam);
  55. case WM_TIMER:
  56. return that->OnTimer();
  57. case WM_INITDIALOG:
  58. that = (UsbPopup *) lParam;
  59. UsbSetWindowLongPtr(hDlg, USBDWLP_USER, (USBLONG_PTR) that);
  60. that->hWnd = hDlg;
  61. return that->OnInitDialog(hDlg);
  62. case WM_NOTIFY:
  63. return that->OnNotify(hDlg, (int) wParam, (LPNMHDR) lParam);
  64. case WM_DEVICECHANGE:
  65. return that->OnDeviceChange(hDlg, wParam, (PDEV_BROADCAST_HDR)lParam);
  66. default:
  67. break;
  68. }
  69. return that->ActualDialogProc(hDlg, uMessage, wParam, lParam);
  70. }
  71. BOOL
  72. UsbPopup::OnCommand(INT wNotifyCode,
  73. INT wID,
  74. HWND hCtl)
  75. {
  76. switch (wID) {
  77. case IDOK:
  78. EndDialog(hWnd, wID);
  79. return TRUE;
  80. }
  81. return FALSE;
  82. }
  83. BOOL UsbPopup::OnNotify(HWND hDlg, int nID, LPNMHDR pnmh)
  84. {
  85. switch (nID) {
  86. case IDC_LIST_CONTROLLERS:
  87. if (pnmh->code == NM_DBLCLK) {
  88. //
  89. // Display properties on this specific device on double click
  90. //
  91. UsbPropertyPage::DisplayPPSelectedListItem(hDlg, hListDevices);
  92. }
  93. return TRUE;
  94. case IDC_TREE_HUBS:
  95. if (pnmh->code == NM_DBLCLK) {
  96. //
  97. // Display properties on this specific device on double click
  98. //
  99. UsbPropertyPage::DisplayPPSelectedTreeItem(hDlg, hTreeDevices);
  100. }
  101. return TRUE;
  102. }
  103. return 0;
  104. }
  105. BOOL
  106. UsbPopup::CustomDialog(
  107. DWORD DialogBoxId,
  108. DWORD IconId,
  109. DWORD FormatStringId,
  110. DWORD TitleStringId)
  111. {
  112. HRESULT hr;
  113. //
  114. // Make sure the device hasn't gone away.
  115. //
  116. if (UsbItem::UsbItemType::Empty == deviceItem.itemType) {
  117. return FALSE;
  118. }
  119. TCHAR buf[MAX_PATH];
  120. TCHAR formatString[MAX_PATH];
  121. LoadString(gHInst,
  122. FormatStringId,
  123. formatString,
  124. MAX_PATH);
  125. UsbSprintf(buf, formatString, deviceItem.configInfo->deviceDesc.c_str());
  126. LoadString(gHInst, TitleStringId, formatString, MAX_PATH);
  127. pun->SetBalloonRetry(-1, -1, 0);
  128. pun->SetIconInfo(LoadIcon(gHInst, MAKEINTRESOURCE(IDI_USB)), formatString);
  129. pun->SetBalloonInfo(formatString, buf, IconId);
  130. //
  131. // Query me every 2 seconds.
  132. //
  133. hr = pun->Show(this, 2000);
  134. pun->Release();
  135. if (S_OK == hr) {
  136. if (-1 == DialogBoxParam(gHInst,
  137. MAKEINTRESOURCE(DialogBoxId),
  138. NULL,
  139. StaticDialogProc,
  140. (LPARAM) this)) {
  141. return FALSE;
  142. }
  143. }
  144. return TRUE;
  145. }
  146. STDMETHODIMP_(ULONG) UsbPopup::AddRef()
  147. {
  148. return InterlockedIncrement(&RefCount);
  149. }
  150. STDMETHODIMP_(ULONG) UsbPopup::Release()
  151. {
  152. if (InterlockedDecrement(&RefCount))
  153. return RefCount;
  154. // delete this;
  155. return 0;
  156. }
  157. HRESULT UsbPopup::QueryInterface(REFIID iid, void **ppv)
  158. {
  159. if ((iid == IID_IUnknown) || (iid == IID_IQueryContinue)) {
  160. *ppv = (void *)(IQueryContinue *)this;
  161. }
  162. else {
  163. *ppv = NULL; // null the out param
  164. return E_NOINTERFACE;
  165. }
  166. AddRef();
  167. return S_OK;
  168. }
  169. HRESULT
  170. UsbPopup::QueryContinue()
  171. {
  172. USB_NODE_CONNECTION_INFORMATION connectionInfo;
  173. ULONG nBytes;
  174. HANDLE hHubDevice;
  175. String hubName = HubAcquireInfo->Buffer;
  176. //
  177. // Try to open the hub device
  178. //
  179. hHubDevice = GetHandleForDevice(hubName);
  180. if (hHubDevice == INVALID_HANDLE_VALUE) {
  181. return S_FALSE;
  182. }
  183. //
  184. // Find out if we still have an underpowered device attached .
  185. //
  186. nBytes = sizeof(USB_NODE_CONNECTION_INFORMATION);
  187. ZeroMemory(&connectionInfo, nBytes);
  188. connectionInfo.ConnectionIndex = ConnectionNotification->ConnectionNumber;
  189. if ( !DeviceIoControl(hHubDevice,
  190. IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
  191. &connectionInfo,
  192. nBytes,
  193. &connectionInfo,
  194. nBytes,
  195. &nBytes,
  196. NULL)) {
  197. return S_FALSE;
  198. }
  199. CloseHandle(hHubDevice);
  200. switch (ConnectionNotification->NotificationType) {
  201. case InsufficentBandwidth:
  202. return connectionInfo.ConnectionStatus == DeviceNotEnoughBandwidth ? S_OK : S_FALSE;
  203. case EnumerationFailure:
  204. return connectionInfo.ConnectionStatus == DeviceFailedEnumeration ? S_OK : S_FALSE;
  205. case InsufficentPower:
  206. return connectionInfo.ConnectionStatus == DeviceNotEnoughPower ? S_OK : S_FALSE;
  207. case OverCurrent:
  208. return connectionInfo.ConnectionStatus == DeviceCausedOvercurrent ? S_OK : S_FALSE;
  209. case ModernDeviceInLegacyHub:
  210. return connectionInfo.ConnectionStatus == DeviceConnected ? S_OK : S_FALSE;
  211. case HubNestedTooDeeply:
  212. return connectionInfo.ConnectionStatus == DeviceHubNestedTooDeeply ? S_OK : S_FALSE;
  213. }
  214. return S_FALSE;
  215. }
  216. void
  217. UsbPopup::Make(PUSB_CONNECTION_NOTIFICATION vUsbConnectionNotification,
  218. LPTSTR strInstanceName)
  219. {
  220. ULONG result;
  221. HRESULT hr;
  222. String hubName;
  223. InstanceName = strInstanceName;
  224. ConnectionNotification = vUsbConnectionNotification;
  225. result = WmiOpenBlock((LPGUID) &GUID_USB_WMI_STD_DATA,
  226. 0,
  227. &WmiHandle);
  228. if (result != ERROR_SUCCESS) {
  229. goto UsbPopupMakeError;
  230. }
  231. hWnd = GetDesktopWindow();
  232. InitCommonControls();
  233. //
  234. // Get the hub name and from that, get the name of the device to display in
  235. // the dialog and display it.
  236. // We'll use the port number which the device is attached to. This is:
  237. // ConnectionNotification->ConnectionNumber;
  238. HubAcquireInfo = GetHubName(WmiHandle,
  239. strInstanceName,
  240. ConnectionNotification);
  241. if (!HubAcquireInfo) {
  242. goto UsbPopupMakeError;
  243. }
  244. hubName = HubAcquireInfo->Buffer;
  245. //
  246. // Make sure that the condition still exists.
  247. //
  248. if (S_FALSE == QueryContinue()) {
  249. USBTRACE((_T("Erorr does not exist anymore. Exitting.\n")));
  250. goto UsbPopupMakeError;
  251. }
  252. if (!deviceItem.GetDeviceInfo(hubName,
  253. ConnectionNotification->ConnectionNumber)) {
  254. goto UsbPopupMakeError;
  255. }
  256. if (!IsPopupStillValid()) {
  257. //
  258. // We already saw the error for this device. Usbhub is being
  259. // repetitive.
  260. //
  261. goto UsbPopupMakeError;
  262. }
  263. hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  264. if (FAILED(hr)) {
  265. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
  266. }
  267. if (FAILED(hr)) {
  268. goto UsbPopupMakeError;
  269. }
  270. hr = CoCreateInstance(CLSID_UserNotification, NULL, CLSCTX_ALL,
  271. IID_PPV_ARG(IUserNotification, &pun));
  272. if (!FAILED(hr)) {
  273. CustomDialogWrap();
  274. }
  275. CoUninitialize();
  276. UsbPopupMakeError:
  277. USBTRACE((_T("UsbPopupMakeError\n")));
  278. if (WmiHandle != INVALID_HANDLE_VALUE) {
  279. WmiCloseBlock(WmiHandle);
  280. }
  281. }
  282. BOOL
  283. UsbPopup::OnInitDialog(HWND HWnd)
  284. {
  285. hWnd = HWnd;
  286. HANDLE hExclamation;
  287. HICON hIcon;
  288. if (RegisterForDeviceReattach) {
  289. //
  290. // Try to open the hub device
  291. //
  292. String hubName = HubAcquireInfo->Buffer;
  293. HANDLE hHubDevice = GetHandleForDevice(hubName);
  294. if (hHubDevice != INVALID_HANDLE_VALUE) {
  295. //
  296. // Register for notification for when the device is re-attached. We want
  297. // to do this before we see the device get detached because we are polling
  298. // and may miss the re-attach if we register when the device is removed.
  299. //
  300. // Allocate configuration information structure and get config mgr info
  301. //
  302. ConfigInfo = new UsbConfigInfo();
  303. AddChunk(ConfigInfo);
  304. if (ConfigInfo) {
  305. String driverKeyName = GetDriverKeyName(hHubDevice,
  306. ConnectionNotification->ConnectionNumber);
  307. if (!driverKeyName.empty()) {
  308. GetConfigMgrInfo(driverKeyName, ConfigInfo); // ISSUE: leak, jsenior, 4/19/00
  309. } else {
  310. USBWARN((_T("Couldn't get driver key name. Error: (%x)."), GetLastError()));
  311. }
  312. CHAR guidBuf[MAX_PATH];
  313. DEV_BROADCAST_DEVICEINTERFACE devInterface;
  314. DWORD len = MAX_PATH;
  315. if (CM_Get_DevNode_Registry_PropertyA(ConfigInfo->devInst,
  316. CM_DRP_CLASSGUID,
  317. NULL,
  318. guidBuf,
  319. &len,
  320. 0) == CR_SUCCESS) {
  321. ZeroMemory(&devInterface, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
  322. if (StrToGUID(guidBuf, &devInterface.dbcc_classguid)) {
  323. devInterface.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  324. devInterface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  325. hNotifyArrival =
  326. RegisterDeviceNotification( HWnd,
  327. &devInterface,
  328. DEVICE_NOTIFY_WINDOW_HANDLE);
  329. if (!hNotifyArrival){
  330. USBWARN((_T("RegisterDeviceNotification failure (%x)."), GetLastError()));
  331. }
  332. } else {
  333. USBWARN((_T("GUID conversion didn't work.")));
  334. }
  335. USBWARN((_T("GUID data: %x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x"),
  336. devInterface.dbcc_classguid.Data1,
  337. devInterface.dbcc_classguid.Data2,
  338. devInterface.dbcc_classguid.Data3,
  339. devInterface.dbcc_classguid.Data4[0],
  340. devInterface.dbcc_classguid.Data4[1],
  341. devInterface.dbcc_classguid.Data4[2],
  342. devInterface.dbcc_classguid.Data4[3],
  343. devInterface.dbcc_classguid.Data4[4],
  344. devInterface.dbcc_classguid.Data4[5],
  345. devInterface.dbcc_classguid.Data4[6],
  346. devInterface.dbcc_classguid.Data4[7]));
  347. } else {
  348. //
  349. // If this fails, we need to default to the old functionality!
  350. // ISSUE: jsenior
  351. //
  352. }
  353. }
  354. CloseHandle(hHubDevice);
  355. }
  356. }
  357. //
  358. // Set the Icon to an exclamation mark
  359. //
  360. if (NULL == (hIcon = LoadIcon(NULL, (LPTSTR) IDI_EXCLAMATION)) ||
  361. NULL == (hExclamation = GetDlgItem(hWnd, IDC_ICON_POWER))) {
  362. return FALSE;
  363. }
  364. SendMessage((HWND) hExclamation, STM_SETICON, (WPARAM) hIcon, NULL);
  365. //
  366. // Get a persistent handle to the tree view control
  367. //
  368. if (NULL == (hTreeDevices = GetDlgItem(HWnd, IDC_TREE_HUBS))) {
  369. return FALSE;
  370. }
  371. TreeView_SetImageList(hTreeDevices, ImageList.ImageList(), TVSIL_NORMAL);
  372. return Refresh();
  373. }
  374. PUSB_ACQUIRE_INFO
  375. UsbPopup::GetHubName(WMIHANDLE WmiHandle,
  376. UsbString InstanceName,
  377. PUSB_CONNECTION_NOTIFICATION ConnectionNotification)
  378. {
  379. ULONG res, size;
  380. PUSB_ACQUIRE_INFO usbAcquireInfo;
  381. //
  382. // zero all the vars, get the controllers name
  383. //
  384. size = ConnectionNotification->HubNameLength * sizeof(WCHAR)
  385. + sizeof(USB_ACQUIRE_INFO);
  386. usbAcquireInfo = (PUSB_ACQUIRE_INFO) LocalAlloc(LMEM_ZEROINIT, size);
  387. if (!usbAcquireInfo) {
  388. USBERROR((_T("Acquire info allocation failed.")));
  389. return NULL;
  390. }
  391. usbAcquireInfo->NotificationType = AcquireHubName;
  392. usbAcquireInfo->TotalSize = size;
  393. res = WmiExecuteMethod(WmiHandle,
  394. InstanceName.c_str(),
  395. AcquireHubName,
  396. size,
  397. usbAcquireInfo,
  398. &size,
  399. usbAcquireInfo
  400. );
  401. if (res != ERROR_SUCCESS) {
  402. usbAcquireInfo = (PUSB_ACQUIRE_INFO) LocalFree(usbAcquireInfo);
  403. }
  404. return usbAcquireInfo;
  405. }
  406. BOOLEAN
  407. UsbPopup::GetBusNotification(WMIHANDLE WmiHandle,
  408. PUSB_BUS_NOTIFICATION UsbBusNotification)
  409. {
  410. ULONG res, size;
  411. memset(UsbBusNotification, 0, sizeof(USB_BUS_NOTIFICATION));
  412. UsbBusNotification->NotificationType = AcquireBusInfo;
  413. size = sizeof(USB_BUS_NOTIFICATION);
  414. res = WmiExecuteMethod(WmiHandle,
  415. InstanceName.c_str(),
  416. AcquireBusInfo,
  417. size,
  418. UsbBusNotification,
  419. &size,
  420. UsbBusNotification
  421. );
  422. if (res != ERROR_SUCCESS) {
  423. return FALSE;
  424. }
  425. return TRUE;
  426. }
  427. PUSB_ACQUIRE_INFO
  428. UsbPopup::GetControllerName(WMIHANDLE WmiHandle,
  429. UsbString InstanceName)
  430. {
  431. ULONG res, size;
  432. USB_BUS_NOTIFICATION usbBusNotification;
  433. PUSB_ACQUIRE_INFO usbAcquireInfo;
  434. memset(&usbBusNotification, 0, sizeof(USB_BUS_NOTIFICATION));
  435. usbBusNotification.NotificationType = AcquireBusInfo;
  436. size = sizeof(USB_BUS_NOTIFICATION);
  437. res = WmiExecuteMethod(WmiHandle,
  438. InstanceName.c_str(),
  439. AcquireBusInfo,
  440. size,
  441. &usbBusNotification,
  442. &size,
  443. &usbBusNotification
  444. );
  445. if (res != ERROR_SUCCESS) {
  446. return NULL;
  447. }
  448. //
  449. // zero all the vars, get the controllers name
  450. //
  451. size = usbBusNotification.ControllerNameLength * sizeof(WCHAR)
  452. + sizeof(USB_ACQUIRE_INFO);
  453. usbAcquireInfo = (PUSB_ACQUIRE_INFO) LocalAlloc(LMEM_ZEROINIT, size);
  454. usbAcquireInfo->NotificationType = AcquireControllerName;
  455. usbAcquireInfo->TotalSize = size;
  456. res = WmiExecuteMethod(WmiHandle,
  457. InstanceName.c_str(),
  458. AcquireControllerName,
  459. size,
  460. usbAcquireInfo,
  461. &size,
  462. usbAcquireInfo
  463. );
  464. if (res != ERROR_SUCCESS) {
  465. usbAcquireInfo = (PUSB_ACQUIRE_INFO) LocalFree(usbAcquireInfo);
  466. }
  467. return usbAcquireInfo;
  468. }
  469. BOOL
  470. UsbPopup::OnDeviceChange(HWND hDlg,
  471. WPARAM wParam,
  472. PDEV_BROADCAST_HDR devHdr)
  473. {
  474. PDEV_BROADCAST_DEVICEINTERFACE devInterface =
  475. (PDEV_BROADCAST_DEVICEINTERFACE) devHdr;
  476. USBTRACE((_T("Device change notification, type %x."), wParam));
  477. switch (wParam) {
  478. case DBT_DEVICEARRIVAL:
  479. USBTRACE((_T("Device arrival.")));
  480. if (devHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
  481. USBTRACE((_T("Device: %s"),devInterface->dbcc_name));
  482. // New device arrival.
  483. // Compare the device description of this puppy to that of the one
  484. // that we have.
  485. //
  486. if (devInterface->dbcc_name == ConfigInfo->deviceDesc &&
  487. deviceState == DeviceDetachedError) {
  488. USBTRACE((_T("Device name match on arrival!")));
  489. //
  490. // The device has been reattached!
  491. //
  492. deviceState = DeviceReattached;
  493. Refresh();
  494. }
  495. }
  496. break;
  497. case DBT_DEVICEREMOVECOMPLETE:
  498. USBTRACE((_T("Device removal.")));
  499. if (devHdr->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
  500. USBTRACE((_T("Device: %s"),devInterface->dbcc_name));
  501. // New device arrival.
  502. // Compare the device description of this puppy to that of the one
  503. // that we have.
  504. //
  505. if (devInterface->dbcc_name == ConfigInfo->deviceDesc &&
  506. deviceState == DeviceAttachedError) {
  507. USBTRACE((_T("Device name match on remove!")));
  508. //
  509. // The device has been reattached!
  510. //
  511. deviceState = DeviceDetachedError;
  512. Refresh();
  513. }
  514. }
  515. break;
  516. }
  517. return TRUE;
  518. }