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