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