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