fixed refreshing the advanced properties on device changes
[reactos.git] / reactos / lib / devmgr / advprop.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: hwpage.c 19599 2005-11-26 02:12:58Z weiden $
20 *
21 * PROJECT: ReactOS devmgr.dll
22 * FILE: lib/devmgr/advprop.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 #define DPN_DEVICEUPDATE (WM_USER + 0x1000)
34
35 typedef INT_PTR (WINAPI *PPROPERTYSHEETW)(LPCPROPSHEETHEADERW);
36 typedef HPROPSHEETPAGE (WINAPI *PCREATEPROPERTYSHEETPAGEW)(LPCPROPSHEETPAGEW);
37 typedef BOOL (WINAPI *PDESTROYPROPERTYSHEETPAGE)(HPROPSHEETPAGE);
38
39 typedef enum
40 {
41 DEA_DISABLE = 0,
42 DEA_ENABLE,
43 DEA_UNKNOWN
44 } DEVENABLEACTION;
45
46 typedef struct _DEVADVPROP_INFO
47 {
48 HWND hWndGeneralPage;
49 HWND hWndParent;
50 WNDPROC ParentOldWndProc;
51
52 HDEVINFO DeviceInfoSet;
53 SP_DEVINFO_DATA DeviceInfoData;
54 HANDLE hMachine;
55 LPCWSTR lpMachineName;
56
57 HINSTANCE hComCtl32;
58
59 DWORD PropertySheetType;
60 DWORD nDevPropSheets;
61 HPROPSHEETPAGE *DevPropSheets;
62
63 BOOL FreeDevPropSheets : 1;
64 BOOL CanDisable : 1;
65 BOOL DeviceEnabled : 1;
66 BOOL DeviceUsageChanged : 1;
67 BOOL CreatedDevInfoSet : 1;
68
69 WCHAR szDevName[255];
70 WCHAR szTemp[255];
71 WCHAR szDeviceID[1];
72 /* struct may be dynamically expanded here! */
73 } DEVADVPROP_INFO, *PDEVADVPROP_INFO;
74
75
76 static VOID
77 InitDevUsageActions(IN HWND hwndDlg,
78 IN HWND hComboBox,
79 IN PDEVADVPROP_INFO dap)
80 {
81 INT Index;
82 UINT i;
83 struct
84 {
85 UINT szId;
86 DEVENABLEACTION Action;
87 } Actions[] =
88 {
89 {IDS_ENABLEDEVICE, DEA_ENABLE},
90 {IDS_DISABLEDEVICE, DEA_DISABLE},
91 };
92
93 for (i = 0;
94 i != sizeof(Actions) / sizeof(Actions[0]);
95 i++)
96 {
97 /* fill in the device usage combo box */
98 if (LoadString(hDllInstance,
99 Actions[i].szId,
100 dap->szTemp,
101 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
102 {
103 Index = (INT)SendMessage(hComboBox,
104 CB_ADDSTRING,
105 0,
106 (LPARAM)dap->szTemp);
107 if (Index != CB_ERR)
108 {
109 SendMessage(hComboBox,
110 CB_SETITEMDATA,
111 (WPARAM)Index,
112 (LPARAM)Actions[i].Action);
113
114 switch (Actions[i].Action)
115 {
116 case DEA_ENABLE:
117 if (dap->DeviceEnabled)
118 {
119 SendMessage(hComboBox,
120 CB_SETCURSEL,
121 (WPARAM)Index,
122 0);
123 }
124 break;
125
126 case DEA_DISABLE:
127 if (!dap->DeviceEnabled)
128 {
129 SendMessage(hComboBox,
130 CB_SETCURSEL,
131 (WPARAM)Index,
132 0);
133 }
134 break;
135
136 default:
137 break;
138 }
139 }
140 }
141 }
142 }
143
144
145 static DEVENABLEACTION
146 GetSelectedUsageAction(IN HWND hComboBox)
147 {
148 INT Index;
149 DEVENABLEACTION Ret = DEA_UNKNOWN;
150
151 Index = (INT)SendMessage(hComboBox,
152 CB_GETCURSEL,
153 0,
154 0);
155 if (Index != CB_ERR)
156 {
157 INT iRet = SendMessage(hComboBox,
158 CB_GETITEMDATA,
159 (WPARAM)Index,
160 0);
161 if (iRet != CB_ERR && iRet < (INT)DEA_UNKNOWN)
162 {
163 Ret = (DEVENABLEACTION)iRet;
164 }
165 }
166
167 return Ret;
168 }
169
170
171 static VOID
172 ApplyGeneralSettings(IN HWND hwndDlg,
173 IN PDEVADVPROP_INFO dap)
174 {
175 if (dap->DeviceUsageChanged)
176 {
177 DEVENABLEACTION SelectedUsageAction;
178
179 SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
180 IDC_DEVUSAGE));
181 if (SelectedUsageAction != DEA_UNKNOWN)
182 {
183 switch (SelectedUsageAction)
184 {
185 case DEA_ENABLE:
186 if (!dap->DeviceEnabled)
187 {
188 /* FIXME - enable device */
189 }
190 break;
191
192 case DEA_DISABLE:
193 if (dap->DeviceEnabled)
194 {
195 /* FIXME - disable device */
196 }
197 break;
198
199 default:
200 break;
201 }
202 }
203 }
204
205 /* disable the apply button */
206 PropSheet_UnChanged(GetParent(hwndDlg),
207 hwndDlg);
208 dap->DeviceUsageChanged = FALSE;
209 }
210
211
212 static VOID
213 UpdateDevInfo(IN HWND hwndDlg,
214 IN PDEVADVPROP_INFO dap,
215 IN BOOL ReOpen)
216 {
217 HICON hIcon;
218 HWND hDevUsage;
219 HWND hPropSheetDlg;
220 BOOL bFlag;
221 DWORD i;
222
223 hPropSheetDlg = GetParent(hwndDlg);
224
225 if (ReOpen)
226 {
227 PROPSHEETHEADER psh;
228 HDEVINFO hOldDevInfo;
229
230 /* switch to the General page */
231 PropSheet_SetCurSelByID(hPropSheetDlg,
232 IDD_DEVICEGENERAL);
233
234 /* remove and destroy the existing device property sheet pages */
235 for (i = 0;
236 i != dap->nDevPropSheets;
237 i++)
238 {
239 PropSheet_RemovePage(hPropSheetDlg,
240 -1,
241 dap->DevPropSheets[i]);
242 }
243
244 if (dap->FreeDevPropSheets)
245 {
246 /* don't free the array if it's the one allocated in
247 DisplayDeviceAdvancedProperties */
248 HeapFree(GetProcessHeap(),
249 0,
250 dap->DevPropSheets);
251
252 dap->FreeDevPropSheets = FALSE;
253 }
254
255 dap->DevPropSheets = NULL;
256 dap->nDevPropSheets = 0;
257
258 /* create a new device info set and re-open the device */
259 hOldDevInfo = dap->DeviceInfoSet;
260 dap->DeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
261 hwndDlg,
262 dap->lpMachineName,
263 NULL);
264 if (dap->DeviceInfoSet != INVALID_HANDLE_VALUE)
265 {
266 if (SetupDiOpenDeviceInfo(dap->DeviceInfoSet,
267 dap->szDeviceID,
268 hwndDlg,
269 0,
270 &dap->DeviceInfoData))
271 {
272 if (dap->CreatedDevInfoSet)
273 {
274 SetupDiDestroyDeviceInfoList(hOldDevInfo);
275 }
276
277 dap->CreatedDevInfoSet = TRUE;
278 }
279 else
280 {
281 SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
282 dap->DeviceInfoSet = INVALID_HANDLE_VALUE;
283 dap->CreatedDevInfoSet = FALSE;
284 }
285 }
286 else
287 {
288 /* oops, something went wrong, restore the old device info set */
289 dap->DeviceInfoSet = hOldDevInfo;
290
291 if (dap->DeviceInfoSet != INVALID_HANDLE_VALUE)
292 {
293 SetupDiOpenDeviceInfo(dap->DeviceInfoSet,
294 dap->szDeviceID,
295 hwndDlg,
296 0,
297 &dap->DeviceInfoData);
298 }
299 }
300
301 /* find out how many new device property sheets to add.
302 fake a PROPSHEETHEADER structure, we don't plan to
303 call PropertySheet again!*/
304 psh.dwSize = sizeof(PROPSHEETHEADER);
305 psh.dwFlags = 0;
306 psh.nPages = 0;
307
308 if (!SetupDiGetClassDevPropertySheets(dap->DeviceInfoSet,
309 &dap->DeviceInfoData,
310 &psh,
311 0,
312 &dap->nDevPropSheets,
313 dap->PropertySheetType) &&
314 dap->nDevPropSheets != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
315 {
316 dap->DevPropSheets = HeapAlloc(GetProcessHeap(),
317 HEAP_ZERO_MEMORY,
318 dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
319 if (dap->DevPropSheets != NULL)
320 {
321 psh.phpage = dap->DevPropSheets;
322
323 /* query the new property sheet pages to add */
324 if (SetupDiGetClassDevPropertySheets(dap->DeviceInfoSet,
325 &dap->DeviceInfoData,
326 &psh,
327 dap->nDevPropSheets,
328 NULL,
329 dap->PropertySheetType))
330 {
331 /* add the property sheets */
332
333 for (i = 0;
334 i != dap->nDevPropSheets;
335 i++)
336 {
337 PropSheet_AddPage(hPropSheetDlg,
338 dap->DevPropSheets[i]);
339 }
340
341 dap->FreeDevPropSheets = TRUE;
342 }
343 else
344 {
345 /* cleanup, we were unable to get the device property sheets */
346 HeapFree(GetProcessHeap(),
347 0,
348 dap->DevPropSheets);
349
350 dap->nDevPropSheets = 0;
351 dap->DevPropSheets = NULL;
352 }
353 }
354 else
355 dap->nDevPropSheets = 0;
356 }
357 }
358
359 /* get the device name */
360 if (GetDeviceDescriptionString(dap->DeviceInfoSet,
361 &dap->DeviceInfoData,
362 dap->szDevName,
363 sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
364 {
365 PropSheet_SetTitle(GetParent(hwndDlg),
366 PSH_PROPTITLE,
367 dap->szDevName);
368 }
369
370 /* set the device image */
371 if (SetupDiLoadClassIcon(&dap->DeviceInfoData.ClassGuid,
372 &hIcon,
373 NULL))
374 {
375 HICON hOldIcon = (HICON)SendDlgItemMessage(hwndDlg,
376 IDC_DEVICON,
377 STM_SETICON,
378 (WPARAM)hIcon,
379 0);
380 if (hOldIcon != NULL)
381 {
382 DestroyIcon(hOldIcon);
383 }
384 }
385
386 /* set the device name edit control text */
387 SetDlgItemText(hwndDlg,
388 IDC_DEVNAME,
389 dap->szDevName);
390
391 /* set the device type edit control text */
392 if (GetDeviceTypeString(&dap->DeviceInfoData,
393 dap->szTemp,
394 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
395 {
396 SetDlgItemText(hwndDlg,
397 IDC_DEVTYPE,
398 dap->szTemp);
399 }
400
401 /* set the device manufacturer edit control text */
402 if (GetDeviceManufacturerString(dap->DeviceInfoSet,
403 &dap->DeviceInfoData,
404 dap->szTemp,
405 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
406 {
407 SetDlgItemText(hwndDlg,
408 IDC_DEVMANUFACTURER,
409 dap->szTemp);
410 }
411
412 /* set the device location edit control text */
413 if (GetDeviceLocationString(dap->DeviceInfoData.DevInst,
414 dap->szTemp,
415 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
416 {
417 SetDlgItemText(hwndDlg,
418 IDC_DEVLOCATION,
419 dap->szTemp);
420 }
421
422 /* set the device status edit control text */
423 if (GetDeviceStatusString(dap->DeviceInfoData.DevInst,
424 dap->hMachine,
425 dap->szTemp,
426 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
427 {
428 SetDlgItemText(hwndDlg,
429 IDC_DEVSTATUS,
430 dap->szTemp);
431 }
432
433 /* check if the device can be enabled/disabled */
434 hDevUsage = GetDlgItem(hwndDlg,
435 IDC_DEVUSAGE);
436
437 dap->CanDisable = FALSE;
438 dap->DeviceEnabled = FALSE;
439
440 if (dap->DeviceInfoSet != INVALID_HANDLE_VALUE)
441 {
442 if (CanDisableDevice(dap->DeviceInfoData.DevInst,
443 dap->hMachine,
444 &bFlag))
445 {
446 dap->CanDisable = bFlag;
447 }
448
449 if (IsDeviceEnabled(dap->DeviceInfoData.DevInst,
450 dap->hMachine,
451 &bFlag))
452 {
453 dap->DeviceEnabled = bFlag;
454 }
455 }
456
457 /* enable/disable the device usage controls */
458 EnableWindow(GetDlgItem(hwndDlg,
459 IDC_DEVUSAGELABEL),
460 dap->CanDisable);
461 EnableWindow(hDevUsage,
462 dap->CanDisable);
463
464 /* clear the combobox */
465 SendMessage(hDevUsage,
466 CB_RESETCONTENT,
467 0,
468 0);
469 if (dap->CanDisable)
470 {
471 InitDevUsageActions(hwndDlg,
472 hDevUsage,
473 dap);
474 }
475
476 /* finally, disable the apply button */
477 PropSheet_UnChanged(hPropSheetDlg,
478 hwndDlg);
479 dap->DeviceUsageChanged = FALSE;
480 }
481
482
483 static LRESULT
484 CALLBACK
485 DlgParentSubWndProc(IN HWND hwnd,
486 IN UINT uMsg,
487 IN WPARAM wParam,
488 IN LPARAM lParam)
489 {
490 PDEVADVPROP_INFO dap;
491
492 dap = (PDEVADVPROP_INFO)GetProp(hwnd,
493 L"DevMgrDevChangeSub");
494 if (dap != NULL)
495 {
496 if (uMsg == WM_DEVICECHANGE && !IsWindowVisible(dap->hWndGeneralPage))
497 {
498 SendMessage(dap->hWndGeneralPage,
499 WM_DEVICECHANGE,
500 wParam,
501 lParam);
502 }
503
504 /* pass the message the the old window proc */
505 return CallWindowProc(dap->ParentOldWndProc,
506 hwnd,
507 uMsg,
508 wParam,
509 lParam);
510 }
511 else
512 {
513 /* this is not a good idea if the subclassed window was an ansi
514 window, but we failed finding out the previous window proc
515 so we can't use CallWindowProc. This should rarely - if ever -
516 happen. */
517
518 return DefWindowProc(hwnd,
519 uMsg,
520 wParam,
521 lParam);
522 }
523 }
524
525
526 static INT_PTR
527 CALLBACK
528 AdvPropGeneralDlgProc(IN HWND hwndDlg,
529 IN UINT uMsg,
530 IN WPARAM wParam,
531 IN LPARAM lParam)
532 {
533 PDEVADVPROP_INFO dap;
534 INT_PTR Ret = FALSE;
535
536 dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
537 DWL_USER);
538
539 if (dap != NULL || uMsg == WM_INITDIALOG)
540 {
541 switch (uMsg)
542 {
543 case WM_COMMAND:
544 {
545 switch (LOWORD(wParam))
546 {
547 case IDC_DEVUSAGE:
548 {
549 if (HIWORD(wParam) == CBN_SELCHANGE)
550 {
551 PropSheet_Changed(GetParent(hwndDlg),
552 hwndDlg);
553 dap->DeviceUsageChanged = TRUE;
554 }
555 break;
556 }
557 }
558 break;
559 }
560
561 case WM_NOTIFY:
562 {
563 NMHDR *hdr = (NMHDR*)lParam;
564 switch (hdr->code)
565 {
566 case PSN_APPLY:
567 ApplyGeneralSettings(hwndDlg,
568 dap);
569 break;
570 }
571 break;
572 }
573
574 case WM_INITDIALOG:
575 {
576 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
577 if (dap != NULL)
578 {
579 HWND hWndParent;
580
581 dap->hWndGeneralPage = hwndDlg;
582
583 SetWindowLongPtr(hwndDlg,
584 DWL_USER,
585 (DWORD_PTR)dap);
586
587 /* subclass the parent window to always receive
588 WM_DEVICECHANGE messages */
589 hWndParent = GetParent(hwndDlg);
590 if (hWndParent != NULL)
591 {
592 /* subclass the parent window. This is not safe
593 if the parent window belongs to another thread! */
594 dap->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
595 GWLP_WNDPROC,
596 (LONG_PTR)DlgParentSubWndProc);
597
598 if (dap->ParentOldWndProc != NULL &&
599 SetProp(hWndParent,
600 L"DevMgrDevChangeSub",
601 (HANDLE)dap))
602 {
603 dap->hWndParent = hWndParent;
604 }
605 }
606
607 UpdateDevInfo(hwndDlg,
608 dap,
609 FALSE);
610 }
611 Ret = TRUE;
612 break;
613 }
614
615 case WM_DEVICECHANGE:
616 {
617 /* FIXME - don't call UpdateDevInfo in all events */
618 UpdateDevInfo(hwndDlg,
619 dap,
620 TRUE);
621 break;
622 }
623
624 case WM_DESTROY:
625 {
626 HICON hDevIcon;
627
628 /* restore the old window proc of the subclassed parent window */
629 if (dap->hWndParent != NULL && dap->ParentOldWndProc != NULL)
630 {
631 SetWindowLongPtr(dap->hWndParent,
632 GWLP_WNDPROC,
633 (LONG_PTR)dap->ParentOldWndProc);
634 }
635
636 /* destroy the device icon */
637 hDevIcon = (HICON)SendDlgItemMessage(hwndDlg,
638 IDC_DEVICON,
639 STM_GETICON,
640 0,
641 0);
642 if (hDevIcon != NULL)
643 {
644 DestroyIcon(hDevIcon);
645 }
646 break;
647 }
648 }
649 }
650
651 return Ret;
652 }
653
654
655 INT_PTR
656 DisplayDeviceAdvancedProperties(IN HWND hWndParent,
657 IN LPCWSTR lpDeviceID OPTIONAL,
658 IN HDEVINFO DeviceInfoSet,
659 IN PSP_DEVINFO_DATA DeviceInfoData,
660 IN HINSTANCE hComCtl32,
661 IN LPCWSTR lpMachineName)
662 {
663 PROPSHEETHEADER psh = {0};
664 PROPSHEETPAGE pspGeneral = {0};
665 DWORD nPropSheets = 0;
666 PPROPERTYSHEETW pPropertySheetW;
667 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
668 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
669 PDEVADVPROP_INFO DevAdvPropInfo;
670 HANDLE hMachine = NULL;
671 DWORD DevIdSize = 0;
672 INT_PTR Ret = -1;
673
674 /* we don't want to statically link against comctl32, so find the
675 functions we need dynamically */
676 pPropertySheetW =
677 (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
678 "PropertySheetW");
679 pCreatePropertySheetPageW =
680 (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
681 "CreatePropertySheetPageW");
682 pDestroyPropertySheetPage =
683 (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
684 "DestroyPropertySheetPage");
685 if (pPropertySheetW == NULL ||
686 pCreatePropertySheetPageW == NULL ||
687 pDestroyPropertySheetPage == NULL)
688 {
689 return -1;
690 }
691
692 if (lpDeviceID == NULL)
693 {
694 /* find out how much size is needed for the device id */
695 if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
696 DeviceInfoData,
697 NULL,
698 0,
699 &DevIdSize))
700 {
701 DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
702 return -1;
703 }
704
705 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
706 {
707 return -1;
708 }
709 }
710 else
711 {
712 DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
713 }
714
715 if (lpMachineName != NULL)
716 {
717 CONFIGRET cr = CM_Connect_Machine(lpMachineName,
718 &hMachine);
719 if (cr != CR_SUCCESS)
720 {
721 return -1;
722 }
723 }
724
725 /* create the internal structure associated with the "General",
726 "Driver", ... pages */
727 DevAdvPropInfo = HeapAlloc(GetProcessHeap(),
728 HEAP_ZERO_MEMORY,
729 FIELD_OFFSET(DEVADVPROP_INFO,
730 szDeviceID) +
731 (DevIdSize * sizeof(WCHAR)));
732 if (DevAdvPropInfo == NULL)
733 {
734 goto Cleanup;
735 }
736
737 if (lpDeviceID == NULL)
738 {
739 /* read the device instance id */
740 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
741 DeviceInfoData,
742 DevAdvPropInfo->szDeviceID,
743 DevIdSize,
744 NULL))
745 {
746 goto Cleanup;
747 }
748 }
749 else
750 {
751 /* copy the device instance id supplied by the caller */
752 wcscpy(DevAdvPropInfo->szDeviceID,
753 lpDeviceID);
754 }
755
756 DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
757 DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
758 DevAdvPropInfo->hMachine = hMachine;
759 DevAdvPropInfo->lpMachineName = lpMachineName;
760 DevAdvPropInfo->szDevName[0] = L'\0';
761 DevAdvPropInfo->hComCtl32 = hComCtl32;
762
763 psh.dwSize = sizeof(PROPSHEETHEADER);
764 psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
765 psh.hwndParent = hWndParent;
766 psh.pszCaption = DevAdvPropInfo->szDevName;
767
768 DevAdvPropInfo->PropertySheetType = lpMachineName != NULL ?
769 DIGCDP_FLAG_REMOTE_ADVANCED :
770 DIGCDP_FLAG_ADVANCED;
771
772 /* find out how many property sheets we need */
773 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
774 &DevAdvPropInfo->DeviceInfoData,
775 &psh,
776 0,
777 &nPropSheets,
778 DevAdvPropInfo->PropertySheetType) &&
779 nPropSheets != 0)
780 {
781 DPRINT1("SetupDiGetClassDevPropertySheets unexpectedly returned TRUE!\n");
782 goto Cleanup;
783 }
784
785 if (nPropSheets != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
786 {
787 goto Cleanup;
788 }
789
790 psh.phpage = HeapAlloc(GetProcessHeap(),
791 HEAP_ZERO_MEMORY,
792 (nPropSheets + 1) * sizeof(HPROPSHEETPAGE));
793 if (psh.phpage == NULL)
794 {
795 goto Cleanup;
796 }
797
798 /* add the "General" property sheet */
799 pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
800 pspGeneral.dwFlags = PSP_DEFAULT;
801 pspGeneral.hInstance = hDllInstance;
802 pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
803 pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
804 pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
805 psh.phpage[0] = pCreatePropertySheetPageW(&pspGeneral);
806 if (psh.phpage[0] != NULL)
807 {
808 psh.nPages++;
809 }
810
811 DevAdvPropInfo->nDevPropSheets = nPropSheets;
812
813 if (nPropSheets != 0)
814 {
815 DevAdvPropInfo->DevPropSheets = psh.phpage + psh.nPages;
816
817 /* create the device property sheets */
818 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
819 &DevAdvPropInfo->DeviceInfoData,
820 &psh,
821 nPropSheets + psh.nPages,
822 NULL,
823 DevAdvPropInfo->PropertySheetType))
824 {
825 goto Cleanup;
826 }
827 }
828
829 /* FIXME - add the "Driver" property sheet if necessary */
830
831 if (psh.nPages != 0)
832 {
833 Ret = pPropertySheetW(&psh);
834
835 /* NOTE: no need to destroy the property sheets anymore! */
836 }
837 else
838 {
839 UINT i;
840
841 Cleanup:
842 /* in case of failure the property sheets must be destroyed */
843 if (psh.phpage != NULL)
844 {
845 for (i = 0;
846 i < psh.nPages;
847 i++)
848 {
849 if (psh.phpage[i] != NULL)
850 {
851 pDestroyPropertySheetPage(psh.phpage[i]);
852 }
853 }
854 }
855 }
856
857 if (DevAdvPropInfo != NULL)
858 {
859 if (DevAdvPropInfo->FreeDevPropSheets)
860 {
861 /* don't free the array if it's the one allocated in
862 DisplayDeviceAdvancedProperties */
863 HeapFree(GetProcessHeap(),
864 0,
865 DevAdvPropInfo->DevPropSheets);
866 }
867
868 if (DevAdvPropInfo->CreatedDevInfoSet)
869 {
870 /* close the device info set in case a new one was created */
871 SetupDiDestroyDeviceInfoList(DevAdvPropInfo->DeviceInfoSet);
872 }
873
874 HeapFree(GetProcessHeap(),
875 0,
876 DevAdvPropInfo);
877 }
878
879 if (psh.phpage != NULL)
880 {
881 HeapFree(GetProcessHeap(),
882 0,
883 psh.phpage);
884 }
885
886 if (hMachine != NULL)
887 {
888 CM_Disconnect_Machine(hMachine);
889 }
890
891 return Ret;
892 }
893
894
895 /***************************************************************************
896 * NAME EXPORTED
897 * DeviceAdvancedPropertiesW
898 *
899 * DESCRIPTION
900 * Invokes the device properties dialog, this version may add some property pages
901 * for some devices
902 *
903 * ARGUMENTS
904 * hWndParent: Handle to the parent window
905 * lpMachineName: Machine Name, NULL is the local machine
906 * lpDeviceID: Specifies the device whose properties are to be shown
907 *
908 * RETURN VALUE
909 * -1: if errors occured
910 *
911 * REVISIONS
912 *
913 * NOTE
914 *
915 * @implemented
916 */
917 INT_PTR
918 WINAPI
919 DeviceAdvancedPropertiesW(HWND hWndParent,
920 LPCWSTR lpMachineName,
921 LPCWSTR lpDeviceID)
922 {
923 HDEVINFO hDevInfo;
924 SP_DEVINFO_DATA DevInfoData;
925 HINSTANCE hComCtl32;
926 INT_PTR Ret = -1;
927
928 /* dynamically load comctl32 */
929 hComCtl32 = LoadAndInitComctl32();
930 if (hComCtl32 != NULL)
931 {
932 hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
933 hWndParent,
934 lpMachineName,
935 NULL);
936 if (hDevInfo != INVALID_HANDLE_VALUE)
937 {
938 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
939 if (SetupDiOpenDeviceInfo(hDevInfo,
940 lpDeviceID,
941 hWndParent,
942 0,
943 &DevInfoData))
944 {
945 Ret = DisplayDeviceAdvancedProperties(hWndParent,
946 lpDeviceID,
947 hDevInfo,
948 &DevInfoData,
949 hComCtl32,
950 lpMachineName);
951 }
952
953 SetupDiDestroyDeviceInfoList(hDevInfo);
954 }
955
956 FreeLibrary(hComCtl32);
957 }
958
959 return Ret;
960 }
961
962
963 /***************************************************************************
964 * NAME EXPORTED
965 * DeviceAdvancedPropertiesA
966 *
967 * DESCRIPTION
968 * Invokes the device properties dialog, this version may add some property pages
969 * for some devices
970 *
971 * ARGUMENTS
972 * hWndParent: Handle to the parent window
973 * lpMachineName: Machine Name, NULL is the local machine
974 * lpDeviceID: Specifies the device whose properties are to be shown
975 *
976 * RETURN VALUE
977 * -1: if errors occured
978 *
979 * REVISIONS
980 *
981 * NOTE
982 *
983 * @implemented
984 */
985 INT_PTR
986 WINAPI
987 DeviceAdvancedPropertiesA(HWND hWndParent,
988 LPCSTR lpMachineName,
989 LPCSTR lpDeviceID)
990 {
991 LPWSTR lpMachineNameW = NULL;
992 LPWSTR lpDeviceIDW = NULL;
993 INT_PTR Ret = -1;
994
995 if (lpMachineName != NULL)
996 {
997 if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
998 CP_ACP)))
999 {
1000 goto Cleanup;
1001 }
1002 }
1003 if (lpDeviceID != NULL)
1004 {
1005 if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
1006 CP_ACP)))
1007 {
1008 goto Cleanup;
1009 }
1010 }
1011
1012 Ret = DeviceAdvancedPropertiesW(hWndParent,
1013 lpMachineNameW,
1014 lpDeviceIDW);
1015
1016 Cleanup:
1017 if (lpMachineNameW != NULL)
1018 {
1019 HeapFree(GetProcessHeap(),
1020 0,
1021 lpMachineNameW);
1022 }
1023 if (lpDeviceIDW != NULL)
1024 {
1025 HeapFree(GetProcessHeap(),
1026 0,
1027 lpDeviceIDW);
1028 }
1029
1030 return Ret;
1031 }