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