- add a (very incomplete) devguid.h
[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 ItemCount;
53 PHWDEVINFO HwDevInfo;
54 } HWCLASSDEVINFO, *PHWCLASSDEVINFO;
55
56 typedef struct _HARDWARE_PAGE_DATA
57 {
58 HWND hWnd;
59 HWND hWndDevList;
60 HINSTANCE hComCtl32; /* only save this to keep track of the references */
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 VOID
128 UpdateControlStates(IN PHARDWARE_PAGE_DATA hpd)
129 {
130 PHWDEVINFO HwDevInfo;
131
132 HwDevInfo = (PHWDEVINFO)ListViewGetSelectedItemData(hpd->hWndDevList);
133 if (HwDevInfo != NULL)
134 {
135 /* FIXME - update static controls and enable buttons */
136 }
137 else
138 {
139 /* FIXME - clear static controls and disable buttons */
140 }
141 }
142
143
144 static VOID
145 FillDevicesList(IN PHARDWARE_PAGE_DATA hpd)
146 {
147 PHWCLASSDEVINFO DevInfo, LastDevInfo;
148 SP_DEVINFO_DATA DevInfoData;
149 WCHAR szBuffer[255];
150 INT ItemCount = 0;
151
152 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
153
154 DevInfo = hpd->ClassDevInfo;
155 LastDevInfo = DevInfo + hpd->NumberOfGuids;
156
157 while (DevInfo != LastDevInfo)
158 {
159 INT ImageIndex = -1;
160
161 DevInfo->hDevInfo = SetupDiGetClassDevs(&DevInfo->Guid,
162 NULL,
163 hpd->hWnd,
164 DIGCF_PRESENT);
165 if (DevInfo->hDevInfo != INVALID_HANDLE_VALUE)
166 {
167 LVITEM li;
168 DWORD MemberIndex = 0;
169
170 SetupDiGetClassImageIndex(&hpd->ClassImageListData,
171 &DevInfo->Guid,
172 &ImageIndex);
173
174 while (SetupDiEnumDeviceInfo(DevInfo->hDevInfo,
175 MemberIndex++,
176 &DevInfoData))
177 {
178 DWORD RegDataType;
179 INT iItem;
180
181 if (DevInfo->HwDevInfo != NULL)
182 {
183 PHWDEVINFO HwNewDevInfo = HeapReAlloc(GetProcessHeap(),
184 0,
185 DevInfo->HwDevInfo,
186 (DevInfo->ItemCount + 1) *
187 sizeof(HWDEVINFO));
188 if (HwNewDevInfo != NULL)
189 {
190 DevInfo->HwDevInfo = HwNewDevInfo;
191 DevInfo->HwDevInfo[DevInfo->ItemCount].ClassDevInfo = DevInfo;
192 DevInfo->HwDevInfo[DevInfo->ItemCount++].DevInfoData = DevInfoData;
193 }
194 else
195 {
196 DPRINT1("Unable to allocate memory for %d SP_DEVINFO_DATA structures!\n",
197 DevInfo->ItemCount + 1);
198 break;
199 }
200 }
201 else
202 {
203 DevInfo->HwDevInfo = HeapAlloc(GetProcessHeap(),
204 0,
205 sizeof(HWDEVINFO));
206 if (DevInfo->HwDevInfo != NULL)
207 {
208 DevInfo->HwDevInfo[DevInfo->ItemCount].ClassDevInfo = DevInfo;
209 DevInfo->HwDevInfo[DevInfo->ItemCount++].DevInfoData = DevInfoData;
210 }
211 else
212 {
213 DPRINT1("Unable to allocate memory for a SP_DEVINFO_DATA structures!\n");
214 break;
215 }
216 }
217
218 if ((SetupDiGetDeviceRegistryProperty(DevInfo->hDevInfo,
219 &DevInfoData,
220 SPDRP_FRIENDLYNAME,
221 &RegDataType,
222 (PBYTE)szBuffer,
223 sizeof(szBuffer),
224 NULL) ||
225 SetupDiGetDeviceRegistryProperty(DevInfo->hDevInfo,
226 &DevInfoData,
227 SPDRP_DEVICEDESC,
228 &RegDataType,
229 (PBYTE)szBuffer,
230 sizeof(szBuffer),
231 NULL)) &&
232 RegDataType == REG_SZ)
233 {
234 /* FIXME - check string for NULL termination! */
235
236 li.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT | LVIF_IMAGE;
237 li.iItem = ItemCount;
238 li.iSubItem = 0;
239 li.state = (ItemCount == 0 ? LVIS_SELECTED : 0);
240 li.stateMask = LVIS_SELECTED;
241 li.pszText = szBuffer;
242 li.iImage = ImageIndex;
243 li.lParam = (LPARAM)&DevInfo->HwDevInfo[DevInfo->ItemCount - 1];
244
245 iItem = ListView_InsertItem(hpd->hWndDevList,
246 &li);
247 if (iItem != -1)
248 {
249 ItemCount++;
250
251 if (SetupDiGetClassDescription(&DevInfo->Guid,
252 szBuffer,
253 sizeof(szBuffer) / sizeof(szBuffer[0]),
254 NULL))
255 {
256 li.mask = LVIF_TEXT;
257 li.iItem = iItem;
258 li.iSubItem = 1;
259
260 ListView_SetItem(hpd->hWndDevList,
261 &li);
262 }
263 }
264 }
265 }
266 }
267
268 DevInfo++;
269 }
270
271 /* update the controls */
272 UpdateControlStates(hpd);
273 }
274
275
276 static LRESULT
277 CALLBACK
278 ParentSubWndProc(IN HWND hwnd,
279 IN UINT uMsg,
280 IN WPARAM wParam,
281 IN LPARAM lParam)
282 {
283 PHARDWARE_PAGE_DATA hpd;
284
285 hpd = (PHARDWARE_PAGE_DATA)GetProp(hwnd,
286 L"DevMgrSubClassInfo");
287 if (hpd != NULL)
288 {
289 if (uMsg == WM_SIZE)
290 {
291 /* resize the hardware page */
292 SetWindowPos(hpd->hWnd,
293 NULL,
294 0,
295 0,
296 LOWORD(lParam),
297 HIWORD(lParam),
298 SWP_NOZORDER);
299 }
300
301 /* pass the message the the old window proc */
302 return CallWindowProc(hpd->ParentOldWndProc,
303 hwnd,
304 uMsg,
305 wParam,
306 lParam);
307 }
308 else
309 {
310 /* this is not a good idea if the subclassed window was an ansi
311 window, but we failed finding out the previous window proc
312 so we can't use CallWindowProc. This should rarely - if ever -
313 happen. */
314
315 return DefWindowProc(hwnd,
316 uMsg,
317 wParam,
318 lParam);
319 }
320 }
321
322
323 static VOID
324 HardwareDlgResize(IN PHARDWARE_PAGE_DATA hpd,
325 IN INT cx,
326 IN INT cy)
327 {
328 HDWP dwp;
329 HWND hControl, hButton;
330 INT Width, x, y, TopBias = 0;
331 RECT rc, rcButton;
332 POINT pt = {0};
333 POINT ptMargin = {0};
334 POINT ptMarginGroup = {0};
335
336 /* use left margin of the IDC_DEVICES label as the right
337 margin of all controls outside the group box */
338 hControl = GetDlgItem(hpd->hWnd,
339 IDC_DEVICES);
340 GetWindowRect(hControl,
341 &rc);
342 MapWindowPoints(hControl,
343 hpd->hWnd,
344 &ptMargin,
345 1);
346
347 Width = cx - (2 * ptMargin.x);
348
349 if ((dwp = BeginDeferWindowPos(8)))
350 {
351 /* rc already has the window rect of IDC_DEVICES! */
352 if (!(dwp = DeferWindowPos(dwp,
353 hControl,
354 NULL,
355 0,
356 0,
357 Width,
358 rc.bottom - rc.top,
359 SWP_NOMOVE | SWP_NOZORDER)))
360 {
361 return;
362 }
363
364 /* resize the devices list view control */
365 GetWindowRect(hpd->hWndDevList,
366 &rc);
367 MapWindowPoints(hpd->hWndDevList,
368 hpd->hWnd,
369 &pt,
370 1);
371 if (hpd->DisplayMode == HWPD_LARGELIST)
372 {
373 /* increase the size of the list view control by 2/3 */
374 TopBias = ((rc.bottom - rc.top) * 2) / 3;
375 }
376 y = pt.y + TopBias + rc.bottom - rc.top + ptMargin.y;
377 if (!(dwp = DeferWindowPos(dwp,
378 hpd->hWndDevList,
379 NULL,
380 0,
381 0,
382 Width,
383 rc.bottom - rc.top + TopBias,
384 SWP_NOMOVE | SWP_NOZORDER)))
385 {
386 return;
387 }
388
389 /* resize the group box control */
390 hControl = GetDlgItem(hpd->hWnd,
391 IDC_PROPERTIESGROUP);
392 GetWindowRect(hControl,
393 &rc);
394 if (!(dwp = DeferWindowPos(dwp,
395 hControl,
396 NULL,
397 ptMargin.x,
398 y,
399 Width,
400 cy - y - ptMargin.y,
401 SWP_NOZORDER)))
402 {
403 return;
404 }
405
406 /* use left margin of the IDC_MANUFACTURER label as the right
407 margin of all controls inside the group box */
408 hControl = GetDlgItem(hpd->hWnd,
409 IDC_MANUFACTURER);
410 GetWindowRect(hControl,
411 &rc);
412 MapWindowPoints(hControl,
413 hpd->hWnd,
414 &ptMarginGroup,
415 1);
416
417 ptMarginGroup.y = ptMargin.y * 2;
418 Width = cx - (2 * ptMarginGroup.x);
419 y += ptMarginGroup.y;
420 if (!(dwp = DeferWindowPos(dwp,
421 hControl,
422 NULL,
423 ptMarginGroup.x,
424 y,
425 Width,
426 rc.bottom - rc.top,
427 SWP_NOZORDER)))
428 {
429 return;
430 }
431 y += rc.bottom - rc.top + (ptMargin.y / 2);
432
433 /* resize the IDC_LOCATION label */
434 hControl = GetDlgItem(hpd->hWnd,
435 IDC_LOCATION);
436 GetWindowRect(hControl,
437 &rc);
438 if (!(dwp = DeferWindowPos(dwp,
439 hControl,
440 NULL,
441 ptMarginGroup.x,
442 y,
443 Width,
444 rc.bottom - rc.top,
445 SWP_NOZORDER)))
446 {
447 return;
448 }
449 y += rc.bottom - rc.top + (ptMargin.y / 2);
450
451 /* measure the size of the buttons */
452 hButton = GetDlgItem(hpd->hWnd,
453 IDC_PROPERTIES);
454 GetWindowRect(hButton,
455 &rcButton);
456
457 /* resize the IDC_STATUS label */
458 hControl = GetDlgItem(hpd->hWnd,
459 IDC_STATUS);
460 GetWindowRect(hControl,
461 &rc);
462 if (!(dwp = DeferWindowPos(dwp,
463 hControl,
464 NULL,
465 ptMarginGroup.x,
466 y,
467 Width,
468 cy - y - (3 * ptMargin.y) -
469 (rcButton.bottom - rcButton.top),
470 SWP_NOZORDER)))
471 {
472 return;
473 }
474
475 /* move the IDC_PROPERTIES button */
476 y = cy - (2 * ptMargin.y) - (rcButton.bottom - rcButton.top);
477 x = cx - ptMarginGroup.x - (rcButton.right - rcButton.left);
478 if (!(dwp = DeferWindowPos(dwp,
479 hButton,
480 NULL,
481 x,
482 y,
483 0,
484 0,
485 SWP_NOSIZE | SWP_NOZORDER)))
486 {
487 return;
488 }
489
490 /* move the IDC_TROUBLESHOOT button */
491 hButton = GetDlgItem(hpd->hWnd,
492 IDC_TROUBLESHOOT);
493 GetWindowRect(hButton,
494 &rcButton);
495 x -= (ptMargin.x / 2) + (rcButton.right - rcButton.left);
496 if (!(dwp = DeferWindowPos(dwp,
497 hButton,
498 NULL,
499 x,
500 y,
501 0,
502 0,
503 SWP_NOSIZE | SWP_NOZORDER)))
504 {
505 return;
506 }
507
508 EndDeferWindowPos(dwp);
509 }
510 }
511
512
513 static INT_PTR
514 CALLBACK
515 HardwareDlgProc(IN HWND hwndDlg,
516 IN UINT uMsg,
517 IN WPARAM wParam,
518 IN LPARAM lParam)
519 {
520 PHARDWARE_PAGE_DATA hpd;
521
522 hpd = (PHARDWARE_PAGE_DATA)GetWindowLongPtr(hwndDlg,
523 DWL_USER);
524
525 if (hpd != NULL || uMsg == WM_INITDIALOG)
526 {
527 switch (uMsg)
528 {
529 case WM_NOTIFY:
530 {
531 NMHDR *pnmh = (NMHDR*)lParam;
532 if (pnmh->hwndFrom == hpd->hWndDevList)
533 {
534 switch (pnmh->code)
535 {
536 case LVN_ITEMCHANGED:
537 {
538 LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
539
540 if ((pnmv->uChanged & LVIF_STATE) &&
541 ((pnmv->uOldState & (LVIS_FOCUSED | LVIS_SELECTED)) ||
542 (pnmv->uNewState & (LVIS_FOCUSED | LVIS_SELECTED))))
543 {
544 UpdateControlStates(hpd);
545 }
546 break;
547 }
548 }
549 }
550 break;
551 }
552
553 case WM_SIZE:
554 HardwareDlgResize(hpd,
555 (INT)LOWORD(lParam),
556 (INT)HIWORD(lParam));
557 break;
558
559 case WM_INITDIALOG:
560 {
561 hpd = (PHARDWARE_PAGE_DATA)lParam;
562 if (hpd != NULL)
563 {
564 HWND hWndParent;
565
566 hpd->hWnd = hwndDlg;
567 SetWindowLongPtr(hwndDlg,
568 DWL_USER,
569 (DWORD_PTR)hpd);
570
571 hpd->ClassImageListData.cbSize = sizeof(SP_CLASSIMAGELIST_DATA);
572
573 SetupDiGetClassImageList(&hpd->ClassImageListData);
574
575 hpd->hWndDevList = GetDlgItem(hwndDlg,
576 IDC_LV_DEVICES);
577
578 /* subclass the parent window */
579 hWndParent = GetAncestor(hwndDlg,
580 GA_PARENT);
581 if (hWndParent != NULL)
582 {
583 RECT rcClient;
584
585 if (GetClientRect(hWndParent,
586 &rcClient) &&
587 SetWindowPos(hwndDlg,
588 NULL,
589 0,
590 0,
591 rcClient.right,
592 rcClient.bottom,
593 SWP_NOZORDER))
594 {
595 /* subclass the parent window. This is not safe
596 if the parent window belongs to another thread! */
597 hpd->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
598 GWLP_WNDPROC,
599 (LONG_PTR)ParentSubWndProc);
600
601 if (hpd->ParentOldWndProc != NULL &&
602 SetProp(hWndParent,
603 L"DevMgrSubClassInfo",
604 (HANDLE)hpd))
605 {
606 hpd->hWndParent = hWndParent;
607 }
608 }
609 }
610
611 /* initialize the devices list view control */
612 InitializeDevicesList(hpd);
613
614 /* fill the devices list view control */
615 FillDevicesList(hpd);
616 }
617 break;
618 }
619
620 case WM_DESTROY:
621 {
622 UINT i;
623
624 /* free the device info set handles */
625 for (i = 0;
626 i < hpd->NumberOfGuids;
627 i++)
628 {
629 SetupDiDestroyDeviceInfoList(hpd->ClassDevInfo[i].hDevInfo);
630 if (hpd->ClassDevInfo[i].HwDevInfo != NULL)
631 {
632 HeapFree(GetProcessHeap(),
633 0,
634 hpd->ClassDevInfo[i].HwDevInfo);
635 }
636 }
637
638 /* restore the old window proc of the subclassed parent window */
639 if (hpd->hWndParent != NULL && hpd->ParentOldWndProc != NULL)
640 {
641 SetWindowLongPtr(hpd->hWndParent,
642 GWLP_WNDPROC,
643 (LONG_PTR)hpd->ParentOldWndProc);
644 }
645
646 if (hpd->ClassImageListData.ImageList != NULL)
647 {
648 SetupDiDestroyClassImageList(&hpd->ClassImageListData);
649 }
650
651 /* free the reference to comctl32 */
652 FreeLibrary(hpd->hComCtl32);
653 hpd->hComCtl32 = NULL;
654
655 /* free the allocated resources */
656 HeapFree(GetProcessHeap(),
657 0,
658 hpd);
659 break;
660 }
661 }
662 }
663
664 return FALSE;
665 }
666
667
668 /***************************************************************************
669 * NAME EXPORTED
670 * DeviceCreateHardwarePageEx
671 *
672 * DESCRIPTION
673 * Creates a hardware page
674 *
675 * ARGUMENTS
676 * hWndParent: Handle to the parent window
677 * lpGuids: An array of guids of devices that are to be listed
678 * uNumberOfGuids: Numbers of guids in the Guids array
679 * Unknown: Unknown parameter, see NOTEs
680 *
681 * RETURN VALUE
682 * Returns the handle of the hardware page window that has been created or
683 * NULL if it failed.
684 *
685 * REVISIONS
686 * 13-05-2005 first working version (Sebastian Gasiorek <zebasoftis@gmail.com>)
687 *
688 * TODO
689 * missing: device icon in list view, Troubleshoot button, device properties,
690 * status description,
691 * devices should be visible afer PSN_SETACTIVE message
692 *
693 */
694 HWND
695 WINAPI
696 DeviceCreateHardwarePageEx(IN HWND hWndParent,
697 IN LPGUID lpGuids,
698 IN UINT uNumberOfGuids,
699 IN HWPAGE_DISPLAYMODE DisplayMode)
700 {
701 PHARDWARE_PAGE_DATA hpd;
702 PINITCOMMONCONTROLS pInitCommonControls;
703
704 /* allocate the HARDWARE_PAGE_DATA structure. Make sure it is
705 zeroed because the initialization code assumes that in
706 failure cases! */
707 hpd = HeapAlloc(GetProcessHeap(),
708 HEAP_ZERO_MEMORY,
709 FIELD_OFFSET(HARDWARE_PAGE_DATA,
710 ClassDevInfo) +
711 (uNumberOfGuids * sizeof(HWCLASSDEVINFO)));
712 if (hpd != NULL)
713 {
714 HWND hWnd;
715 UINT i;
716
717 hpd->DisplayMode = ((DisplayMode > HWPD_MAX) ? HWPD_STANDARDLIST : DisplayMode);
718
719 /* initialize the HARDWARE_PAGE_DATA structure */
720 hpd->NumberOfGuids = uNumberOfGuids;
721 for (i = 0;
722 i < uNumberOfGuids;
723 i++)
724 {
725 hpd->ClassDevInfo[i].Guid = lpGuids[i];
726 }
727
728 /* load comctl32.dll dynamically */
729 hpd->hComCtl32 = LoadLibrary(TEXT("comctl32.dll"));
730 if (hpd->hComCtl32 == NULL)
731 {
732 goto Cleanup;
733 }
734
735 /* initialize the common controls */
736 pInitCommonControls = (PINITCOMMONCONTROLS)GetProcAddress(hpd->hComCtl32,
737 "InitCommonControls");
738 if (pInitCommonControls == NULL)
739 {
740 goto Cleanup;
741 }
742 pInitCommonControls();
743
744 /* create the dialog */
745 hWnd = CreateDialogParam(hDllInstance,
746 MAKEINTRESOURCE(IDD_HARDWARE),
747 hWndParent,
748 HardwareDlgProc,
749 (LPARAM)hpd);
750 if (hWnd != NULL)
751 {
752 return hWnd;
753 }
754 else
755 {
756 Cleanup:
757 /* oops, something went wrong... */
758 if (hpd->hComCtl32 != NULL)
759 {
760 FreeLibrary(hpd->hComCtl32);
761 }
762
763 HeapFree(GetProcessHeap(),
764 0,
765 hpd);
766 }
767 }
768
769 return NULL;
770 }
771
772
773 /***************************************************************************
774 * NAME EXPORTED
775 * DeviceCreateHardwarePage
776 *
777 * DESCRIPTION
778 * Creates a hardware page
779 *
780 * ARGUMENTS
781 * hWndParent: Handle to the parent window
782 * lpGuid: Guid of the device
783 *
784 * RETURN VALUE
785 * Returns the handle of the hardware page window that has been created or
786 * NULL if it failed.
787 *
788 * REVISIONS
789 *
790 * NOTE
791 *
792 */
793
794 HWND
795 WINAPI
796 DeviceCreateHardwarePage(IN HWND hWndParent,
797 IN LPGUID lpGuid)
798 {
799 return DeviceCreateHardwarePageEx(hWndParent,
800 lpGuid,
801 1,
802 HWPD_LARGELIST);
803 }