1 /* 2 * ReactOS Device Manager Applet 3 * Copyright (C) 2004 - 2005 ReactOS Team 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 /* 20 * PROJECT: ReactOS devmgr.dll 21 * FILE: lib/devmgr/hwpage.c 22 * PURPOSE: ReactOS Device Manager 23 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com> 24 * UPDATE HISTORY: 25 * 04-04-2004 Created 26 */ 27 28 #include "precomp.h" 29 #include "properties.h" 30 #include "resource.h" 31 32 33 typedef struct _HWDEVINFO 34 { 35 struct _HWCLASSDEVINFO *ClassDevInfo; 36 SP_DEVINFO_DATA DevInfoData; 37 BOOL HideDevice; 38 } HWDEVINFO, *PHWDEVINFO; 39 40 typedef struct _HWCLASSDEVINFO 41 { 42 GUID Guid; 43 HDEVINFO hDevInfo; 44 INT ImageIndex; 45 INT ItemCount; 46 PHWDEVINFO HwDevInfo; 47 } HWCLASSDEVINFO, *PHWCLASSDEVINFO; 48 49 typedef struct _HARDWARE_PAGE_DATA 50 { 51 HWND hWnd; 52 HWND hWndDevList; 53 HINSTANCE hComCtl32; /* only save this to keep track of the references */ 54 INT DevListViewHeight; 55 SP_CLASSIMAGELIST_DATA ClassImageListData; 56 HWPAGE_DISPLAYMODE DisplayMode; 57 58 /* parent window subclass info */ 59 WNDPROC ParentOldWndProc; 60 HWND hWndParent; 61 62 UINT NumberOfGuids; 63 HWCLASSDEVINFO ClassDevInfo[1]; 64 /* struct may be dynamically expanded here! */ 65 } HARDWARE_PAGE_DATA, *PHARDWARE_PAGE_DATA; 66 67 #define CX_TYPECOLUMN_WIDTH 80 68 69 static VOID 70 InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd) 71 { 72 LVCOLUMN lvc; 73 RECT rcClient; 74 WCHAR szColName[255]; 75 int iCol = 0; 76 77 /* set the list view style */ 78 (void)ListView_SetExtendedListViewStyle(hpd->hWndDevList, 79 LVS_EX_FULLROWSELECT); 80 81 /* set the list view image list */ 82 if (hpd->ClassImageListData.ImageList != NULL) 83 { 84 (void)ListView_SetImageList(hpd->hWndDevList, 85 hpd->ClassImageListData.ImageList, 86 LVSIL_SMALL); 87 } 88 89 GetClientRect(hpd->hWndDevList, 90 &rcClient); 91 92 /* add the list view columns */ 93 lvc.mask = LVCF_TEXT | LVCF_WIDTH; 94 lvc.fmt = LVCFMT_LEFT; 95 lvc.pszText = szColName; 96 97 if (LoadString(hDllInstance, 98 IDS_NAME, 99 szColName, 100 sizeof(szColName) / sizeof(szColName[0]))) 101 { 102 lvc.cx = rcClient.right - CX_TYPECOLUMN_WIDTH - 103 GetSystemMetrics(SM_CXVSCROLL); 104 (void)ListView_InsertColumn(hpd->hWndDevList, 105 iCol++, 106 &lvc); 107 } 108 if (LoadString(hDllInstance, 109 IDS_TYPE, 110 szColName, 111 sizeof(szColName) / sizeof(szColName[0]))) 112 { 113 lvc.cx = CX_TYPECOLUMN_WIDTH; 114 (void)ListView_InsertColumn(hpd->hWndDevList, 115 iCol++, 116 &lvc); 117 } 118 } 119 120 121 static BOOL 122 DisplaySelectedDeviceProperties(IN PHARDWARE_PAGE_DATA hpd) 123 { 124 PHWDEVINFO HwDevInfo; 125 SP_DEVINFO_DATA DevInfoData; 126 BOOL Ret = FALSE; 127 128 HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList); 129 if (HwDevInfo != NULL) 130 { 131 /* make a copy of the SP_DEVINFO_DATA structure on the stack, it may 132 become invalid in case the devices are updated */ 133 DevInfoData = HwDevInfo->DevInfoData; 134 135 /* display the advanced properties */ 136 Ret = DisplayDeviceAdvancedProperties(hpd->hWnd, 137 NULL, 138 HwDevInfo->ClassDevInfo->hDevInfo, 139 &DevInfoData, 140 hpd->hComCtl32, 141 NULL, 142 0) != -1; 143 } 144 145 return Ret; 146 } 147 148 149 static VOID 150 UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd) 151 { 152 PHWDEVINFO HwDevInfo; 153 HWND hBtnTroubleShoot, hBtnProperties; 154 155 hBtnTroubleShoot = GetDlgItem(hpd->hWnd, 156 IDC_TROUBLESHOOT); 157 hBtnProperties = GetDlgItem(hpd->hWnd, 158 IDC_PROPERTIES); 159 160 HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList); 161 if (HwDevInfo != NULL) 162 { 163 /* update static controls */ 164 WCHAR szBuffer[256]; 165 LPWSTR szFormatted = NULL; 166 167 /* get the manufacturer string */ 168 if (GetDeviceManufacturerString(HwDevInfo->ClassDevInfo->hDevInfo, 169 &HwDevInfo->DevInfoData, 170 szBuffer, 171 sizeof(szBuffer) / sizeof(szBuffer[0])) && 172 LoadAndFormatString(hDllInstance, 173 IDS_MANUFACTURER, 174 &szFormatted, 175 szBuffer) != 0) 176 { 177 SetDlgItemText(hpd->hWnd, 178 IDC_MANUFACTURER, 179 szFormatted); 180 LocalFree((HLOCAL)szFormatted); 181 } 182 183 /* get the location string */ 184 if (GetDeviceLocationString(HwDevInfo->ClassDevInfo->hDevInfo, 185 &HwDevInfo->DevInfoData, 186 0, 187 szBuffer, 188 sizeof(szBuffer) / sizeof(szBuffer[0])) && 189 LoadAndFormatString(hDllInstance, 190 IDS_LOCATION, 191 &szFormatted, 192 szBuffer) != 0) 193 { 194 SetDlgItemText(hpd->hWnd, 195 IDC_LOCATION, 196 szFormatted); 197 LocalFree((HLOCAL)szFormatted); 198 } 199 200 if (GetDeviceStatusString(HwDevInfo->DevInfoData.DevInst, 201 NULL, 202 szBuffer, 203 sizeof(szBuffer) / sizeof(szBuffer[0])) && 204 LoadAndFormatString(hDllInstance, 205 IDS_STATUS, 206 &szFormatted, 207 szBuffer) != 0) 208 { 209 SetDlgItemText(hpd->hWnd, 210 IDC_STATUS, 211 szFormatted); 212 LocalFree((HLOCAL)szFormatted); 213 } 214 } 215 else 216 { 217 /* clear static controls */ 218 SetDlgItemText(hpd->hWnd, 219 IDC_MANUFACTURER, 220 NULL); 221 SetDlgItemText(hpd->hWnd, 222 IDC_LOCATION, 223 NULL); 224 SetDlgItemText(hpd->hWnd, 225 IDC_STATUS, 226 NULL); 227 } 228 229 EnableWindow(hBtnTroubleShoot, 230 HwDevInfo != NULL); 231 EnableWindow(hBtnProperties, 232 HwDevInfo != NULL); 233 } 234 235 236 static VOID 237 FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd) 238 { 239 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo; 240 241 ClassDevInfo = hpd->ClassDevInfo; 242 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids; 243 244 /* free the device info set handles and structures */ 245 while (ClassDevInfo != LastClassDevInfo) 246 { 247 if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE) 248 { 249 SetupDiDestroyDeviceInfoList(ClassDevInfo->hDevInfo); 250 ClassDevInfo->hDevInfo = INVALID_HANDLE_VALUE; 251 } 252 253 ClassDevInfo->ItemCount = 0; 254 ClassDevInfo->ImageIndex = 0; 255 256 if (ClassDevInfo->HwDevInfo != NULL) 257 { 258 HeapFree(GetProcessHeap(), 259 0, 260 ClassDevInfo->HwDevInfo); 261 ClassDevInfo->HwDevInfo = NULL; 262 } 263 264 ClassDevInfo++; 265 } 266 } 267 268 269 static VOID 270 BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd) 271 { 272 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo; 273 SP_DEVINFO_DATA DevInfoData; 274 275 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); 276 277 ClassDevInfo = hpd->ClassDevInfo; 278 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids; 279 280 while (ClassDevInfo != LastClassDevInfo) 281 { 282 ClassDevInfo->ImageIndex = -1; 283 284 /* open a class device handle for the GUID we're processing */ 285 ClassDevInfo->hDevInfo = SetupDiGetClassDevs(&ClassDevInfo->Guid, 286 NULL, 287 hpd->hWnd, 288 DIGCF_PRESENT | DIGCF_PROFILE); 289 if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE) 290 { 291 DWORD MemberIndex = 0; 292 293 SetupDiGetClassImageIndex(&hpd->ClassImageListData, 294 &ClassDevInfo->Guid, 295 &ClassDevInfo->ImageIndex); 296 297 /* enumerate all devices in the class */ 298 while (SetupDiEnumDeviceInfo(ClassDevInfo->hDevInfo, 299 MemberIndex++, 300 &DevInfoData)) 301 { 302 BOOL HideDevice = FALSE; 303 304 if (ClassDevInfo->HwDevInfo != NULL) 305 { 306 PHWDEVINFO HwNewDevInfo = (PHWDEVINFO)HeapReAlloc(GetProcessHeap(), 307 0, 308 ClassDevInfo->HwDevInfo, 309 (ClassDevInfo->ItemCount + 1) * 310 sizeof(HWDEVINFO)); 311 if (HwNewDevInfo != NULL) 312 { 313 ClassDevInfo->HwDevInfo = HwNewDevInfo; 314 } 315 else 316 { 317 ERR("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n", 318 ClassDevInfo->ItemCount + 1); 319 break; 320 } 321 } 322 else 323 { 324 ClassDevInfo->HwDevInfo = (PHWDEVINFO)HeapAlloc(GetProcessHeap(), 325 0, 326 sizeof(HWDEVINFO)); 327 if (ClassDevInfo->HwDevInfo == NULL) 328 { 329 ERR("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n"); 330 break; 331 } 332 } 333 334 /* Find out if the device should be hidden by default */ 335 IsDeviceHidden(DevInfoData.DevInst, 336 NULL, 337 &HideDevice); 338 339 /* save all information for the current device */ 340 ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].ClassDevInfo = ClassDevInfo; 341 ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].DevInfoData = DevInfoData; 342 ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount++].HideDevice = HideDevice; 343 } 344 } 345 346 ClassDevInfo++; 347 } 348 } 349 350 351 static BOOL 352 DeviceIdMatch(IN HDEVINFO DeviceInfoSet, 353 IN PSP_DEVINFO_DATA DeviceInfoData, 354 IN LPCWSTR lpDeviceId) 355 { 356 DWORD DevIdLen; 357 LPWSTR lpQueriedDeviceId; 358 BOOL Ret = FALSE; 359 360 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet, 361 DeviceInfoData, 362 NULL, 363 0, 364 &DevIdLen) && 365 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 366 { 367 if (DevIdLen == wcslen(lpDeviceId) + 1) 368 { 369 lpQueriedDeviceId = (LPWSTR)HeapAlloc(GetProcessHeap(), 370 0, 371 DevIdLen * sizeof(WCHAR)); 372 if (lpQueriedDeviceId != NULL) 373 { 374 if (SetupDiGetDeviceInstanceId(DeviceInfoSet, 375 DeviceInfoData, 376 lpQueriedDeviceId, 377 DevIdLen, 378 NULL)) 379 { 380 Ret = (wcscmp(lpDeviceId, 381 lpQueriedDeviceId) == 0); 382 } 383 384 HeapFree(GetProcessHeap(), 385 0, 386 lpQueriedDeviceId); 387 } 388 } 389 } 390 391 return Ret; 392 } 393 394 395 static VOID 396 FillDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd, 397 IN LPCWSTR lpSelectDeviceId OPTIONAL, 398 IN GUID *SelectedClassGuid OPTIONAL) 399 { 400 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo; 401 PHWDEVINFO HwDevInfo, LastHwDevInfo; 402 WCHAR szBuffer[255]; 403 BOOL SelectedInClass; 404 INT ItemCount = 0; 405 406 BuildDevicesList(hpd); 407 408 ClassDevInfo = hpd->ClassDevInfo; 409 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids; 410 411 while (ClassDevInfo != LastClassDevInfo) 412 { 413 if (ClassDevInfo->HwDevInfo != NULL) 414 { 415 HwDevInfo = ClassDevInfo->HwDevInfo; 416 LastHwDevInfo = HwDevInfo + ClassDevInfo->ItemCount; 417 418 SelectedInClass = (SelectedClassGuid != NULL && 419 IsEqualGUID(*SelectedClassGuid, 420 ClassDevInfo->Guid)); 421 while (HwDevInfo != LastHwDevInfo) 422 { 423 INT iItem; 424 LVITEM li = {0}; 425 426 /* get the device name */ 427 if (!HwDevInfo->HideDevice && 428 GetDeviceDescriptionString(ClassDevInfo->hDevInfo, 429 &HwDevInfo->DevInfoData, 430 szBuffer, 431 sizeof(szBuffer) / sizeof(szBuffer[0]))) 432 { 433 li.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT | LVIF_IMAGE; 434 li.iItem = ItemCount; 435 if ((ItemCount == 0 && lpSelectDeviceId == NULL) || 436 (SelectedInClass && 437 DeviceIdMatch(ClassDevInfo->hDevInfo, 438 &HwDevInfo->DevInfoData, 439 lpSelectDeviceId))) 440 { 441 li.state = LVIS_SELECTED; 442 } 443 li.stateMask = LVIS_SELECTED; 444 li.pszText = szBuffer; 445 li.iImage = ClassDevInfo->ImageIndex; 446 li.lParam = (LPARAM)HwDevInfo; 447 448 iItem = ListView_InsertItem(hpd->hWndDevList, 449 &li); 450 if (iItem != -1) 451 { 452 ItemCount++; 453 454 /* get the device type for the second column */ 455 if (GetDeviceTypeString(&HwDevInfo->DevInfoData, 456 szBuffer, 457 sizeof(szBuffer) / sizeof(szBuffer[0]))) 458 { 459 li.mask = LVIF_TEXT; 460 li.iItem = iItem; 461 li.iSubItem = 1; 462 463 (void)ListView_SetItem(hpd->hWndDevList, 464 &li); 465 } 466 } 467 } 468 469 HwDevInfo++; 470 } 471 } 472 473 ClassDevInfo++; 474 } 475 476 /* update the controls */ 477 UpdateControlStates(hpd); 478 } 479 480 481 static VOID 482 UpdateDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd) 483 { 484 PHWDEVINFO HwDevInfo; 485 GUID SelectedClassGuid = {0}; 486 LPWSTR lpDeviceId = NULL; 487 488 /* if a device currently is selected, remember the device id so we can 489 select the device after the update if still present */ 490 HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList); 491 if (HwDevInfo != NULL) 492 { 493 DWORD DevIdLen; 494 if (!SetupDiGetDeviceInstanceId(HwDevInfo->ClassDevInfo->hDevInfo, 495 &HwDevInfo->DevInfoData, 496 NULL, 497 0, 498 &DevIdLen) && 499 GetLastError() == ERROR_INSUFFICIENT_BUFFER) 500 { 501 SelectedClassGuid = HwDevInfo->DevInfoData.ClassGuid; 502 lpDeviceId = (LPWSTR)HeapAlloc(GetProcessHeap(), 503 0, 504 DevIdLen * sizeof(WCHAR)); 505 if (lpDeviceId != NULL && 506 !SetupDiGetDeviceInstanceId(HwDevInfo->ClassDevInfo->hDevInfo, 507 &HwDevInfo->DevInfoData, 508 lpDeviceId, 509 DevIdLen, 510 NULL)) 511 { 512 HeapFree(GetProcessHeap(), 513 0, 514 lpDeviceId); 515 lpDeviceId = NULL; 516 } 517 } 518 } 519 520 /* clear the devices list view control */ 521 (void)ListView_DeleteAllItems(hpd->hWndDevList); 522 523 /* free the device list */ 524 FreeDevicesList(hpd); 525 526 /* build rebuild the device list and fill the list box again */ 527 FillDevicesListViewControl(hpd, 528 lpDeviceId, 529 (lpDeviceId != NULL ? 530 &SelectedClassGuid : 531 NULL)); 532 533 if (lpDeviceId != NULL) 534 { 535 HeapFree(GetProcessHeap(), 536 0, 537 lpDeviceId); 538 } 539 } 540 541 542 static LRESULT 543 CALLBACK 544 ParentSubWndProc(IN HWND hwnd, 545 IN UINT uMsg, 546 IN WPARAM wParam, 547 IN LPARAM lParam) 548 { 549 PHARDWARE_PAGE_DATA hpd; 550 551 hpd = (PHARDWARE_PAGE_DATA)GetProp(hwnd, 552 L"DevMgrSubClassInfo"); 553 if (hpd != NULL) 554 { 555 if (uMsg == WM_SIZE) 556 { 557 /* resize the hardware page */ 558 SetWindowPos(hpd->hWnd, 559 NULL, 560 0, 561 0, 562 LOWORD(lParam), 563 HIWORD(lParam), 564 SWP_NOZORDER); 565 } 566 else if (uMsg == WM_DEVICECHANGE && IsWindowVisible(hpd->hWnd)) 567 { 568 /* forward a WM_DEVICECHANGE message to the hardware 569 page which wouldn't get the message itself as it is 570 a child window */ 571 SendMessage(hpd->hWnd, 572 WM_DEVICECHANGE, 573 wParam, 574 lParam); 575 } 576 577 /* pass the message the the old window proc */ 578 return CallWindowProc(hpd->ParentOldWndProc, 579 hwnd, 580 uMsg, 581 wParam, 582 lParam); 583 } 584 else 585 { 586 /* this is not a good idea if the subclassed window was an ansi 587 window, but we failed finding out the previous window proc 588 so we can't use CallWindowProc. This should rarely - if ever - 589 happen. */ 590 591 return DefWindowProc(hwnd, 592 uMsg, 593 wParam, 594 lParam); 595 } 596 } 597 598 599 static VOID 600 HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd, 601 IN INT cx, 602 IN INT cy) 603 { 604 HDWP dwp; 605 HWND hControl, hButton; 606 INT Width, x, y; 607 RECT rc, rcButton; 608 POINT pt = {0}; 609 POINT ptMargin = {0}; 610 POINT ptMarginGroup = {0}; 611 612 /* use left margin of the IDC_DEVICES label as the right 613 margin of all controls outside the group box */ 614 hControl = GetDlgItem(hpd->hWnd, 615 IDC_DEVICES); 616 GetWindowRect(hControl, 617 &rc); 618 MapWindowPoints(hControl, 619 hpd->hWnd, 620 &ptMargin, 621 1); 622 623 Width = cx - (2 * ptMargin.x); 624 625 if ((dwp = BeginDeferWindowPos(8))) 626 { 627 /* rc already has the window rect of IDC_DEVICES! */ 628 if (!(dwp = DeferWindowPos(dwp, 629 hControl, 630 NULL, 631 0, 632 0, 633 Width, 634 rc.bottom - rc.top, 635 SWP_NOMOVE | SWP_NOZORDER))) 636 { 637 return; 638 } 639 640 /* resize the devices list view control */ 641 GetWindowRect(hpd->hWndDevList, 642 &rc); 643 MapWindowPoints(hpd->hWndDevList, 644 hpd->hWnd, 645 &pt, 646 1); 647 y = pt.y + hpd->DevListViewHeight + ptMargin.y; 648 if (!(dwp = DeferWindowPos(dwp, 649 hpd->hWndDevList, 650 NULL, 651 0, 652 0, 653 Width, 654 hpd->DevListViewHeight, 655 SWP_NOMOVE | SWP_NOZORDER))) 656 { 657 return; 658 } 659 660 /* resize the group box control */ 661 hControl = GetDlgItem(hpd->hWnd, 662 IDC_PROPERTIESGROUP); 663 GetWindowRect(hControl, 664 &rc); 665 if (!(dwp = DeferWindowPos(dwp, 666 hControl, 667 NULL, 668 ptMargin.x, 669 y, 670 Width, 671 cy - y - ptMargin.y, 672 SWP_NOZORDER))) 673 { 674 return; 675 } 676 677 /* use left margin of the IDC_MANUFACTURER label as the right 678 margin of all controls inside the group box */ 679 hControl = GetDlgItem(hpd->hWnd, 680 IDC_MANUFACTURER); 681 GetWindowRect(hControl, 682 &rc); 683 MapWindowPoints(hControl, 684 hpd->hWnd, 685 &ptMarginGroup, 686 1); 687 688 ptMarginGroup.y = ptMargin.y * 2; 689 Width = cx - (2 * ptMarginGroup.x); 690 y += ptMarginGroup.y; 691 if (!(dwp = DeferWindowPos(dwp, 692 hControl, 693 NULL, 694 ptMarginGroup.x, 695 y, 696 Width, 697 rc.bottom - rc.top, 698 SWP_NOZORDER))) 699 { 700 return; 701 } 702 y += rc.bottom - rc.top + (ptMargin.y / 2); 703 704 /* resize the IDC_LOCATION label */ 705 hControl = GetDlgItem(hpd->hWnd, 706 IDC_LOCATION); 707 GetWindowRect(hControl, 708 &rc); 709 if (!(dwp = DeferWindowPos(dwp, 710 hControl, 711 NULL, 712 ptMarginGroup.x, 713 y, 714 Width, 715 rc.bottom - rc.top, 716 SWP_NOZORDER))) 717 { 718 return; 719 } 720 y += rc.bottom - rc.top + (ptMargin.y / 2); 721 722 /* measure the size of the buttons */ 723 hButton = GetDlgItem(hpd->hWnd, 724 IDC_PROPERTIES); 725 GetWindowRect(hButton, 726 &rcButton); 727 728 /* resize the IDC_STATUS label */ 729 hControl = GetDlgItem(hpd->hWnd, 730 IDC_STATUS); 731 GetWindowRect(hControl, 732 &rc); 733 if (!(dwp = DeferWindowPos(dwp, 734 hControl, 735 NULL, 736 ptMarginGroup.x, 737 y, 738 Width, 739 cy - y - (3 * ptMargin.y) - 740 (rcButton.bottom - rcButton.top), 741 SWP_NOZORDER))) 742 { 743 return; 744 } 745 746 /* move the IDC_PROPERTIES button */ 747 y = cy - (2 * ptMargin.y) - (rcButton.bottom - rcButton.top); 748 x = cx - ptMarginGroup.x - (rcButton.right - rcButton.left); 749 if (!(dwp = DeferWindowPos(dwp, 750 hButton, 751 NULL, 752 x, 753 y, 754 0, 755 0, 756 SWP_NOSIZE | SWP_NOZORDER))) 757 { 758 return; 759 } 760 761 /* move the IDC_TROUBLESHOOT button */ 762 hButton = GetDlgItem(hpd->hWnd, 763 IDC_TROUBLESHOOT); 764 GetWindowRect(hButton, 765 &rcButton); 766 x -= (ptMargin.x / 2) + (rcButton.right - rcButton.left); 767 if (!(dwp = DeferWindowPos(dwp, 768 hButton, 769 NULL, 770 x, 771 y, 772 0, 773 0, 774 SWP_NOSIZE | SWP_NOZORDER))) 775 { 776 return; 777 } 778 779 EndDeferWindowPos(dwp); 780 } 781 } 782 783 784 static VOID 785 EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd, 786 BOOL Enable) 787 { 788 HWND hBtnTroubleShoot = GetDlgItem(hpd->hWnd, 789 IDC_TROUBLESHOOT); 790 791 ShowWindow(hBtnTroubleShoot, 792 Enable ? SW_SHOW : SW_HIDE); 793 } 794 795 796 static INT_PTR 797 CALLBACK 798 HardwareDlgProc(IN HWND hwndDlg, 799 IN UINT uMsg, 800 IN WPARAM wParam, 801 IN LPARAM lParam) 802 { 803 PHARDWARE_PAGE_DATA hpd; 804 INT_PTR Ret = FALSE; 805 806 hpd = (PHARDWARE_PAGE_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER); 807 808 if (hpd != NULL || uMsg == WM_INITDIALOG) 809 { 810 switch (uMsg) 811 { 812 case WM_NOTIFY: 813 { 814 NMHDR *pnmh = (NMHDR*)lParam; 815 if (pnmh->hwndFrom == hpd->hWndDevList) 816 { 817 switch (pnmh->code) 818 { 819 case LVN_ITEMCHANGED: 820 { 821 LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam; 822 823 if ((pnmv->uChanged & LVIF_STATE) && 824 ((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) || 825 (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED)))) 826 { 827 UpdateControlStates(hpd); 828 } 829 break; 830 } 831 832 case NM_DBLCLK: 833 { 834 DisplaySelectedDeviceProperties(hpd); 835 break; 836 } 837 } 838 } 839 break; 840 } 841 842 case WM_COMMAND: 843 { 844 switch (LOWORD(wParam)) 845 { 846 case IDC_TROUBLESHOOT: 847 { 848 /* FIXME - start the help using the command in the window text */ 849 break; 850 } 851 852 case IDC_PROPERTIES: 853 { 854 DisplaySelectedDeviceProperties(hpd); 855 break; 856 } 857 } 858 break; 859 } 860 861 case WM_SIZE: 862 HardwareDlgResize(hpd, 863 (INT)LOWORD(lParam), 864 (INT)HIWORD(lParam)); 865 break; 866 867 case WM_SETTEXT: 868 { 869 LPCWSTR szWndText = (LPCWSTR)lParam; 870 EnableTroubleShoot(hpd, 871 (szWndText != NULL && szWndText[0] != L'\0')); 872 break; 873 } 874 875 case WM_DEVICECHANGE: 876 { 877 /* FIXME - don't call UpdateDevicesListViewControl for all events */ 878 UpdateDevicesListViewControl(hpd); 879 Ret = TRUE; 880 break; 881 } 882 883 case WM_INITDIALOG: 884 { 885 hpd = (PHARDWARE_PAGE_DATA)lParam; 886 if (hpd != NULL) 887 { 888 HWND hWndParent; 889 890 hpd->hWnd = hwndDlg; 891 SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)hpd); 892 893 hpd->ClassImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA); 894 895 SetupDiGetClassImageList(&hpd->ClassImageListData); 896 897 /* calculate the size of the devices list view control */ 898 hpd->hWndDevList = GetDlgItem(hwndDlg, 899 IDC_LV_DEVICES); 900 if (hpd->hWndDevList != NULL) 901 { 902 RECT rcClient; 903 GetClientRect(hpd->hWndDevList, 904 &rcClient); 905 hpd->DevListViewHeight = rcClient.bottom; 906 907 if (hpd->DisplayMode == HWPD_LARGELIST) 908 { 909 hpd->DevListViewHeight = (hpd->DevListViewHeight * 3) / 2; 910 } 911 } 912 913 /* subclass the parent window */ 914 hWndParent = GetAncestor(hwndDlg, 915 GA_PARENT); 916 if (hWndParent != NULL) 917 { 918 RECT rcClient; 919 920 if (GetClientRect(hWndParent, 921 &rcClient) && 922 SetWindowPos(hwndDlg, 923 NULL, 924 0, 925 0, 926 rcClient.right, 927 rcClient.bottom, 928 SWP_NOZORDER)) 929 { 930 /* subclass the parent window. This is not safe 931 if the parent window belongs to another thread! */ 932 hpd->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent, 933 GWLP_WNDPROC, 934 (LONG_PTR)ParentSubWndProc); 935 936 if (hpd->ParentOldWndProc != NULL && 937 SetProp(hWndParent, 938 L"DevMgrSubClassInfo", 939 (HANDLE)hpd)) 940 { 941 hpd->hWndParent = hWndParent; 942 } 943 } 944 } 945 946 /* initialize the devices list view control */ 947 InitializeDevicesList(hpd); 948 949 /* fill the devices list view control */ 950 FillDevicesListViewControl(hpd, 951 NULL, 952 NULL); 953 954 /* decide whether to show or hide the troubleshoot button */ 955 EnableTroubleShoot(hpd, 956 GetWindowTextLength(hwndDlg) != 0); 957 } 958 Ret = TRUE; 959 break; 960 } 961 962 case WM_DESTROY: 963 { 964 /* zero hpd pointer in window data, because it can be used later (WM_DESTROY has not to be last message) */ 965 SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR)NULL); 966 967 /* free devices list */ 968 FreeDevicesList(hpd); 969 970 /* restore the old window proc of the subclassed parent window */ 971 if (hpd->hWndParent != NULL && hpd->ParentOldWndProc != NULL) 972 { 973 SetWindowLongPtr(hpd->hWndParent, 974 GWLP_WNDPROC, 975 (LONG_PTR)hpd->ParentOldWndProc); 976 } 977 978 if (hpd->ClassImageListData.ImageList != NULL) 979 { 980 SetupDiDestroyClassImageList(&hpd->ClassImageListData); 981 } 982 983 /* free the reference to comctl32 */ 984 FreeLibrary(hpd->hComCtl32); 985 hpd->hComCtl32 = NULL; 986 987 /* free the allocated resources */ 988 HeapFree(GetProcessHeap(), 989 0, 990 hpd); 991 break; 992 } 993 } 994 } 995 996 return Ret; 997 } 998 999 1000 /*************************************************************************** 1001 * NAME EXPORTED 1002 * DeviceCreateHardwarePageEx 1003 * 1004 * DESCRIPTION 1005 * Creates a hardware page 1006 * 1007 * ARGUMENTS 1008 * hWndParent: Handle to the parent window 1009 * lpGuids: An array of guids of devices that are to be listed 1010 * uNumberOfGuids: Numbers of guids in the Guids array 1011 * DisplayMode: Sets the size of the device list view control 1012 * 1013 * RETURN VALUE 1014 * Returns the handle of the hardware page window that has been created or 1015 * NULL if it failed. 1016 * 1017 * @implemented 1018 */ 1019 HWND 1020 WINAPI 1021 DeviceCreateHardwarePageEx(IN HWND hWndParent, 1022 IN LPGUID lpGuids, 1023 IN UINT uNumberOfGuids, 1024 IN HWPAGE_DISPLAYMODE DisplayMode) 1025 { 1026 PHARDWARE_PAGE_DATA hpd; 1027 1028 /* allocate the HARDWARE_PAGE_DATA structure. Make sure it is 1029 zeroed because the initialization code assumes that in 1030 failure cases! */ 1031 hpd = (PHARDWARE_PAGE_DATA)HeapAlloc(GetProcessHeap(), 1032 HEAP_ZERO_MEMORY, 1033 FIELD_OFFSET(HARDWARE_PAGE_DATA, 1034 ClassDevInfo[uNumberOfGuids])); 1035 if (hpd != NULL) 1036 { 1037 HWND hWnd; 1038 UINT i; 1039 1040 hpd->DisplayMode = ((DisplayMode > HWPD_MAX) ? HWPD_STANDARDLIST : DisplayMode); 1041 1042 /* initialize the HARDWARE_PAGE_DATA structure */ 1043 hpd->NumberOfGuids = uNumberOfGuids; 1044 for (i = 0; 1045 i < uNumberOfGuids; 1046 i++) 1047 { 1048 hpd->ClassDevInfo[i].hDevInfo = INVALID_HANDLE_VALUE; 1049 hpd->ClassDevInfo[i].Guid = lpGuids[i]; 1050 } 1051 1052 /* load comctl32.dll dynamically */ 1053 hpd->hComCtl32 = LoadAndInitComctl32(); 1054 if (hpd->hComCtl32 == NULL) 1055 { 1056 goto Cleanup; 1057 } 1058 1059 /* create the dialog */ 1060 hWnd = CreateDialogParam(hDllInstance, 1061 MAKEINTRESOURCE(IDD_HARDWARE), 1062 hWndParent, 1063 HardwareDlgProc, 1064 (LPARAM)hpd); 1065 if (hWnd != NULL) 1066 { 1067 return hWnd; 1068 } 1069 else 1070 { 1071 Cleanup: 1072 /* oops, something went wrong... */ 1073 if (hpd->hComCtl32 != NULL) 1074 { 1075 FreeLibrary(hpd->hComCtl32); 1076 } 1077 1078 HeapFree(GetProcessHeap(), 1079 0, 1080 hpd); 1081 } 1082 } 1083 1084 return NULL; 1085 } 1086 1087 1088 /*************************************************************************** 1089 * NAME EXPORTED 1090 * DeviceCreateHardwarePage 1091 * 1092 * DESCRIPTION 1093 * Creates a hardware page 1094 * 1095 * ARGUMENTS 1096 * hWndParent: Handle to the parent window 1097 * lpGuid: Guid of the device 1098 * 1099 * RETURN VALUE 1100 * Returns the handle of the hardware page window that has been created or 1101 * NULL if it failed. 1102 * 1103 * @implemented 1104 */ 1105 HWND 1106 WINAPI 1107 DeviceCreateHardwarePage(IN HWND hWndParent, 1108 IN LPGUID lpGuid) 1109 { 1110 return DeviceCreateHardwarePageEx(hWndParent, 1111 lpGuid, 1112 1, 1113 HWPD_LARGELIST); 1114 } 1115