display the device location
[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 VOID
130 UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd)
131 {
132 PHWDEVINFO HwDevInfo;
133 HWND hBtnTroubleShoot, hBtnProperties;
134
135 hBtnTroubleShoot = GetDlgItem(hpd->hWnd,
136 IDC_TROUBLESHOOT);
137 hBtnProperties = GetDlgItem(hpd->hWnd,
138 IDC_PROPERTIES);
139
140 HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
141 if (HwDevInfo != NULL)
142 {
143 /* update static controls */
144 CONFIGRET cRet;
145 DWORD RegDataType;
146 ULONG DataSize;
147 WCHAR szBuffer[256];
148 LPWSTR szFormatted = NULL;
149
150 /* get the manufacturer string */
151 if (!SetupDiGetDeviceRegistryProperty(HwDevInfo->ClassDevInfo->hDevInfo,
152 &HwDevInfo->DevInfoData,
153 SPDRP_MFG,
154 &RegDataType,
155 (PBYTE)szBuffer,
156 sizeof(szBuffer),
157 NULL) ||
158 RegDataType != REG_SZ)
159 {
160 szBuffer[0] = L'\0';
161 }
162 /* FIXME - check string for NULL termination! */
163 if (LoadAndFormatString(hDllInstance,
164 IDS_MANUFACTURER,
165 &szFormatted,
166 szBuffer) != 0)
167 {
168 SetDlgItemText(hpd->hWnd,
169 IDC_MANUFACTURER,
170 szFormatted);
171 LocalFree((HLOCAL)szFormatted);
172 }
173
174 /* get the location string */
175 DataSize = sizeof(szBuffer);
176 cRet = CM_Get_DevNode_Registry_Property(HwDevInfo->DevInfoData.DevInst,
177 CM_DRP_LOCATION_INFORMATION,
178 &RegDataType,
179 szBuffer,
180 &DataSize,
181 0);
182 if (cRet != CR_SUCCESS ||
183 RegDataType != REG_SZ)
184 {
185 szBuffer[0] = L'\0';
186
187 if (cRet == CR_NO_SUCH_REGISTRY_KEY ||
188 cRet == CR_NO_SUCH_VALUE)
189 {
190 LoadString(hDllInstance,
191 IDS_UNKNOWN,
192 szBuffer,
193 sizeof(szBuffer) / sizeof(szBuffer[0]));
194 }
195 }
196 /* FIXME - check string for NULL termination! */
197
198 if (szBuffer[0] >= L'0' && szBuffer[0] <= L'9')
199 {
200 /* convert the string to an integer value and create a
201 formatted string */
202 unsigned long ulLocation = wcstoul(szBuffer,
203 NULL,
204 10);
205 if (LoadAndFormatString(hDllInstance,
206 IDS_LOCATIONSTR,
207 &szFormatted,
208 ulLocation,
209 szBuffer) != 0)
210 {
211 wcsncpy(szBuffer,
212 szFormatted,
213 (sizeof(szBuffer) / sizeof(szBuffer[0])) - 1);
214 szBuffer[(sizeof(szBuffer) / sizeof(szBuffer[0])) - 1] = L'\0';
215 LocalFree((HLOCAL)szFormatted);
216 }
217 }
218
219 if (LoadAndFormatString(hDllInstance,
220 IDS_LOCATION,
221 &szFormatted,
222 szBuffer) != 0)
223 {
224 SetDlgItemText(hpd->hWnd,
225 IDC_LOCATION,
226 szFormatted);
227 LocalFree((HLOCAL)szFormatted);
228 }
229
230 /* FIXME - Display the device status */
231 }
232 else
233 {
234 /* clear static controls */
235 SetDlgItemText(hpd->hWnd,
236 IDC_MANUFACTURER,
237 NULL);
238 SetDlgItemText(hpd->hWnd,
239 IDC_LOCATION,
240 NULL);
241 SetDlgItemText(hpd->hWnd,
242 IDC_STATUS,
243 NULL);
244 }
245
246 EnableWindow(hBtnTroubleShoot,
247 HwDevInfo != NULL);
248 EnableWindow(hBtnProperties,
249 HwDevInfo != NULL);
250 }
251
252 static VOID
253 FreeDevicesList(IN PHARDWARE_PAGE_DATA hpd)
254 {
255 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
256
257 ClassDevInfo = hpd->ClassDevInfo;
258 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
259
260 /* free the device info set handles */
261 while (ClassDevInfo != LastClassDevInfo)
262 {
263 if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE)
264 {
265 SetupDiDestroyDeviceInfoList(ClassDevInfo->hDevInfo);
266 }
267 ClassDevInfo->hDevInfo = NULL;
268 ClassDevInfo->ItemCount = 0;
269 ClassDevInfo->ImageIndex = 0;
270
271 if (ClassDevInfo->HwDevInfo != NULL)
272 {
273 HeapFree(GetProcessHeap(),
274 0,
275 ClassDevInfo->HwDevInfo);
276 ClassDevInfo->HwDevInfo = NULL;
277 }
278
279 ClassDevInfo++;
280 }
281 }
282
283
284 static VOID
285 BuildDevicesList(IN PHARDWARE_PAGE_DATA hpd)
286 {
287 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
288 SP_DEVINFO_DATA DevInfoData;
289
290 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
291
292 ClassDevInfo = hpd->ClassDevInfo;
293 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
294
295 while (ClassDevInfo != LastClassDevInfo)
296 {
297 ClassDevInfo->ImageIndex = -1;
298 ClassDevInfo->hDevInfo = SetupDiGetClassDevs(&ClassDevInfo->Guid,
299 NULL,
300 hpd->hWnd,
301 DIGCF_PRESENT);
302 if (ClassDevInfo->hDevInfo != INVALID_HANDLE_VALUE)
303 {
304 DWORD MemberIndex = 0;
305
306 SetupDiGetClassImageIndex(&hpd->ClassImageListData,
307 &ClassDevInfo->Guid,
308 &ClassDevInfo->ImageIndex);
309
310 while (SetupDiEnumDeviceInfo(ClassDevInfo->hDevInfo,
311 MemberIndex++,
312 &DevInfoData))
313 {
314 if (ClassDevInfo->HwDevInfo != NULL)
315 {
316 PHWDEVINFO HwNewDevInfo = HeapReAlloc(GetProcessHeap(),
317 0,
318 ClassDevInfo->HwDevInfo,
319 (ClassDevInfo->ItemCount + 1) *
320 sizeof(HWDEVINFO));
321 if (HwNewDevInfo != NULL)
322 {
323 ClassDevInfo->HwDevInfo = HwNewDevInfo;
324 }
325 else
326 {
327 DPRINT1("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
328 ClassDevInfo->ItemCount + 1);
329 break;
330 }
331 }
332 else
333 {
334 ClassDevInfo->HwDevInfo = HeapAlloc(GetProcessHeap(),
335 0,
336 sizeof(HWDEVINFO));
337 if (ClassDevInfo->HwDevInfo == NULL)
338 {
339 DPRINT1("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
340 break;
341 }
342 }
343
344 ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount].ClassDevInfo = ClassDevInfo;
345 ClassDevInfo->HwDevInfo[ClassDevInfo->ItemCount++].DevInfoData = DevInfoData;
346 }
347 }
348
349 ClassDevInfo++;
350 }
351 }
352
353
354 static VOID
355 FillDevicesList(IN PHARDWARE_PAGE_DATA hpd)
356 {
357 PHWCLASSDEVINFO ClassDevInfo, LastClassDevInfo;
358 PHWDEVINFO HwDevInfo, LastHwDevInfo;
359 WCHAR szBuffer[255];
360 INT ItemCount = 0;
361
362 BuildDevicesList(hpd);
363
364 ClassDevInfo = hpd->ClassDevInfo;
365 LastClassDevInfo = ClassDevInfo + hpd->NumberOfGuids;
366
367 while (ClassDevInfo != LastClassDevInfo)
368 {
369 if (ClassDevInfo->HwDevInfo != NULL)
370 {
371 HwDevInfo = ClassDevInfo->HwDevInfo;
372 LastHwDevInfo = HwDevInfo + ClassDevInfo->ItemCount;
373
374 while (HwDevInfo != LastHwDevInfo)
375 {
376 DWORD RegDataType;
377 INT iItem;
378 LVITEM li;
379
380 if ((SetupDiGetDeviceRegistryProperty(ClassDevInfo->hDevInfo,
381 &HwDevInfo->DevInfoData,
382 SPDRP_FRIENDLYNAME,
383 &RegDataType,
384 (PBYTE)szBuffer,
385 sizeof(szBuffer),
386 NULL) ||
387 SetupDiGetDeviceRegistryProperty(ClassDevInfo->hDevInfo,
388 &HwDevInfo->DevInfoData,
389 SPDRP_DEVICEDESC,
390 &RegDataType,
391 (PBYTE)szBuffer,
392 sizeof(szBuffer),
393 NULL)) &&
394 RegDataType == REG_SZ)
395 {
396 /* FIXME - check string for NULL termination! */
397
398 li.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT | LVIF_IMAGE;
399 li.iItem = ItemCount;
400 li.iSubItem = 0;
401 li.state = (ItemCount == 0 ? LVIS_SELECTED : 0);
402 li.stateMask = LVIS_SELECTED;
403 li.pszText = szBuffer;
404 li.iImage = ClassDevInfo->ImageIndex;
405 li.lParam = (LPARAM)HwDevInfo;
406
407 iItem = ListView_InsertItem(hpd->hWndDevList,
408 &li);
409 if (iItem != -1)
410 {
411 ItemCount++;
412
413 if (SetupDiGetClassDescription(&ClassDevInfo->Guid,
414 szBuffer,
415 sizeof(szBuffer) / sizeof(szBuffer[0]),
416 NULL))
417 {
418 li.mask = LVIF_TEXT;
419 li.iItem = iItem;
420 li.iSubItem = 1;
421
422 ListView_SetItem(hpd->hWndDevList,
423 &li);
424 }
425 }
426 }
427
428 HwDevInfo++;
429 }
430 }
431
432 ClassDevInfo++;
433 }
434
435 /* update the controls */
436 UpdateControlStates(hpd);
437 }
438
439
440 static LRESULT
441 CALLBACK
442 ParentSubWndProc(IN HWND hwnd,
443 IN UINT uMsg,
444 IN WPARAM wParam,
445 IN LPARAM lParam)
446 {
447 PHARDWARE_PAGE_DATA hpd;
448
449 hpd = (PHARDWARE_PAGE_DATA)GetProp(hwnd,
450 L"DevMgrSubClassInfo");
451 if (hpd != NULL)
452 {
453 if (uMsg == WM_SIZE)
454 {
455 /* resize the hardware page */
456 SetWindowPos(hpd->hWnd,
457 NULL,
458 0,
459 0,
460 LOWORD(lParam),
461 HIWORD(lParam),
462 SWP_NOZORDER);
463 }
464
465 /* pass the message the the old window proc */
466 return CallWindowProc(hpd->ParentOldWndProc,
467 hwnd,
468 uMsg,
469 wParam,
470 lParam);
471 }
472 else
473 {
474 /* this is not a good idea if the subclassed window was an ansi
475 window, but we failed finding out the previous window proc
476 so we can't use CallWindowProc. This should rarely - if ever -
477 happen. */
478
479 return DefWindowProc(hwnd,
480 uMsg,
481 wParam,
482 lParam);
483 }
484 }
485
486
487 static VOID
488 HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd,
489 IN INT cx,
490 IN INT cy)
491 {
492 HDWP dwp;
493 HWND hControl, hButton;
494 INT Width, x, y;
495 RECT rc, rcButton;
496 POINT pt = {0};
497 POINT ptMargin = {0};
498 POINT ptMarginGroup = {0};
499
500 /* use left margin of the IDC_DEVICES label as the right
501 margin of all controls outside the group box */
502 hControl = GetDlgItem(hpd->hWnd,
503 IDC_DEVICES);
504 GetWindowRect(hControl,
505 &rc);
506 MapWindowPoints(hControl,
507 hpd->hWnd,
508 &ptMargin,
509 1);
510
511 Width = cx - (2 * ptMargin.x);
512
513 if ((dwp = BeginDeferWindowPos(8)))
514 {
515 /* rc already has the window rect of IDC_DEVICES! */
516 if (!(dwp = DeferWindowPos(dwp,
517 hControl,
518 NULL,
519 0,
520 0,
521 Width,
522 rc.bottom - rc.top,
523 SWP_NOMOVE | SWP_NOZORDER)))
524 {
525 return;
526 }
527
528 /* resize the devices list view control */
529 GetWindowRect(hpd->hWndDevList,
530 &rc);
531 MapWindowPoints(hpd->hWndDevList,
532 hpd->hWnd,
533 &pt,
534 1);
535 y = pt.y + hpd->DevListViewHeight + ptMargin.y;
536 if (!(dwp = DeferWindowPos(dwp,
537 hpd->hWndDevList,
538 NULL,
539 0,
540 0,
541 Width,
542 hpd->DevListViewHeight,
543 SWP_NOMOVE | SWP_NOZORDER)))
544 {
545 return;
546 }
547
548 /* resize the group box control */
549 hControl = GetDlgItem(hpd->hWnd,
550 IDC_PROPERTIESGROUP);
551 GetWindowRect(hControl,
552 &rc);
553 if (!(dwp = DeferWindowPos(dwp,
554 hControl,
555 NULL,
556 ptMargin.x,
557 y,
558 Width,
559 cy - y - ptMargin.y,
560 SWP_NOZORDER)))
561 {
562 return;
563 }
564
565 /* use left margin of the IDC_MANUFACTURER label as the right
566 margin of all controls inside the group box */
567 hControl = GetDlgItem(hpd->hWnd,
568 IDC_MANUFACTURER);
569 GetWindowRect(hControl,
570 &rc);
571 MapWindowPoints(hControl,
572 hpd->hWnd,
573 &ptMarginGroup,
574 1);
575
576 ptMarginGroup.y = ptMargin.y * 2;
577 Width = cx - (2 * ptMarginGroup.x);
578 y += ptMarginGroup.y;
579 if (!(dwp = DeferWindowPos(dwp,
580 hControl,
581 NULL,
582 ptMarginGroup.x,
583 y,
584 Width,
585 rc.bottom - rc.top,
586 SWP_NOZORDER)))
587 {
588 return;
589 }
590 y += rc.bottom - rc.top + (ptMargin.y / 2);
591
592 /* resize the IDC_LOCATION label */
593 hControl = GetDlgItem(hpd->hWnd,
594 IDC_LOCATION);
595 GetWindowRect(hControl,
596 &rc);
597 if (!(dwp = DeferWindowPos(dwp,
598 hControl,
599 NULL,
600 ptMarginGroup.x,
601 y,
602 Width,
603 rc.bottom - rc.top,
604 SWP_NOZORDER)))
605 {
606 return;
607 }
608 y += rc.bottom - rc.top + (ptMargin.y / 2);
609
610 /* measure the size of the buttons */
611 hButton = GetDlgItem(hpd->hWnd,
612 IDC_PROPERTIES);
613 GetWindowRect(hButton,
614 &rcButton);
615
616 /* resize the IDC_STATUS label */
617 hControl = GetDlgItem(hpd->hWnd,
618 IDC_STATUS);
619 GetWindowRect(hControl,
620 &rc);
621 if (!(dwp = DeferWindowPos(dwp,
622 hControl,
623 NULL,
624 ptMarginGroup.x,
625 y,
626 Width,
627 cy - y - (3 * ptMargin.y) -
628 (rcButton.bottom - rcButton.top),
629 SWP_NOZORDER)))
630 {
631 return;
632 }
633
634 /* move the IDC_PROPERTIES button */
635 y = cy - (2 * ptMargin.y) - (rcButton.bottom - rcButton.top);
636 x = cx - ptMarginGroup.x - (rcButton.right - rcButton.left);
637 if (!(dwp = DeferWindowPos(dwp,
638 hButton,
639 NULL,
640 x,
641 y,
642 0,
643 0,
644 SWP_NOSIZE | SWP_NOZORDER)))
645 {
646 return;
647 }
648
649 /* move the IDC_TROUBLESHOOT button */
650 hButton = GetDlgItem(hpd->hWnd,
651 IDC_TROUBLESHOOT);
652 GetWindowRect(hButton,
653 &rcButton);
654 x -= (ptMargin.x / 2) + (rcButton.right - rcButton.left);
655 if (!(dwp = DeferWindowPos(dwp,
656 hButton,
657 NULL,
658 x,
659 y,
660 0,
661 0,
662 SWP_NOSIZE | SWP_NOZORDER)))
663 {
664 return;
665 }
666
667 EndDeferWindowPos(dwp);
668 }
669 }
670
671
672 static VOID
673 EnableTroubleShoot(PHARDWARE_PAGE_DATA hpd,
674 BOOL Enable)
675 {
676 HWND hBtnTroubleShoot = GetDlgItem(hpd->hWnd,
677 IDC_TROUBLESHOOT);
678
679 ShowWindow(hBtnTroubleShoot,
680 Enable ? SW_SHOW : SW_HIDE);
681 }
682
683
684 static INT_PTR
685 CALLBACK
686 HardwareDlgProc(IN HWND hwndDlg,
687 IN UINT uMsg,
688 IN WPARAM wParam,
689 IN LPARAM lParam)
690 {
691 PHARDWARE_PAGE_DATA hpd;
692
693 hpd = (PHARDWARE_PAGE_DATA)GetWindowLongPtr(hwndDlg,
694 DWL_USER);
695
696 if (hpd != NULL || uMsg == WM_INITDIALOG)
697 {
698 switch (uMsg)
699 {
700 case WM_NOTIFY:
701 {
702 NMHDR *pnmh = (NMHDR*)lParam;
703 if (pnmh->hwndFrom == hpd->hWndDevList)
704 {
705 switch (pnmh->code)
706 {
707 case LVN_ITEMCHANGED:
708 {
709 LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
710
711 if ((pnmv->uChanged & LVIF_STATE) &&
712 ((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) ||
713 (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))))
714 {
715 UpdateControlStates(hpd);
716 }
717 break;
718 }
719 }
720 }
721 break;
722 }
723
724 case WM_SIZE:
725 HardwareDlgResize(hpd,
726 (INT)LOWORD(lParam),
727 (INT)HIWORD(lParam));
728 break;
729
730 case WM_SETTEXT:
731 {
732 LPCWSTR szWndText = (LPCWSTR)lParam;
733 EnableTroubleShoot(hpd,
734 (szWndText != NULL && szWndText[0] != L'\0'));
735 break;
736 }
737
738 case WM_INITDIALOG:
739 {
740 hpd = (PHARDWARE_PAGE_DATA)lParam;
741 if (hpd != NULL)
742 {
743 HWND hWndParent;
744
745 hpd->hWnd = hwndDlg;
746 SetWindowLongPtr(hwndDlg,
747 DWL_USER,
748 (DWORD_PTR)hpd);
749
750 hpd->ClassImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
751
752 SetupDiGetClassImageList(&hpd->ClassImageListData);
753
754 /* calculate the size of the devices list view control */
755 hpd->hWndDevList = GetDlgItem(hwndDlg,
756 IDC_LV_DEVICES);
757 if (hpd->hWndDevList != NULL)
758 {
759 RECT rcClient;
760 GetClientRect(hpd->hWndDevList,
761 &rcClient);
762 hpd->DevListViewHeight = rcClient.bottom;
763
764 if (hpd->DisplayMode == HWPD_LARGELIST)
765 {
766 hpd->DevListViewHeight = (hpd->DevListViewHeight * 3) / 2;
767 }
768 }
769
770 /* subclass the parent window */
771 hWndParent = GetAncestor(hwndDlg,
772 GA_PARENT);
773 if (hWndParent != NULL)
774 {
775 RECT rcClient;
776
777 if (GetClientRect(hWndParent,
778 &rcClient) &&
779 SetWindowPos(hwndDlg,
780 NULL,
781 0,
782 0,
783 rcClient.right,
784 rcClient.bottom,
785 SWP_NOZORDER))
786 {
787 /* subclass the parent window. This is not safe
788 if the parent window belongs to another thread! */
789 hpd->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
790 GWLP_WNDPROC,
791 (LONG_PTR)ParentSubWndProc);
792
793 if (hpd->ParentOldWndProc != NULL &&
794 SetProp(hWndParent,
795 L"DevMgrSubClassInfo",
796 (HANDLE)hpd))
797 {
798 hpd->hWndParent = hWndParent;
799 }
800 }
801 }
802
803 /* initialize the devices list view control */
804 InitializeDevicesList(hpd);
805
806 /* fill the devices list view control */
807 FillDevicesList(hpd);
808
809 /* decide whether to show or hide the troubleshoot button */
810 EnableTroubleShoot(hpd,
811 GetWindowTextLength(hwndDlg) != 0);
812 }
813 break;
814 }
815
816 case WM_DESTROY:
817 {
818 /* free devices list */
819 FreeDevicesList(hpd);
820
821 /* restore the old window proc of the subclassed parent window */
822 if (hpd->hWndParent != NULL && hpd->ParentOldWndProc != NULL)
823 {
824 SetWindowLongPtr(hpd->hWndParent,
825 GWLP_WNDPROC,
826 (LONG_PTR)hpd->ParentOldWndProc);
827 }
828
829 if (hpd->ClassImageListData.ImageList != NULL)
830 {
831 SetupDiDestroyClassImageList(&hpd->ClassImageListData);
832 }
833
834 /* free the reference to comctl32 */
835 FreeLibrary(hpd->hComCtl32);
836 hpd->hComCtl32 = NULL;
837
838 /* free the allocated resources */
839 HeapFree(GetProcessHeap(),
840 0,
841 hpd);
842 break;
843 }
844 }
845 }
846
847 return FALSE;
848 }
849
850
851 /***************************************************************************
852 * NAME EXPORTED
853 * DeviceCreateHardwarePageEx
854 *
855 * DESCRIPTION
856 * Creates a hardware page
857 *
858 * ARGUMENTS
859 * hWndParent: Handle to the parent window
860 * lpGuids: An array of guids of devices that are to be listed
861 * uNumberOfGuids: Numbers of guids in the Guids array
862 * Unknown: Unknown parameter, see NOTEs
863 *
864 * RETURN VALUE
865 * Returns the handle of the hardware page window that has been created or
866 * NULL if it failed.
867 *
868 * REVISIONS
869 * 13-05-2005 first working version (Sebastian Gasiorek <zebasoftis@gmail.com>)
870 *
871 * TODO
872 * missing: device icon in list view, Troubleshoot button, device properties,
873 * status description,
874 * devices should be visible afer PSN_SETACTIVE message
875 *
876 */
877 HWND
878 WINAPI
879 DeviceCreateHardwarePageEx(IN HWND hWndParent,
880 IN LPGUID lpGuids,
881 IN UINT uNumberOfGuids,
882 IN HWPAGE_DISPLAYMODE DisplayMode)
883 {
884 PHARDWARE_PAGE_DATA hpd;
885 PINITCOMMONCONTROLS pInitCommonControls;
886
887 /* allocate the HARDWARE_PAGE_DATA structure. Make sure it is
888 zeroed because the initialization code assumes that in
889 failure cases! */
890 hpd = HeapAlloc(GetProcessHeap(),
891 HEAP_ZERO_MEMORY,
892 FIELD_OFFSET(HARDWARE_PAGE_DATA,
893 ClassDevInfo) +
894 (uNumberOfGuids * sizeof(HWCLASSDEVINFO)));
895 if (hpd != NULL)
896 {
897 HWND hWnd;
898 UINT i;
899
900 hpd->DisplayMode = ((DisplayMode > HWPD_MAX) ? HWPD_STANDARDLIST : DisplayMode);
901
902 /* initialize the HARDWARE_PAGE_DATA structure */
903 hpd->NumberOfGuids = uNumberOfGuids;
904 for (i = 0;
905 i < uNumberOfGuids;
906 i++)
907 {
908 hpd->ClassDevInfo[i].Guid = lpGuids[i];
909 }
910
911 /* load comctl32.dll dynamically */
912 hpd->hComCtl32 = LoadLibrary(TEXT("comctl32.dll"));
913 if (hpd->hComCtl32 == NULL)
914 {
915 goto Cleanup;
916 }
917
918 /* initialize the common controls */
919 pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hpd->hComCtl32,
920 "InitCommonControls");
921 if (pInitCommonControls == NULL)
922 {
923 goto Cleanup;
924 }
925 pInitCommonControls();
926
927 /* create the dialog */
928 hWnd = CreateDialogParam(hDllInstance,
929 MAKEINTRESOURCE(IDD_HARDWARE),
930 hWndParent,
931 HardwareDlgProc,
932 (LPARAM)hpd);
933 if (hWnd != NULL)
934 {
935 return hWnd;
936 }
937 else
938 {
939 Cleanup:
940 /* oops, something went wrong... */
941 if (hpd->hComCtl32 != NULL)
942 {
943 FreeLibrary(hpd->hComCtl32);
944 }
945
946 HeapFree(GetProcessHeap(),
947 0,
948 hpd);
949 }
950 }
951
952 return NULL;
953 }
954
955
956 /***************************************************************************
957 * NAME EXPORTED
958 * DeviceCreateHardwarePage
959 *
960 * DESCRIPTION
961 * Creates a hardware page
962 *
963 * ARGUMENTS
964 * hWndParent: Handle to the parent window
965 * lpGuid: Guid of the device
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 * REVISIONS
972 *
973 * NOTE
974 *
975 */
976 HWND
977 WINAPI
978 DeviceCreateHardwarePage(IN HWND hWndParent,
979 IN LPGUID lpGuid)
980 {
981 return DeviceCreateHardwarePageEx(hWndParent,
982 lpGuid,
983 1,
984 HWPD_LARGELIST);
985 }