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