38f799d2d7f816344e3ba2c2f30c8ed8055a62c1
[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 typedef INT_PTR (WINAPI *PPROPERTYSHEETW)(LPCPROPSHEETHEADERW);
34 typedef HPROPSHEETPAGE (WINAPI *PCREATEPROPERTYSHEETPAGEW)(LPCPROPSHEETPAGEW);
35 typedef BOOL (WINAPI *PDESTROYPROPERTYSHEETPAGE)(HPROPSHEETPAGE);
36
37 typedef enum
38 {
39 DEA_DISABLE = 0,
40 DEA_ENABLE,
41 DEA_UNKNOWN
42 } DEVENABLEACTION;
43
44 typedef struct _DEVADVPROP_INFO
45 {
46 HWND hWndGeneralPage;
47 HWND hWndParent;
48 WNDPROC ParentOldWndProc;
49
50 HDEVINFO DeviceInfoSet;
51 SP_DEVINFO_DATA DeviceInfoData;
52 HDEVINFO CurrentDeviceInfoSet;
53 SP_DEVINFO_DATA CurrentDeviceInfoData;
54 DEVINST ParentDevInst;
55 HMACHINE hMachine;
56 LPCWSTR lpMachineName;
57
58 HINSTANCE hComCtl32;
59
60 DWORD PropertySheetType;
61 DWORD nDevPropSheets;
62 HPROPSHEETPAGE *DevPropSheets;
63
64 BOOL FreeDevPropSheets : 1;
65 BOOL CanDisable : 1;
66 BOOL DeviceEnabled : 1;
67 BOOL DeviceUsageChanged : 1;
68 BOOL CloseDevInst : 1;
69 BOOL IsAdmin : 1;
70 BOOL DoDefaultDevAction : 1;
71
72 WCHAR szDevName[255];
73 WCHAR szTemp[255];
74 WCHAR szDeviceID[1];
75 /* struct may be dynamically expanded here! */
76 } DEVADVPROP_INFO, *PDEVADVPROP_INFO;
77
78
79 static VOID
80 InitDevUsageActions(IN HWND hwndDlg,
81 IN HWND hComboBox,
82 IN PDEVADVPROP_INFO dap)
83 {
84 INT Index;
85 UINT i;
86 struct
87 {
88 UINT szId;
89 DEVENABLEACTION Action;
90 } Actions[] =
91 {
92 {IDS_ENABLEDEVICE, DEA_ENABLE},
93 {IDS_DISABLEDEVICE, DEA_DISABLE},
94 };
95
96 for (i = 0;
97 i != sizeof(Actions) / sizeof(Actions[0]);
98 i++)
99 {
100 /* fill in the device usage combo box */
101 if (LoadString(hDllInstance,
102 Actions[i].szId,
103 dap->szTemp,
104 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
105 {
106 Index = (INT)SendMessage(hComboBox,
107 CB_ADDSTRING,
108 0,
109 (LPARAM)dap->szTemp);
110 if (Index != CB_ERR)
111 {
112 SendMessage(hComboBox,
113 CB_SETITEMDATA,
114 (WPARAM)Index,
115 (LPARAM)Actions[i].Action);
116
117 switch (Actions[i].Action)
118 {
119 case DEA_ENABLE:
120 if (dap->DeviceEnabled)
121 {
122 SendMessage(hComboBox,
123 CB_SETCURSEL,
124 (WPARAM)Index,
125 0);
126 }
127 break;
128
129 case DEA_DISABLE:
130 if (!dap->DeviceEnabled)
131 {
132 SendMessage(hComboBox,
133 CB_SETCURSEL,
134 (WPARAM)Index,
135 0);
136 }
137 break;
138
139 default:
140 break;
141 }
142 }
143 }
144 }
145 }
146
147
148 static DEVENABLEACTION
149 GetSelectedUsageAction(IN HWND hComboBox)
150 {
151 INT Index;
152 DEVENABLEACTION Ret = DEA_UNKNOWN;
153
154 Index = (INT)SendMessage(hComboBox,
155 CB_GETCURSEL,
156 0,
157 0);
158 if (Index != CB_ERR)
159 {
160 INT iRet = SendMessage(hComboBox,
161 CB_GETITEMDATA,
162 (WPARAM)Index,
163 0);
164 if (iRet != CB_ERR && iRet < (INT)DEA_UNKNOWN)
165 {
166 Ret = (DEVENABLEACTION)iRet;
167 }
168 }
169
170 return Ret;
171 }
172
173
174 static VOID
175 ApplyGeneralSettings(IN HWND hwndDlg,
176 IN PDEVADVPROP_INFO dap)
177 {
178 if (dap->DeviceUsageChanged && dap->IsAdmin)
179 {
180 DEVENABLEACTION SelectedUsageAction;
181
182 SelectedUsageAction = GetSelectedUsageAction(GetDlgItem(hwndDlg,
183 IDC_DEVUSAGE));
184 if (SelectedUsageAction != DEA_UNKNOWN)
185 {
186 switch (SelectedUsageAction)
187 {
188 case DEA_ENABLE:
189 if (!dap->DeviceEnabled)
190 {
191 /* FIXME - enable device */
192 }
193 break;
194
195 case DEA_DISABLE:
196 if (dap->DeviceEnabled)
197 {
198 /* FIXME - disable device */
199 }
200 break;
201
202 default:
203 break;
204 }
205 }
206 }
207
208 /* disable the apply button */
209 PropSheet_UnChanged(GetParent(hwndDlg),
210 hwndDlg);
211 dap->DeviceUsageChanged = FALSE;
212 }
213
214
215 static VOID
216 UpdateDevInfo(IN HWND hwndDlg,
217 IN PDEVADVPROP_INFO dap,
218 IN BOOL ReOpen)
219 {
220 HICON hIcon;
221 HWND hDevUsage, hPropSheetDlg, hDevProbBtn;
222 CONFIGRET cr;
223 ULONG Status, ProblemNumber;
224 UINT TroubleShootStrId = IDS_TROUBLESHOOTDEV;
225 BOOL bFlag;
226 DWORD i;
227 HDEVINFO DeviceInfoSet = NULL;
228 PSP_DEVINFO_DATA DeviceInfoData = NULL;
229
230 hPropSheetDlg = GetParent(hwndDlg);
231
232 if (ReOpen)
233 {
234 PROPSHEETHEADER psh;
235
236 /* switch to the General page */
237 PropSheet_SetCurSelByID(hPropSheetDlg,
238 IDD_DEVICEGENERAL);
239
240 /* remove and destroy the existing device property sheet pages */
241 for (i = 0;
242 i != dap->nDevPropSheets;
243 i++)
244 {
245 PropSheet_RemovePage(hPropSheetDlg,
246 -1,
247 dap->DevPropSheets[i]);
248 }
249
250 if (dap->FreeDevPropSheets)
251 {
252 /* don't free the array if it's the one allocated in
253 DisplayDeviceAdvancedProperties */
254 HeapFree(GetProcessHeap(),
255 0,
256 dap->DevPropSheets);
257
258 dap->FreeDevPropSheets = FALSE;
259 }
260
261 dap->DevPropSheets = NULL;
262 dap->nDevPropSheets = 0;
263
264 /* create a new device info set and re-open the device */
265 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
266 {
267 SetupDiDestroyDeviceInfoList(dap->CurrentDeviceInfoSet);
268 }
269
270 dap->ParentDevInst = 0;
271 dap->CurrentDeviceInfoSet = SetupDiCreateDeviceInfoListEx(NULL,
272 hwndDlg,
273 dap->lpMachineName,
274 NULL);
275 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
276 {
277 if (SetupDiOpenDeviceInfo(dap->CurrentDeviceInfoSet,
278 dap->szDeviceID,
279 hwndDlg,
280 0,
281 &dap->CurrentDeviceInfoData))
282 {
283 if (dap->CloseDevInst)
284 {
285 SetupDiDestroyDeviceInfoList(dap->DeviceInfoSet);
286 }
287
288 dap->CloseDevInst = TRUE;
289 dap->DeviceInfoSet = dap->CurrentDeviceInfoSet;
290 dap->DeviceInfoData = dap->CurrentDeviceInfoData;
291 dap->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
292 }
293 else
294 goto GetParentNode;
295 }
296 else
297 {
298 GetParentNode:
299 /* get the parent node from the initial devinst */
300 CM_Get_Parent_Ex(&dap->ParentDevInst,
301 dap->DeviceInfoData.DevInst,
302 0,
303 dap->hMachine);
304 }
305
306 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
307 {
308 DeviceInfoSet = dap->CurrentDeviceInfoSet;
309 DeviceInfoData = &dap->CurrentDeviceInfoData;
310 }
311 else
312 {
313 DeviceInfoSet = dap->DeviceInfoSet;
314 DeviceInfoData = &dap->DeviceInfoData;
315 }
316
317 /* find out how many new device property sheets to add.
318 fake a PROPSHEETHEADER structure, we don't plan to
319 call PropertySheet again!*/
320 psh.dwSize = sizeof(PROPSHEETHEADER);
321 psh.dwFlags = 0;
322 psh.nPages = 0;
323
324 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
325 DeviceInfoData,
326 &psh,
327 0,
328 &dap->nDevPropSheets,
329 dap->PropertySheetType) &&
330 dap->nDevPropSheets != 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
331 {
332 dap->DevPropSheets = HeapAlloc(GetProcessHeap(),
333 HEAP_ZERO_MEMORY,
334 dap->nDevPropSheets * sizeof(HPROPSHEETPAGE));
335 if (dap->DevPropSheets != NULL)
336 {
337 psh.phpage = dap->DevPropSheets;
338
339 /* query the new property sheet pages to add */
340 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
341 DeviceInfoData,
342 &psh,
343 dap->nDevPropSheets,
344 NULL,
345 dap->PropertySheetType))
346 {
347 /* add the property sheets */
348
349 for (i = 0;
350 i != dap->nDevPropSheets;
351 i++)
352 {
353 PropSheet_AddPage(hPropSheetDlg,
354 dap->DevPropSheets[i]);
355 }
356
357 dap->FreeDevPropSheets = TRUE;
358 }
359 else
360 {
361 /* cleanup, we were unable to get the device property sheets */
362 HeapFree(GetProcessHeap(),
363 0,
364 dap->DevPropSheets);
365
366 dap->nDevPropSheets = 0;
367 dap->DevPropSheets = NULL;
368 }
369 }
370 else
371 dap->nDevPropSheets = 0;
372 }
373 }
374 else
375 {
376 if (dap->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
377 {
378 DeviceInfoSet = dap->CurrentDeviceInfoSet;
379 DeviceInfoData = &dap->CurrentDeviceInfoData;
380 }
381 else
382 {
383 DeviceInfoSet = dap->DeviceInfoSet;
384 DeviceInfoData = &dap->DeviceInfoData;
385 }
386 }
387
388 /* get the device name */
389 if (GetDeviceDescriptionString(DeviceInfoSet,
390 DeviceInfoData,
391 dap->szDevName,
392 sizeof(dap->szDevName) / sizeof(dap->szDevName[0])))
393 {
394 PropSheet_SetTitle(GetParent(hwndDlg),
395 PSH_PROPTITLE,
396 dap->szDevName);
397 }
398
399 /* set the device image */
400 if (SetupDiLoadClassIcon(&DeviceInfoData->ClassGuid,
401 &hIcon,
402 NULL))
403 {
404 HICON hOldIcon = (HICON)SendDlgItemMessage(hwndDlg,
405 IDC_DEVICON,
406 STM_SETICON,
407 (WPARAM)hIcon,
408 0);
409 if (hOldIcon != NULL)
410 {
411 DestroyIcon(hOldIcon);
412 }
413 }
414
415 /* set the device name edit control text */
416 SetDlgItemText(hwndDlg,
417 IDC_DEVNAME,
418 dap->szDevName);
419
420 /* set the device type edit control text */
421 if (GetDeviceTypeString(DeviceInfoData,
422 dap->szTemp,
423 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
424 {
425 SetDlgItemText(hwndDlg,
426 IDC_DEVTYPE,
427 dap->szTemp);
428 }
429
430 /* set the device manufacturer edit control text */
431 if (GetDeviceManufacturerString(DeviceInfoSet,
432 DeviceInfoData,
433 dap->szTemp,
434 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
435 {
436 SetDlgItemText(hwndDlg,
437 IDC_DEVMANUFACTURER,
438 dap->szTemp);
439 }
440
441 /* set the device location edit control text */
442 if (GetDeviceLocationString(DeviceInfoData->DevInst,
443 dap->ParentDevInst,
444 dap->szTemp,
445 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
446 {
447 SetDlgItemText(hwndDlg,
448 IDC_DEVLOCATION,
449 dap->szTemp);
450 }
451
452 /* set the device status edit control text */
453 if (GetDeviceStatusString(DeviceInfoData->DevInst,
454 dap->hMachine,
455 dap->szTemp,
456 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])))
457 {
458 SetDlgItemText(hwndDlg,
459 IDC_DEVSTATUS,
460 dap->szTemp);
461 }
462
463 /* set the device troubleshoot button text and disable it if necessary */
464 hDevProbBtn = GetDlgItem(hwndDlg,
465 IDC_DEVPROBLEM);
466 EnableWindow(hDevProbBtn,
467 dap->IsAdmin);
468 cr = CM_Get_DevNode_Status_Ex(&Status,
469 &ProblemNumber,
470 DeviceInfoData->DevInst,
471 0,
472 dap->hMachine);
473 if (cr == CR_SUCCESS &&
474 (Status & DN_HAS_PROBLEM) && ProblemNumber == CM_PROB_DISABLED)
475 {
476 TroubleShootStrId = IDS_ENABLEDEV;
477 }
478
479 if (LoadString(hDllInstance,
480 TroubleShootStrId,
481 dap->szTemp,
482 sizeof(dap->szTemp) / sizeof(dap->szTemp[0])) != 0)
483 {
484 SetWindowText(hDevProbBtn,
485 dap->szTemp);
486 }
487
488 /* check if the device can be enabled/disabled */
489 hDevUsage = GetDlgItem(hwndDlg,
490 IDC_DEVUSAGE);
491
492 dap->CanDisable = FALSE;
493 dap->DeviceEnabled = FALSE;
494
495 if (CanDisableDevice(DeviceInfoData->DevInst,
496 dap->hMachine,
497 &bFlag))
498 {
499 dap->CanDisable = bFlag;
500 }
501
502 if (IsDeviceEnabled(DeviceInfoData->DevInst,
503 dap->hMachine,
504 &bFlag))
505 {
506 dap->DeviceEnabled = bFlag;
507 }
508
509 /* enable/disable the device usage controls */
510 EnableWindow(GetDlgItem(hwndDlg,
511 IDC_DEVUSAGELABEL),
512 dap->CanDisable && dap->IsAdmin);
513 EnableWindow(hDevUsage,
514 dap->CanDisable && dap->IsAdmin);
515
516 /* clear the combobox */
517 SendMessage(hDevUsage,
518 CB_RESETCONTENT,
519 0,
520 0);
521 if (dap->CanDisable)
522 {
523 InitDevUsageActions(hwndDlg,
524 hDevUsage,
525 dap);
526 }
527
528 /* finally, disable the apply button */
529 PropSheet_UnChanged(hPropSheetDlg,
530 hwndDlg);
531 dap->DeviceUsageChanged = FALSE;
532 }
533
534
535 static LRESULT
536 CALLBACK
537 DlgParentSubWndProc(IN HWND hwnd,
538 IN UINT uMsg,
539 IN WPARAM wParam,
540 IN LPARAM lParam)
541 {
542 PDEVADVPROP_INFO dap;
543
544 dap = (PDEVADVPROP_INFO)GetProp(hwnd,
545 L"DevMgrDevChangeSub");
546 if (dap != NULL)
547 {
548 if (uMsg == WM_DEVICECHANGE && !IsWindowVisible(dap->hWndGeneralPage))
549 {
550 SendMessage(dap->hWndGeneralPage,
551 WM_DEVICECHANGE,
552 wParam,
553 lParam);
554 }
555
556 /* pass the message the the old window proc */
557 return CallWindowProc(dap->ParentOldWndProc,
558 hwnd,
559 uMsg,
560 wParam,
561 lParam);
562 }
563 else
564 {
565 /* this is not a good idea if the subclassed window was an ansi
566 window, but we failed finding out the previous window proc
567 so we can't use CallWindowProc. This should rarely - if ever -
568 happen. */
569
570 return DefWindowProc(hwnd,
571 uMsg,
572 wParam,
573 lParam);
574 }
575 }
576
577
578 static INT_PTR
579 CALLBACK
580 AdvPropGeneralDlgProc(IN HWND hwndDlg,
581 IN UINT uMsg,
582 IN WPARAM wParam,
583 IN LPARAM lParam)
584 {
585 PDEVADVPROP_INFO dap;
586 INT_PTR Ret = FALSE;
587
588 dap = (PDEVADVPROP_INFO)GetWindowLongPtr(hwndDlg,
589 DWL_USER);
590
591 if (dap != NULL || uMsg == WM_INITDIALOG)
592 {
593 switch (uMsg)
594 {
595 case WM_COMMAND:
596 {
597 switch (LOWORD(wParam))
598 {
599 case IDC_DEVUSAGE:
600 {
601 if (HIWORD(wParam) == CBN_SELCHANGE)
602 {
603 PropSheet_Changed(GetParent(hwndDlg),
604 hwndDlg);
605 dap->DeviceUsageChanged = TRUE;
606 }
607 break;
608 }
609
610 case IDC_DEVPROBLEM:
611 {
612 if (dap->IsAdmin)
613 {
614 /* display the device problem wizard */
615 ShowDeviceProblemWizard(hwndDlg,
616 dap->DeviceInfoSet,
617 &dap->DeviceInfoData,
618 dap->hMachine);
619 }
620 break;
621 }
622 }
623 break;
624 }
625
626 case WM_NOTIFY:
627 {
628 NMHDR *hdr = (NMHDR*)lParam;
629 switch (hdr->code)
630 {
631 case PSN_APPLY:
632 ApplyGeneralSettings(hwndDlg,
633 dap);
634 break;
635 }
636 break;
637 }
638
639 case WM_INITDIALOG:
640 {
641 dap = (PDEVADVPROP_INFO)((LPPROPSHEETPAGE)lParam)->lParam;
642 if (dap != NULL)
643 {
644 HWND hWndParent;
645
646 dap->hWndGeneralPage = hwndDlg;
647
648 SetWindowLongPtr(hwndDlg,
649 DWL_USER,
650 (DWORD_PTR)dap);
651
652 /* subclass the parent window to always receive
653 WM_DEVICECHANGE messages */
654 hWndParent = GetParent(hwndDlg);
655 if (hWndParent != NULL)
656 {
657 /* subclass the parent window. This is not safe
658 if the parent window belongs to another thread! */
659 dap->ParentOldWndProc = (WNDPROC)SetWindowLongPtr(hWndParent,
660 GWLP_WNDPROC,
661 (LONG_PTR)DlgParentSubWndProc);
662
663 if (dap->ParentOldWndProc != NULL &&
664 SetProp(hWndParent,
665 L"DevMgrDevChangeSub",
666 (HANDLE)dap))
667 {
668 dap->hWndParent = hWndParent;
669 }
670 }
671
672 UpdateDevInfo(hwndDlg,
673 dap,
674 FALSE);
675 }
676 Ret = TRUE;
677 break;
678 }
679
680 case WM_DEVICECHANGE:
681 {
682 /* FIXME - don't call UpdateDevInfo for all events */
683 UpdateDevInfo(hwndDlg,
684 dap,
685 TRUE);
686 Ret = TRUE;
687 break;
688 }
689
690 case WM_DESTROY:
691 {
692 HICON hDevIcon;
693
694 /* restore the old window proc of the subclassed parent window */
695 if (dap->hWndParent != NULL && dap->ParentOldWndProc != NULL)
696 {
697 SetWindowLongPtr(dap->hWndParent,
698 GWLP_WNDPROC,
699 (LONG_PTR)dap->ParentOldWndProc);
700 }
701
702 /* destroy the device icon */
703 hDevIcon = (HICON)SendDlgItemMessage(hwndDlg,
704 IDC_DEVICON,
705 STM_GETICON,
706 0,
707 0);
708 if (hDevIcon != NULL)
709 {
710 DestroyIcon(hDevIcon);
711 }
712 break;
713 }
714 }
715 }
716
717 return Ret;
718 }
719
720
721 INT_PTR
722 DisplayDeviceAdvancedProperties(IN HWND hWndParent,
723 IN LPCWSTR lpDeviceID OPTIONAL,
724 IN HDEVINFO DeviceInfoSet,
725 IN PSP_DEVINFO_DATA DeviceInfoData,
726 IN HINSTANCE hComCtl32,
727 IN LPCWSTR lpMachineName,
728 IN DWORD dwFlags)
729 {
730 PROPSHEETHEADER psh = {0};
731 PROPSHEETPAGE pspGeneral = {0};
732 DWORD nPropSheets = 0;
733 PPROPERTYSHEETW pPropertySheetW;
734 PCREATEPROPERTYSHEETPAGEW pCreatePropertySheetPageW;
735 PDESTROYPROPERTYSHEETPAGE pDestroyPropertySheetPage;
736 PDEVADVPROP_INFO DevAdvPropInfo;
737 HMACHINE hMachine = NULL;
738 DWORD DevIdSize = 0;
739 INT_PTR Ret = -1;
740
741 /* we don't want to statically link against comctl32, so find the
742 functions we need dynamically */
743 pPropertySheetW =
744 (PPROPERTYSHEETW)GetProcAddress(hComCtl32,
745 "PropertySheetW");
746 pCreatePropertySheetPageW =
747 (PCREATEPROPERTYSHEETPAGEW)GetProcAddress(hComCtl32,
748 "CreatePropertySheetPageW");
749 pDestroyPropertySheetPage =
750 (PDESTROYPROPERTYSHEETPAGE)GetProcAddress(hComCtl32,
751 "DestroyPropertySheetPage");
752 if (pPropertySheetW == NULL ||
753 pCreatePropertySheetPageW == NULL ||
754 pDestroyPropertySheetPage == NULL)
755 {
756 return -1;
757 }
758
759 if (lpDeviceID == NULL)
760 {
761 /* find out how much size is needed for the device id */
762 if (SetupDiGetDeviceInstanceId(DeviceInfoSet,
763 DeviceInfoData,
764 NULL,
765 0,
766 &DevIdSize))
767 {
768 DPRINT1("SetupDiGetDeviceInstanceId unexpectedly returned TRUE!\n");
769 return -1;
770 }
771
772 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
773 {
774 return -1;
775 }
776 }
777 else
778 {
779 DevIdSize = (DWORD)wcslen(lpDeviceID) + 1;
780 }
781
782 if (lpMachineName != NULL)
783 {
784 CONFIGRET cr = CM_Connect_Machine(lpMachineName,
785 &hMachine);
786 if (cr != CR_SUCCESS)
787 {
788 return -1;
789 }
790 }
791
792 /* create the internal structure associated with the "General",
793 "Driver", ... pages */
794 DevAdvPropInfo = HeapAlloc(GetProcessHeap(),
795 HEAP_ZERO_MEMORY,
796 FIELD_OFFSET(DEVADVPROP_INFO,
797 szDeviceID) +
798 (DevIdSize * sizeof(WCHAR)));
799 if (DevAdvPropInfo == NULL)
800 {
801 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
802 goto Cleanup;
803 }
804
805 if (lpDeviceID == NULL)
806 {
807 /* read the device instance id */
808 if (!SetupDiGetDeviceInstanceId(DeviceInfoSet,
809 DeviceInfoData,
810 DevAdvPropInfo->szDeviceID,
811 DevIdSize,
812 NULL))
813 {
814 goto Cleanup;
815 }
816 }
817 else
818 {
819 /* copy the device instance id supplied by the caller */
820 wcscpy(DevAdvPropInfo->szDeviceID,
821 lpDeviceID);
822 }
823
824 DevAdvPropInfo->DeviceInfoSet = DeviceInfoSet;
825 DevAdvPropInfo->DeviceInfoData = *DeviceInfoData;
826 DevAdvPropInfo->CurrentDeviceInfoSet = INVALID_HANDLE_VALUE;
827 DevAdvPropInfo->CurrentDeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
828
829 DevAdvPropInfo->hMachine = hMachine;
830 DevAdvPropInfo->lpMachineName = lpMachineName;
831 DevAdvPropInfo->szDevName[0] = L'\0';
832 DevAdvPropInfo->hComCtl32 = hComCtl32;
833
834 DevAdvPropInfo->IsAdmin = IsUserAdmin();
835 DevAdvPropInfo->DoDefaultDevAction = ((dwFlags & DPF_DEVICE_STATUS_ACTION) != 0);
836
837 psh.dwSize = sizeof(PROPSHEETHEADER);
838 psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
839 psh.hwndParent = hWndParent;
840 psh.pszCaption = DevAdvPropInfo->szDevName;
841
842 DevAdvPropInfo->PropertySheetType = lpMachineName != NULL ?
843 DIGCDP_FLAG_REMOTE_ADVANCED :
844 DIGCDP_FLAG_ADVANCED;
845
846 /* find out how many property sheets we need */
847 if (SetupDiGetClassDevPropertySheets(DeviceInfoSet,
848 &DevAdvPropInfo->DeviceInfoData,
849 &psh,
850 0,
851 &nPropSheets,
852 DevAdvPropInfo->PropertySheetType) &&
853 nPropSheets != 0)
854 {
855 DPRINT1("SetupDiGetClassDevPropertySheets unexpectedly returned TRUE!\n");
856 goto Cleanup;
857 }
858
859 if (nPropSheets != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
860 {
861 goto Cleanup;
862 }
863
864 psh.phpage = HeapAlloc(GetProcessHeap(),
865 HEAP_ZERO_MEMORY,
866 (nPropSheets + 1) * sizeof(HPROPSHEETPAGE));
867 if (psh.phpage == NULL)
868 {
869 goto Cleanup;
870 }
871
872 /* add the "General" property sheet */
873 pspGeneral.dwSize = sizeof(PROPSHEETPAGE);
874 pspGeneral.dwFlags = PSP_DEFAULT;
875 pspGeneral.hInstance = hDllInstance;
876 pspGeneral.pszTemplate = (LPCWSTR)MAKEINTRESOURCE(IDD_DEVICEGENERAL);
877 pspGeneral.pfnDlgProc = AdvPropGeneralDlgProc;
878 pspGeneral.lParam = (LPARAM)DevAdvPropInfo;
879 psh.phpage[0] = pCreatePropertySheetPageW(&pspGeneral);
880 if (psh.phpage[0] != NULL)
881 {
882 psh.nPages++;
883 }
884
885 DevAdvPropInfo->nDevPropSheets = nPropSheets;
886
887 if (nPropSheets != 0)
888 {
889 DevAdvPropInfo->DevPropSheets = psh.phpage + psh.nPages;
890
891 /* create the device property sheets */
892 if (!SetupDiGetClassDevPropertySheets(DeviceInfoSet,
893 &DevAdvPropInfo->DeviceInfoData,
894 &psh,
895 nPropSheets + psh.nPages,
896 NULL,
897 DevAdvPropInfo->PropertySheetType))
898 {
899 goto Cleanup;
900 }
901 }
902
903 /* FIXME - add the "Driver" property sheet if necessary */
904
905 if (psh.nPages != 0)
906 {
907 Ret = pPropertySheetW(&psh);
908
909 /* NOTE: no need to destroy the property sheets anymore! */
910 }
911 else
912 {
913 UINT i;
914
915 Cleanup:
916 /* in case of failure the property sheets must be destroyed */
917 if (psh.phpage != NULL)
918 {
919 for (i = 0;
920 i < psh.nPages;
921 i++)
922 {
923 if (psh.phpage[i] != NULL)
924 {
925 pDestroyPropertySheetPage(psh.phpage[i]);
926 }
927 }
928 }
929 }
930
931 if (DevAdvPropInfo != NULL)
932 {
933 if (DevAdvPropInfo->FreeDevPropSheets)
934 {
935 /* don't free the array if it's the one allocated in
936 DisplayDeviceAdvancedProperties */
937 HeapFree(GetProcessHeap(),
938 0,
939 DevAdvPropInfo->DevPropSheets);
940 }
941
942 if (DevAdvPropInfo->CloseDevInst)
943 {
944 /* close the device info set in case a new one was created */
945 SetupDiDestroyDeviceInfoList(DevAdvPropInfo->DeviceInfoSet);
946 }
947
948 if (DevAdvPropInfo->CurrentDeviceInfoSet != INVALID_HANDLE_VALUE)
949 {
950 SetupDiDestroyDeviceInfoList(DevAdvPropInfo->CurrentDeviceInfoSet);
951 }
952
953 HeapFree(GetProcessHeap(),
954 0,
955 DevAdvPropInfo);
956 }
957
958 if (psh.phpage != NULL)
959 {
960 HeapFree(GetProcessHeap(),
961 0,
962 psh.phpage);
963 }
964
965 if (hMachine != NULL)
966 {
967 CM_Disconnect_Machine(hMachine);
968 }
969
970 return Ret;
971 }
972
973
974 /***************************************************************************
975 * NAME EXPORTED
976 * DeviceAdvancedPropertiesW
977 *
978 * DESCRIPTION
979 * Invokes the device properties dialog, this version may add some property pages
980 * for some devices
981 *
982 * ARGUMENTS
983 * hWndParent: Handle to the parent window
984 * lpMachineName: Machine Name, NULL is the local machine
985 * lpDeviceID: Specifies the device whose properties are to be shown
986 *
987 * RETURN VALUE
988 * Always returns -1, a call to GetLastError returns 0 if successful
989 *
990 * @implemented
991 */
992 INT_PTR
993 WINAPI
994 DeviceAdvancedPropertiesW(IN HWND hWndParent OPTIONAL,
995 IN LPCWSTR lpMachineName OPTIONAL,
996 IN LPCWSTR lpDeviceID)
997 {
998 HDEVINFO hDevInfo;
999 SP_DEVINFO_DATA DevInfoData;
1000 HINSTANCE hComCtl32;
1001 INT_PTR Ret = -1;
1002
1003 if (lpDeviceID == NULL)
1004 {
1005 SetLastError(ERROR_INVALID_PARAMETER);
1006 return FALSE;
1007 }
1008
1009 /* dynamically load comctl32 */
1010 hComCtl32 = LoadAndInitComctl32();
1011 if (hComCtl32 != NULL)
1012 {
1013 hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
1014 hWndParent,
1015 lpMachineName,
1016 NULL);
1017 if (hDevInfo != INVALID_HANDLE_VALUE)
1018 {
1019 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1020 if (SetupDiOpenDeviceInfo(hDevInfo,
1021 lpDeviceID,
1022 hWndParent,
1023 0,
1024 &DevInfoData))
1025 {
1026 Ret = DisplayDeviceAdvancedProperties(hWndParent,
1027 lpDeviceID,
1028 hDevInfo,
1029 &DevInfoData,
1030 hComCtl32,
1031 lpMachineName,
1032 0);
1033 }
1034
1035 SetupDiDestroyDeviceInfoList(hDevInfo);
1036 }
1037
1038 FreeLibrary(hComCtl32);
1039 }
1040
1041 return Ret;
1042 }
1043
1044
1045 /***************************************************************************
1046 * NAME EXPORTED
1047 * DeviceAdvancedPropertiesA
1048 *
1049 * DESCRIPTION
1050 * Invokes the device properties dialog, this version may add some property pages
1051 * for some devices
1052 *
1053 * ARGUMENTS
1054 * hWndParent: Handle to the parent window
1055 * lpMachineName: Machine Name, NULL is the local machine
1056 * lpDeviceID: Specifies the device whose properties are to be shown
1057 *
1058 * RETURN VALUE
1059 * Always returns -1, a call to GetLastError returns 0 if successful
1060 *
1061 * @implemented
1062 */
1063 INT_PTR
1064 WINAPI
1065 DeviceAdvancedPropertiesA(IN HWND hWndParent OPTIONAL,
1066 IN LPCSTR lpMachineName OPTIONAL,
1067 IN LPCSTR lpDeviceID)
1068 {
1069 LPWSTR lpMachineNameW = NULL;
1070 LPWSTR lpDeviceIDW = NULL;
1071 INT_PTR Ret = -1;
1072
1073 if (lpMachineName != NULL)
1074 {
1075 if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
1076 CP_ACP)))
1077 {
1078 goto Cleanup;
1079 }
1080 }
1081 if (lpDeviceID != NULL)
1082 {
1083 if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
1084 CP_ACP)))
1085 {
1086 goto Cleanup;
1087 }
1088 }
1089
1090 Ret = DeviceAdvancedPropertiesW(hWndParent,
1091 lpMachineNameW,
1092 lpDeviceIDW);
1093
1094 Cleanup:
1095 if (lpMachineNameW != NULL)
1096 {
1097 HeapFree(GetProcessHeap(),
1098 0,
1099 lpMachineNameW);
1100 }
1101 if (lpDeviceIDW != NULL)
1102 {
1103 HeapFree(GetProcessHeap(),
1104 0,
1105 lpDeviceIDW);
1106 }
1107
1108 return Ret;
1109 }
1110
1111
1112 /***************************************************************************
1113 * NAME EXPORTED
1114 * DevicePropertiesExA
1115 *
1116 * DESCRIPTION
1117 * Invokes the extended device properties dialog
1118 *
1119 * ARGUMENTS
1120 * hWndParent: Handle to the parent window
1121 * lpMachineName: Machine Name, NULL is the local machine
1122 * lpDeviceID: Specifies the device whose properties are to be shown, optional if
1123 * bShowDevMgr is nonzero
1124 * dwFlags: This parameter can be a combination of the following flags:
1125 * * DPF_DEVICE_STATUS_ACTION: Only valid if bShowDevMgr, causes
1126 * the default device status action button
1127 * to be clicked (Troubleshoot, Enable
1128 * Device, etc)
1129 * bShowDevMgr: If non-zero it displays the device manager instead of
1130 * the advanced device property dialog
1131 *
1132 * RETURN VALUE
1133 * 1: if bShowDevMgr is non-zero and no error occured
1134 * -1: a call to GetLastError returns 0 if successful
1135 *
1136 * @implemented
1137 */
1138 INT_PTR
1139 WINAPI
1140 DevicePropertiesExA(IN HWND hWndParent OPTIONAL,
1141 IN LPCSTR lpMachineName OPTIONAL,
1142 IN LPCSTR lpDeviceID OPTIONAL,
1143 IN DWORD dwFlags OPTIONAL,
1144 IN BOOL bShowDevMgr)
1145 {
1146 LPWSTR lpMachineNameW = NULL;
1147 LPWSTR lpDeviceIDW = NULL;
1148 INT_PTR Ret = -1;
1149
1150 if (lpMachineName != NULL)
1151 {
1152 if (!(lpMachineNameW = ConvertMultiByteToUnicode(lpMachineName,
1153 CP_ACP)))
1154 {
1155 goto Cleanup;
1156 }
1157 }
1158 if (lpDeviceID != NULL)
1159 {
1160 if (!(lpDeviceIDW = ConvertMultiByteToUnicode(lpDeviceID,
1161 CP_ACP)))
1162 {
1163 goto Cleanup;
1164 }
1165 }
1166
1167 Ret = DevicePropertiesExW(hWndParent,
1168 lpMachineNameW,
1169 lpDeviceIDW,
1170 dwFlags,
1171 bShowDevMgr);
1172
1173 Cleanup:
1174 if (lpMachineNameW != NULL)
1175 {
1176 HeapFree(GetProcessHeap(),
1177 0,
1178 lpMachineNameW);
1179 }
1180 if (lpDeviceIDW != NULL)
1181 {
1182 HeapFree(GetProcessHeap(),
1183 0,
1184 lpDeviceIDW);
1185 }
1186
1187 return Ret;
1188 }
1189
1190
1191 /***************************************************************************
1192 * NAME EXPORTED
1193 * DevicePropertiesExW
1194 *
1195 * DESCRIPTION
1196 * Invokes the extended device properties dialog
1197 *
1198 * ARGUMENTS
1199 * hWndParent: Handle to the parent window
1200 * lpMachineName: Machine Name, NULL is the local machine
1201 * lpDeviceID: Specifies the device whose properties are to be shown, optional if
1202 * bShowDevMgr is nonzero
1203 * dwFlags: This parameter can be a combination of the following flags:
1204 * * DPF_DEVICE_STATUS_ACTION: Only valid if bShowDevMgr, causes
1205 * the default device status action button
1206 * to be clicked (Troubleshoot, Enable
1207 * Device, etc)
1208 * bShowDevMgr: If non-zero it displays the device manager instead of
1209 * the advanced device property dialog
1210 *
1211 * RETURN VALUE
1212 * 1: if bShowDevMgr is non-zero and no error occured
1213 * -1: a call to GetLastError returns 0 if successful
1214 *
1215 * @unimplemented
1216 */
1217 INT_PTR
1218 WINAPI
1219 DevicePropertiesExW(IN HWND hWndParent OPTIONAL,
1220 IN LPCWSTR lpMachineName OPTIONAL,
1221 IN LPCWSTR lpDeviceID OPTIONAL,
1222 IN DWORD dwFlags OPTIONAL,
1223 IN BOOL bShowDevMgr)
1224 {
1225 INT_PTR Ret = -1;
1226
1227 if (dwFlags & ~(DPF_UNKNOWN | DPF_DEVICE_STATUS_ACTION))
1228 {
1229 DPRINT1("DevPropertiesExW: Invalid flags: 0x%x\n",
1230 dwFlags & ~(DPF_UNKNOWN | DPF_DEVICE_STATUS_ACTION));
1231 SetLastError(ERROR_INVALID_FLAGS);
1232 return -1;
1233 }
1234
1235 if (bShowDevMgr)
1236 {
1237 DPRINT("DevPropertiesExW doesn't support bShowDevMgr!\n");
1238 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1239 }
1240 else
1241 {
1242 HDEVINFO hDevInfo;
1243 SP_DEVINFO_DATA DevInfoData;
1244 HINSTANCE hComCtl32;
1245
1246 if (lpDeviceID == NULL)
1247 {
1248 SetLastError(ERROR_INVALID_PARAMETER);
1249 return -1;
1250 }
1251
1252 /* dynamically load comctl32 */
1253 hComCtl32 = LoadAndInitComctl32();
1254 if (hComCtl32 != NULL)
1255 {
1256 hDevInfo = SetupDiCreateDeviceInfoListEx(NULL,
1257 hWndParent,
1258 lpMachineName,
1259 NULL);
1260 if (hDevInfo != INVALID_HANDLE_VALUE)
1261 {
1262 DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1263 if (SetupDiOpenDeviceInfo(hDevInfo,
1264 lpDeviceID,
1265 hWndParent,
1266 0,
1267 &DevInfoData))
1268 {
1269 Ret = DisplayDeviceAdvancedProperties(hWndParent,
1270 lpDeviceID,
1271 hDevInfo,
1272 &DevInfoData,
1273 hComCtl32,
1274 lpMachineName,
1275 dwFlags);
1276 }
1277
1278 SetupDiDestroyDeviceInfoList(hDevInfo);
1279 }
1280
1281 FreeLibrary(hComCtl32);
1282 }
1283 }
1284
1285 return Ret;
1286 }