xref: /reactos/dll/win32/devmgr/properties/hwpage.cpp (revision bedc16d4)
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
InitializeDevicesList(IN PHARDWARE_PAGE_DATA hpd)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
DisplaySelectedDeviceProperties(IN PHARDWARE_PAGE_DATA hpd)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
UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd)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
FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd)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
BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd)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
DeviceIdMatch(IN HDEVINFO DeviceInfoSet,IN PSP_DEVINFO_DATA DeviceInfoData,IN LPCWSTR lpDeviceId)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
FillDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd,IN LPCWSTR lpSelectDeviceId OPTIONAL,IN GUID * SelectedClassGuid OPTIONAL)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
UpdateDevicesListViewControl(IN PHARDWARE_PAGE_DATA hpd)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
ParentSubWndProc(IN HWND hwnd,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)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
HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd,IN INT cx,IN INT cy)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
EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd,BOOL Enable)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
HardwareDlgProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)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
DeviceCreateHardwarePageEx(IN HWND hWndParent,IN LPGUID lpGuids,IN UINT uNumberOfGuids,IN HWPAGE_DISPLAYMODE DisplayMode)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                                          DYNAMIC_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
DeviceCreateHardwarePage(IN HWND hWndParent,IN LPGUID lpGuid)1107 DeviceCreateHardwarePage(IN HWND hWndParent,
1108                          IN LPGUID lpGuid)
1109 {
1110     return DeviceCreateHardwarePageEx(hWndParent,
1111                                       lpGuid,
1112                                       1,
1113                                       HWPD_LARGELIST);
1114 }
1115