688e2b5cfa284d6b294826a9b4e6eaa9d2cf46fe
[reactos.git] / reactos / lib / newdev / newdev.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS New devices installation
4 * FILE: lib/newdev/newdev.c
5 * PURPOSE: New devices installation
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
8 * PROGRAMMERS: Christoph von Wittich (Christoph@ActiveVB.de)
9 */
10
11 //#define NDEBUG
12 #include <debug.h>
13
14 #include "newdev.h"
15
16 static BOOL SearchDriver ( PDEVINSTDATA DevInstData, LPCTSTR Path );
17 static BOOL InstallDriver ( PDEVINSTDATA DevInstData );
18 static DWORD WINAPI FindDriverProc( LPVOID lpParam );
19 static BOOL FindDriver ( PDEVINSTDATA DevInstData );
20
21 static DEVINSTDATA DevInstData;
22 HINSTANCE hDllInstance;
23 HANDLE hThread;
24
25 BOOL
26 CanDisableDevice(IN DEVINST DevInst,
27 IN HMACHINE hMachine,
28 OUT BOOL *CanDisable)
29 {
30 CONFIGRET cr;
31 ULONG Status, ProblemNumber;
32 BOOL Ret = FALSE;
33
34 cr = CM_Get_DevNode_Status_Ex(&Status,
35 &ProblemNumber,
36 DevInst,
37 0,
38 hMachine);
39 if (cr == CR_SUCCESS)
40 {
41 *CanDisable = ((Status & DN_DISABLEABLE) != 0);
42 Ret = TRUE;
43 }
44
45 return Ret;
46 }
47
48
49 BOOL
50 IsDeviceEnabled(IN DEVINST DevInst,
51 IN HMACHINE hMachine,
52 OUT BOOL *IsEnabled)
53 {
54 CONFIGRET cr;
55 ULONG Status, ProblemNumber;
56 BOOL Ret = FALSE;
57
58 cr = CM_Get_DevNode_Status_Ex(&Status,
59 &ProblemNumber,
60 DevInst,
61 0,
62 hMachine);
63 if (cr == CR_SUCCESS)
64 {
65 *IsEnabled = ((Status & DN_STARTED) != 0);
66 Ret = TRUE;
67 }
68
69 return Ret;
70 }
71
72
73 BOOL
74 EnableDevice(IN HDEVINFO DeviceInfoSet,
75 IN PSP_DEVINFO_DATA DevInfoData OPTIONAL,
76 IN BOOL bEnable,
77 IN DWORD HardwareProfile OPTIONAL,
78 OUT BOOL *bNeedReboot OPTIONAL)
79 {
80 SP_PROPCHANGE_PARAMS pcp;
81 SP_DEVINSTALL_PARAMS dp;
82 DWORD LastErr;
83 BOOL Ret = FALSE;
84
85 pcp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
86 pcp.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
87 pcp.HwProfile = HardwareProfile;
88
89 if (bEnable)
90 {
91 /* try to enable the device on the global profile */
92 pcp.StateChange = DICS_ENABLE;
93 pcp.Scope = DICS_FLAG_GLOBAL;
94
95 /* ignore errors */
96 LastErr = GetLastError();
97 if (SetupDiSetClassInstallParams(DeviceInfoSet,
98 DevInfoData,
99 &pcp.ClassInstallHeader,
100 sizeof(SP_PROPCHANGE_PARAMS)))
101 {
102 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
103 DeviceInfoSet,
104 DevInfoData);
105 }
106 SetLastError(LastErr);
107 }
108
109 /* try config-specific */
110 pcp.StateChange = (bEnable ? DICS_ENABLE : DICS_DISABLE);
111 pcp.Scope = DICS_FLAG_CONFIGSPECIFIC;
112
113 if (SetupDiSetClassInstallParams(DeviceInfoSet,
114 DevInfoData,
115 &pcp.ClassInstallHeader,
116 sizeof(SP_PROPCHANGE_PARAMS)) &&
117 SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
118 DeviceInfoSet,
119 DevInfoData))
120 {
121 dp.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
122 if (SetupDiGetDeviceInstallParams(DeviceInfoSet,
123 DevInfoData,
124 &dp))
125 {
126 if (bNeedReboot != NULL)
127 {
128 *bNeedReboot = ((dp.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT)) != 0);
129 }
130
131 Ret = TRUE;
132 }
133 }
134 return Ret;
135 }
136
137 /*
138 * @unimplemented
139 */
140 BOOL WINAPI
141 UpdateDriverForPlugAndPlayDevicesW(
142 IN HWND hwndParent,
143 IN LPCWSTR HardwareId,
144 IN LPCWSTR FullInfPath,
145 IN DWORD InstallFlags,
146 OUT PBOOL bRebootRequired OPTIONAL)
147 {
148 UNIMPLEMENTED;
149 SetLastError(ERROR_GEN_FAILURE);
150 return FALSE;
151 }
152
153 /*
154 * @implemented
155 */
156 BOOL WINAPI
157 UpdateDriverForPlugAndPlayDevicesA(
158 IN HWND hwndParent,
159 IN LPCSTR HardwareId,
160 IN LPCSTR FullInfPath,
161 IN DWORD InstallFlags,
162 OUT PBOOL bRebootRequired OPTIONAL)
163 {
164 BOOL Result;
165 LPWSTR HardwareIdW = NULL;
166 LPWSTR FullInfPathW = NULL;
167
168 int len = MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, NULL, 0);
169 HardwareIdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
170 if (!HardwareIdW)
171 {
172 SetLastError(ERROR_GEN_FAILURE);
173 return FALSE;
174 }
175 MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, HardwareIdW, len);
176
177 len = MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, NULL, 0);
178 FullInfPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
179 if (!FullInfPathW)
180 {
181 HeapFree(GetProcessHeap(), 0, HardwareIdW);
182 SetLastError(ERROR_GEN_FAILURE);
183 return FALSE;
184 }
185 MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, FullInfPathW, len);
186
187 Result = UpdateDriverForPlugAndPlayDevicesW(hwndParent,
188 HardwareIdW,
189 FullInfPathW,
190 InstallFlags,
191 bRebootRequired);
192
193 HeapFree(GetProcessHeap(), 0, HardwareIdW);
194 HeapFree(GetProcessHeap(), 0, FullInfPathW);
195
196 return Result;
197 }
198
199
200 static HFONT
201 CreateTitleFont(VOID)
202 {
203 NONCLIENTMETRICS ncm;
204 LOGFONT LogFont;
205 HDC hdc;
206 INT FontSize;
207 HFONT hFont;
208
209 ncm.cbSize = sizeof(NONCLIENTMETRICS);
210 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
211
212 LogFont = ncm.lfMessageFont;
213 LogFont.lfWeight = FW_BOLD;
214 _tcscpy(LogFont.lfFaceName, _T("MS Shell Dlg"));
215
216 hdc = GetDC(NULL);
217 FontSize = 12;
218 LogFont.lfHeight = 0 - GetDeviceCaps (hdc, LOGPIXELSY) * FontSize / 72;
219 hFont = CreateFontIndirect(&LogFont);
220 ReleaseDC(NULL, hdc);
221
222 return hFont;
223 }
224
225 static VOID
226 CenterWindow(HWND hWnd)
227 {
228 HWND hWndParent;
229 RECT rcParent;
230 RECT rcWindow;
231
232 hWndParent = GetParent(hWnd);
233 if (hWndParent == NULL)
234 hWndParent = GetDesktopWindow();
235
236 GetWindowRect(hWndParent, &rcParent);
237 GetWindowRect(hWnd, &rcWindow);
238
239 SetWindowPos(hWnd,
240 HWND_TOP,
241 ((rcParent.right - rcParent.left) - (rcWindow.right - rcWindow.left)) / 2,
242 ((rcParent.bottom - rcParent.top) - (rcWindow.bottom - rcWindow.top)) / 2,
243 0,
244 0,
245 SWP_NOSIZE);
246 }
247
248 static INT_PTR CALLBACK
249 WelcomeDlgProc(
250 IN HWND hwndDlg,
251 IN UINT uMsg,
252 IN WPARAM wParam,
253 IN LPARAM lParam)
254 {
255
256 PDEVINSTDATA DevInstData;
257
258 /* Retrieve pointer to the global setup data */
259 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
260
261 switch (uMsg)
262 {
263 case WM_INITDIALOG:
264 {
265 HWND hwndControl;
266 DWORD dwStyle;
267
268 /* Get pointer to the global setup data */
269 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
270 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
271
272 hwndControl = GetParent(hwndDlg);
273
274 /* Center the wizard window */
275 CenterWindow (hwndControl);
276
277 /* Hide the system menu */
278 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
279 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
280
281 /* Set title font */
282 SendDlgItemMessage(hwndDlg,
283 IDC_WELCOMETITLE,
284 WM_SETFONT,
285 (WPARAM)DevInstData->hTitleFont,
286 (LPARAM)TRUE);
287
288 SendDlgItemMessage(hwndDlg,
289 IDC_DEVICE,
290 WM_SETTEXT,
291 0,
292 (LPARAM) DevInstData->buffer);
293
294 SendDlgItemMessage(hwndDlg,
295 IDC_RADIO_AUTO,
296 BM_SETCHECK,
297 (WPARAM) TRUE,
298 (LPARAM) 0);
299
300
301 }
302 break;
303
304
305 case WM_NOTIFY:
306 {
307 LPNMHDR lpnm = (LPNMHDR)lParam;
308
309 switch (lpnm->code)
310 {
311 case PSN_SETACTIVE:
312 /* Enable the Next button */
313 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
314 break;
315
316 case PSN_WIZNEXT:
317 /* Handle a Next button click, if necessary */
318
319 if (SendDlgItemMessage(hwndDlg, IDC_RADIO_AUTO, BM_GETCHECK, (WPARAM) 0, (LPARAM) 0) == BST_CHECKED)
320 PropSheet_SetCurSel(GetParent(hwndDlg), 0, IDD_SEARCHDRV);
321
322 break;
323
324 default:
325 break;
326 }
327 }
328 break;
329
330 default:
331 break;
332 }
333
334 return FALSE;
335 }
336
337 static INT_PTR CALLBACK
338 CHSourceDlgProc(
339 IN HWND hwndDlg,
340 IN UINT uMsg,
341 IN WPARAM wParam,
342 IN LPARAM lParam)
343 {
344
345 PDEVINSTDATA DevInstData;
346
347 /* Retrieve pointer to the global setup data */
348 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
349
350 switch (uMsg)
351 {
352 case WM_INITDIALOG:
353 {
354 HWND hwndControl;
355 DWORD dwStyle;
356
357 /* Get pointer to the global setup data */
358 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
359 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
360
361 hwndControl = GetParent(hwndDlg);
362
363 /* Center the wizard window */
364 CenterWindow (hwndControl);
365
366 /* Hide the system menu */
367 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
368 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
369
370 SendDlgItemMessage(hwndDlg,
371 IDC_RADIO_SEARCHHERE,
372 BM_SETCHECK,
373 (WPARAM) TRUE,
374 (LPARAM) 0);
375
376 }
377 break;
378
379
380 case WM_NOTIFY:
381 {
382 LPNMHDR lpnm = (LPNMHDR)lParam;
383
384 switch (lpnm->code)
385 {
386 case PSN_SETACTIVE:
387 /* Enable the Next and Back buttons */
388 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT | PSWIZB_BACK);
389 break;
390
391 case PSN_WIZNEXT:
392 /* Handle a Next button click, if necessary */
393 PropSheet_SetCurSel(GetParent(hwndDlg), 0, 4);
394 break;
395
396 default:
397 break;
398 }
399 }
400 break;
401
402 default:
403 break;
404 }
405
406 return FALSE;
407 }
408
409 static INT_PTR CALLBACK
410 SearchDrvDlgProc(
411 IN HWND hwndDlg,
412 IN UINT uMsg,
413 IN WPARAM wParam,
414 IN LPARAM lParam)
415 {
416
417 PDEVINSTDATA DevInstData;
418 DWORD dwThreadId;
419
420 /* Retrieve pointer to the global setup data */
421 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
422
423 switch (uMsg)
424 {
425 case WM_INITDIALOG:
426 {
427 HWND hwndControl;
428 DWORD dwStyle;
429
430 /* Get pointer to the global setup data */
431 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
432 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
433
434 DevInstData->hDialog = hwndDlg;
435 hwndControl = GetParent(hwndDlg);
436
437 /* Center the wizard window */
438 CenterWindow (hwndControl);
439
440 SendDlgItemMessage(hwndDlg,
441 IDC_DEVICE,
442 WM_SETTEXT,
443 0,
444 (LPARAM) DevInstData->buffer);
445
446 /* Hide the system menu */
447 dwStyle = GetWindowLong(hwndControl, GWL_STYLE);
448 SetWindowLong(hwndControl, GWL_STYLE, dwStyle & ~WS_SYSMENU);
449 }
450 break;
451
452 case WM_SEARCH_FINISHED:
453 {
454 CloseHandle(hThread);
455 hThread = 0;
456 if (wParam == 0)
457 PropSheet_SetCurSel(GetParent(hwndDlg), 0, IDD_NODRIVER);
458 else
459 PropSheet_SetCurSel(GetParent(hwndDlg), 0, IDD_FINISHPAGE);
460 break;
461 }
462 case WM_NOTIFY:
463 {
464 LPNMHDR lpnm = (LPNMHDR)lParam;
465
466 switch (lpnm->code)
467 {
468 case PSN_SETACTIVE:
469 PropSheet_SetWizButtons(GetParent(hwndDlg), !PSWIZB_NEXT | !PSWIZB_BACK);
470 hThread = CreateThread( NULL, 0, FindDriverProc, DevInstData, 0, &dwThreadId);
471 break;
472
473 case PSN_KILLACTIVE:
474 if (hThread != 0)
475 {
476 SetWindowLong ( hwndDlg, DWL_MSGRESULT, TRUE);
477 return TRUE;
478 }
479 break;
480 case PSN_WIZNEXT:
481 /* Handle a Next button click, if necessary */
482 break;
483
484 default:
485 break;
486 }
487 }
488 break;
489
490 default:
491 break;
492 }
493
494 return FALSE;
495 }
496
497 static DWORD WINAPI
498 FindDriverProc(
499 IN LPVOID lpParam)
500 {
501 TCHAR drive[] = {'?',':',0};
502 size_t nType;
503 DWORD dwDrives;
504 PDEVINSTDATA DevInstData;
505 DWORD config_flags;
506 UINT i = 1;
507
508 DevInstData = (PDEVINSTDATA)lpParam;
509
510 dwDrives = GetLogicalDrives();
511 for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++)
512 {
513 if (dwDrives & i)
514 {
515 nType = GetDriveType( drive );
516 if ((nType == DRIVE_CDROM))
517 //if ((nType == DRIVE_CDROM) || (nType == DRIVE_FIXED))
518 {
519 /* search for inf file */
520 if (SearchDriver ( DevInstData, drive ))
521 {
522 /* if we found a valid driver inf... */
523 if (FindDriver ( DevInstData ))
524 {
525 InstallDriver ( DevInstData );
526 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 1, 0);
527 return 0;
528 }
529 }
530 }
531 }
532 i <<= 1;
533 }
534
535 /* update device configuration */
536 if(SetupDiGetDeviceRegistryProperty(DevInstData->hDevInfo,
537 &DevInstData->devInfoData,
538 SPDRP_CONFIGFLAGS,
539 NULL,
540 (BYTE *)&config_flags,
541 sizeof(config_flags),
542 NULL))
543 {
544 config_flags |= CONFIGFLAG_FAILEDINSTALL;
545 SetupDiSetDeviceRegistryProperty(
546 DevInstData->hDevInfo,
547 &DevInstData->devInfoData,
548 SPDRP_CONFIGFLAGS,
549 NULL, 0 );
550 }
551
552 PostMessage(DevInstData->hDialog, WM_SEARCH_FINISHED, 0, 0);
553 return 0;
554 }
555
556 static INT_PTR CALLBACK
557 FinishDlgProc(
558 IN HWND hwndDlg,
559 IN UINT uMsg,
560 IN WPARAM wParam,
561 IN LPARAM lParam)
562 {
563
564 PDEVINSTDATA DevInstData;
565
566 /* Retrieve pointer to the global setup data */
567 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
568
569 switch (uMsg)
570 {
571 case WM_INITDIALOG:
572 {
573 HWND hwndControl;
574
575 /* Get pointer to the global setup data */
576 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
577 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
578
579 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
580 ShowWindow (hwndControl, SW_HIDE);
581 EnableWindow (hwndControl, FALSE);
582
583 SendDlgItemMessage(hwndDlg,
584 IDC_DEVICE,
585 WM_SETTEXT,
586 0,
587 (LPARAM) DevInstData->drvInfoData.Description);
588
589 /* Set title font */
590 SendDlgItemMessage(hwndDlg,
591 IDC_FINISHTITLE,
592 WM_SETFONT,
593 (WPARAM)DevInstData->hTitleFont,
594 (LPARAM)TRUE);
595 }
596 break;
597
598 case WM_NOTIFY:
599 {
600 LPNMHDR lpnm = (LPNMHDR)lParam;
601
602 switch (lpnm->code)
603 {
604 case PSN_SETACTIVE:
605 /* Enable the correct buttons on for the active page */
606 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH);
607 break;
608
609 case PSN_WIZBACK:
610 /* Handle a Back button click, if necessary */
611 break;
612
613 case PSN_WIZFINISH:
614 /* Handle a Finish button click, if necessary */
615 break;
616
617 default:
618 break;
619 }
620 }
621 break;
622
623 default:
624 break;
625 }
626
627 return FALSE;
628 }
629
630 static INT_PTR CALLBACK
631 InstFailDlgProc(
632 IN HWND hwndDlg,
633 IN UINT uMsg,
634 IN WPARAM wParam,
635 IN LPARAM lParam)
636 {
637
638 PDEVINSTDATA DevInstData;
639
640 /* Get pointer to the global setup data */
641 DevInstData = (PDEVINSTDATA)GetWindowLongPtr (hwndDlg, GWL_USERDATA);
642
643 switch (uMsg)
644 {
645 case WM_INITDIALOG:
646 {
647 HWND hwndControl;
648 BOOL DisableableDevice = FALSE;
649
650 DevInstData = (PDEVINSTDATA)((LPPROPSHEETPAGE)lParam)->lParam;
651 SetWindowLongPtr(hwndDlg, GWL_USERDATA, (DWORD_PTR)DevInstData);
652
653 hwndControl = GetDlgItem(GetParent(hwndDlg), IDCANCEL);
654 ShowWindow (hwndControl, SW_HIDE);
655 EnableWindow (hwndControl, FALSE);
656
657 /* Set title font */
658 SendDlgItemMessage(hwndDlg,
659 IDC_FINISHTITLE,
660 WM_SETFONT,
661 (WPARAM)DevInstData->hTitleFont,
662 (LPARAM)TRUE);
663
664 /* disable the "do not show this dialog anymore" checkbox
665 if the device cannot be disabled */
666 CanDisableDevice(DevInstData->devInfoData.DevInst,
667 NULL,
668 &DisableableDevice);
669 EnableWindow(GetDlgItem(hwndDlg,
670 IDC_DONOTSHOWDLG),
671 DisableableDevice);
672 }
673 break;
674
675 case WM_NOTIFY:
676 {
677 LPNMHDR lpnm = (LPNMHDR)lParam;
678
679 switch (lpnm->code)
680 {
681 case PSN_SETACTIVE:
682 /* Enable the correct buttons on for the active page */
683 PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH);
684 break;
685
686 case PSN_WIZBACK:
687 PropSheet_SetCurSel(GetParent(hwndDlg), 0, IDD_WELCOMEPAGE);
688 /* Handle a Back button click, if necessary */
689 break;
690
691 case PSN_WIZFINISH:
692 {
693 BOOL DisableableDevice = FALSE;
694 BOOL IsEnabled = FALSE;
695
696 if (CanDisableDevice(DevInstData->devInfoData.DevInst,
697 NULL,
698 &DisableableDevice) &&
699 DisableableDevice &&
700 IsDeviceEnabled(DevInstData->devInfoData.DevInst,
701 NULL,
702 &IsEnabled) &&
703 IsEnabled &&
704 SendDlgItemMessage(hwndDlg, IDC_DONOTSHOWDLG, BM_GETCHECK, (WPARAM) 0, (LPARAM) 0) == BST_CHECKED)
705 {
706 /* disable the device */
707 EnableDevice(DevInstData->hDevInfo,
708 &DevInstData->devInfoData,
709 FALSE,
710 0,
711 NULL);
712 }
713 break;
714 }
715
716 default:
717 break;
718 }
719 }
720 break;
721
722 default:
723 break;
724 }
725
726 return FALSE;
727 }
728
729
730 static BOOL
731 FindDriver(
732 IN PDEVINSTDATA DevInstData)
733 {
734
735 BOOL ret;
736
737 ret = SetupDiBuildDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER);
738 if (!ret)
739 {
740 DPRINT("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
741 return FALSE;
742 }
743
744 DevInstData->drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
745 ret = SetupDiEnumDriverInfo(
746 DevInstData->hDevInfo,
747 &DevInstData->devInfoData,
748 SPDIT_COMPATDRIVER,
749 0,
750 &DevInstData->drvInfoData);
751 if (!ret)
752 {
753 if (GetLastError() == ERROR_NO_MORE_ITEMS)
754 return FALSE;
755 DPRINT("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
756 return FALSE;
757 }
758 DPRINT("Installing driver %S: %S\n", DevInstData->drvInfoData.MfgName, DevInstData->drvInfoData.Description);
759
760 return TRUE;
761 }
762
763
764 static BOOL
765 IsDots(IN LPCTSTR str)
766 {
767 if(_tcscmp(str, _T(".")) && _tcscmp(str, _T(".."))) return FALSE;
768 return TRUE;
769 }
770
771 static LPTSTR
772 GetFileExt(IN LPTSTR FileName)
773 {
774 if (FileName == 0)
775 return _T("");
776
777 int i = _tcsclen(FileName);
778 while ((i >= 0) && (FileName[i] != _T('.')))
779 i--;
780
781 FileName = _tcslwr(FileName);
782
783 if (i >= 0)
784 return &FileName[i];
785 else
786 return _T("");
787 }
788
789 static BOOL
790 SearchDriver(
791 IN PDEVINSTDATA DevInstData,
792 IN LPCTSTR Path)
793 {
794 WIN32_FIND_DATA wfd;
795 SP_DEVINSTALL_PARAMS DevInstallParams;
796 TCHAR DirPath[MAX_PATH];
797 TCHAR FileName[MAX_PATH];
798 TCHAR FullPath[MAX_PATH];
799 TCHAR LastDirPath[MAX_PATH] = _T("");
800 TCHAR PathWithPattern[MAX_PATH];
801 BOOL ok = TRUE;
802 BOOL ret;
803 HANDLE hFindFile;
804
805 _tcscpy(DirPath, Path);
806
807 if (DirPath[_tcsclen(DirPath) - 1] != '\\')
808 _tcscat(DirPath, _T("\\"));
809
810 _tcscpy(PathWithPattern, DirPath);
811 _tcscat(PathWithPattern, _T("\\*"));
812
813 for (hFindFile = FindFirstFile(PathWithPattern, &wfd); ((hFindFile != INVALID_HANDLE_VALUE) && ok); ok = FindNextFile(hFindFile, &wfd))
814 {
815
816 _tcscpy(FileName, wfd.cFileName);
817 if (IsDots(FileName)) continue;
818
819 if((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
820 {
821 _tcscpy(FullPath, DirPath);
822 _tcscat(FullPath, FileName);
823 if(SearchDriver(DevInstData, FullPath))
824 break;
825 }
826 else
827 {
828 LPCTSTR pszExtension = GetFileExt(FileName);
829
830 if ((_tcscmp(pszExtension, _T(".inf")) == 0) && (_tcscmp(LastDirPath, DirPath) != 0))
831 {
832 _tcscpy(LastDirPath, DirPath);
833 ZeroMemory (&DevInstallParams, sizeof(SP_DEVINSTALL_PARAMS));
834 DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
835
836 ret = SetupDiGetDeviceInstallParams(
837 DevInstData->hDevInfo,
838 &DevInstData->devInfoData,
839 &DevInstallParams);
840
841 if (_tcsclen(DirPath) <= MAX_PATH)
842 {
843 memcpy(DevInstallParams.DriverPath, DirPath, (_tcsclen(DirPath) + 1) * sizeof(TCHAR));
844 }
845
846 ret = SetupDiSetDeviceInstallParams(
847 DevInstData->hDevInfo,
848 &DevInstData->devInfoData,
849 &DevInstallParams);
850
851 if ( FindDriver ( DevInstData ) )
852 {
853 if (hFindFile != INVALID_HANDLE_VALUE)
854 FindClose(hFindFile);
855 return TRUE;
856 }
857
858 }
859 }
860 }
861
862 if (hFindFile != INVALID_HANDLE_VALUE)
863 FindClose(hFindFile);
864
865 return FALSE;
866 }
867
868 static BOOL
869 InstallDriver(
870 IN PDEVINSTDATA DevInstData)
871 {
872
873 BOOL ret;
874
875 ret = SetupDiCallClassInstaller(
876 DIF_SELECTBESTCOMPATDRV,
877 DevInstData->hDevInfo,
878 &DevInstData->devInfoData);
879 if (!ret)
880 {
881 DPRINT("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%lx\n", GetLastError());
882 return FALSE;
883 }
884
885 ret = SetupDiCallClassInstaller(
886 DIF_ALLOW_INSTALL,
887 DevInstData->hDevInfo,
888 &DevInstData->devInfoData);
889 if (!ret)
890 {
891 DPRINT("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%lx\n", GetLastError());
892 return FALSE;
893 }
894
895 ret = SetupDiCallClassInstaller(
896 DIF_NEWDEVICEWIZARD_PREANALYZE,
897 DevInstData->hDevInfo,
898 &DevInstData->devInfoData);
899 if (!ret)
900 {
901 DPRINT("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%lx\n", GetLastError());
902 return FALSE;
903 }
904
905 ret = SetupDiCallClassInstaller(
906 DIF_NEWDEVICEWIZARD_POSTANALYZE,
907 DevInstData->hDevInfo,
908 &DevInstData->devInfoData);
909 if (!ret)
910 {
911 DPRINT("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%lx\n", GetLastError());
912 return FALSE;
913 }
914
915 ret = SetupDiCallClassInstaller(
916 DIF_INSTALLDEVICEFILES,
917 DevInstData->hDevInfo,
918 &DevInstData->devInfoData);
919 if (!ret)
920 {
921 DPRINT("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%lx\n", GetLastError());
922 return FALSE;
923 }
924
925 ret = SetupDiCallClassInstaller(
926 DIF_REGISTER_COINSTALLERS,
927 DevInstData->hDevInfo,
928 &DevInstData->devInfoData);
929 if (!ret)
930 {
931 DPRINT("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%lx\n", GetLastError());
932 return FALSE;
933 }
934
935 ret = SetupDiCallClassInstaller(
936 DIF_INSTALLINTERFACES,
937 DevInstData->hDevInfo,
938 &DevInstData->devInfoData);
939 if (!ret)
940 {
941 DPRINT("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%lx\n", GetLastError());
942 return FALSE;
943 }
944
945 ret = SetupDiCallClassInstaller(
946 DIF_INSTALLDEVICE,
947 DevInstData->hDevInfo,
948 &DevInstData->devInfoData);
949 if (!ret)
950 {
951 DPRINT("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%lx\n", GetLastError());
952 return FALSE;
953 }
954
955 ret = SetupDiCallClassInstaller(
956 DIF_NEWDEVICEWIZARD_FINISHINSTALL,
957 DevInstData->hDevInfo,
958 &DevInstData->devInfoData);
959 if (!ret)
960 {
961 DPRINT("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%lx\n", GetLastError());
962 return FALSE;
963 }
964
965 ret = SetupDiCallClassInstaller(
966 DIF_DESTROYPRIVATEDATA,
967 DevInstData->hDevInfo,
968 &DevInstData->devInfoData);
969 if (!ret)
970 {
971 DPRINT("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%lx\n", GetLastError());
972 return FALSE;
973 }
974
975 return TRUE;
976
977 }
978
979 static VOID
980 CleanUp(VOID)
981 {
982
983 if (DevInstData.devInfoData.cbSize != 0)
984 {
985 if (!SetupDiDestroyDriverInfoList(DevInstData.hDevInfo, &DevInstData.devInfoData, SPDIT_COMPATDRIVER))
986 DPRINT("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
987 }
988
989 if (DevInstData.hDevInfo != INVALID_HANDLE_VALUE)
990 {
991 if (!SetupDiDestroyDeviceInfoList(DevInstData.hDevInfo))
992 DPRINT("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
993 }
994
995 if (DevInstData.buffer)
996 HeapFree(GetProcessHeap(), 0, DevInstData.buffer);
997
998 }
999
1000 BOOL WINAPI
1001 DevInstallW(
1002 IN HWND hWndParent,
1003 IN HINSTANCE hInstance,
1004 IN LPCWSTR InstanceId,
1005 IN INT Show)
1006 {
1007
1008 PROPSHEETHEADER psh;
1009 HPROPSHEETPAGE ahpsp[5];
1010 PROPSHEETPAGE psp;
1011 BOOL ret;
1012 DWORD config_flags;
1013 /*TCHAR buf[128];*/
1014
1015 /* FIXME: Nov 2005. umpnpmgr.exe is directly calling DevInstallW in
1016 * SYSTEM context, which is not member of the Administrators group.
1017 * So, just ignore the test at the moment... */
1018 //if (!IsUserAdmin())
1019 //{
1020 // /* XP kills the process... */
1021 // ExitProcess(ERROR_ACCESS_DENIED);
1022 //}
1023
1024 /* Clear devinst data */
1025 ZeroMemory(&DevInstData, sizeof(DEVINSTDATA));
1026 DevInstData.devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
1027
1028
1029 DevInstData.hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
1030 if (DevInstData.hDevInfo == INVALID_HANDLE_VALUE)
1031 {
1032 DPRINT("SetupDiCreateDeviceInfoListExW() failed with error 0x%lx\n", GetLastError());
1033 CleanUp();
1034 return FALSE;
1035 }
1036
1037 DevInstData.devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
1038 ret = SetupDiOpenDeviceInfoW(
1039 DevInstData.hDevInfo,
1040 InstanceId,
1041 NULL,
1042 0, /* Open flags */
1043 &DevInstData.devInfoData);
1044 if (!ret)
1045 {
1046 DPRINT("SetupDiOpenDeviceInfoW() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId);
1047 DevInstData.devInfoData.cbSize = 0;
1048 CleanUp();
1049 return FALSE;
1050 }
1051
1052 SetLastError(ERROR_GEN_FAILURE);
1053 ret = SetupDiGetDeviceRegistryProperty(
1054 DevInstData.hDevInfo,
1055 &DevInstData.devInfoData,
1056 SPDRP_DEVICEDESC,
1057 &DevInstData.regDataType,
1058 NULL, 0,
1059 &DevInstData.requiredSize);
1060
1061 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData.regDataType == REG_SZ)
1062 {
1063 DevInstData.buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData.requiredSize);
1064 if (!DevInstData.buffer)
1065 {
1066 DPRINT("HeapAlloc() failed\n");
1067 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1068 }
1069 else
1070 {
1071 ret = SetupDiGetDeviceRegistryProperty(
1072 DevInstData.hDevInfo,
1073 &DevInstData.devInfoData,
1074 SPDRP_DEVICEDESC,
1075 &DevInstData.regDataType,
1076 DevInstData.buffer, DevInstData.requiredSize,
1077 &DevInstData.requiredSize);
1078 }
1079 }
1080 if (!ret)
1081 {
1082 DPRINT("SetupDiGetDeviceRegistryProperty() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId);
1083 CleanUp();
1084 return FALSE;
1085 }
1086
1087 if(SetupDiGetDeviceRegistryProperty(DevInstData.hDevInfo,
1088 &DevInstData.devInfoData,
1089 SPDRP_CONFIGFLAGS,
1090 NULL,
1091 (BYTE *)&config_flags,
1092 sizeof(config_flags),
1093 NULL))
1094 {
1095 if (config_flags & CONFIGFLAG_FAILEDINSTALL)
1096 {
1097 CleanUp();
1098 return TRUE;
1099 }
1100 }
1101 /*
1102 else
1103 {
1104 swprintf(buf, _T("%ld"), GetLastError());
1105 MessageBox(0,buf,buf,0);
1106 }
1107 */
1108
1109 DPRINT("Installing %S (%S)\n", DevInstData.buffer, InstanceId);
1110
1111 if ((!FindDriver(&DevInstData)) && (Show != SW_HIDE))
1112 {
1113
1114 /* Create the Welcome page */
1115 ZeroMemory (&psp, sizeof(PROPSHEETPAGE));
1116 psp.dwSize = sizeof(PROPSHEETPAGE);
1117 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1118 psp.hInstance = hDllInstance;
1119 psp.lParam = (LPARAM)&DevInstData;
1120 psp.pfnDlgProc = WelcomeDlgProc;
1121 psp.pszTemplate = MAKEINTRESOURCE(IDD_WELCOMEPAGE);
1122 ahpsp[IDD_WELCOMEPAGE] = CreatePropertySheetPage(&psp);
1123
1124 /* Create the Select Source page */
1125 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
1126 psp.pfnDlgProc = CHSourceDlgProc;
1127 psp.pszTemplate = MAKEINTRESOURCE(IDD_CHSOURCE);
1128 ahpsp[IDD_CHSOURCE] = CreatePropertySheetPage(&psp);
1129
1130 /* Create the Search driver page */
1131 psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
1132 psp.pfnDlgProc = SearchDrvDlgProc;
1133 psp.pszTemplate = MAKEINTRESOURCE(IDD_SEARCHDRV);
1134 ahpsp[IDD_SEARCHDRV] = CreatePropertySheetPage(&psp);
1135
1136 /* Create the Finish page */
1137 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1138 psp.pfnDlgProc = FinishDlgProc;
1139 psp.pszTemplate = MAKEINTRESOURCE(IDD_FINISHPAGE);
1140 ahpsp[IDD_FINISHPAGE] = CreatePropertySheetPage(&psp);
1141
1142 /* Create the Install failed page */
1143 psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
1144 psp.pfnDlgProc = InstFailDlgProc;
1145 psp.pszTemplate = MAKEINTRESOURCE(IDD_NODRIVER);
1146 ahpsp[IDD_NODRIVER] = CreatePropertySheetPage(&psp);
1147
1148 /* Create the property sheet */
1149 psh.dwSize = sizeof(PROPSHEETHEADER);
1150 psh.dwFlags = PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER;
1151 psh.hInstance = hDllInstance;
1152 psh.hwndParent = NULL;
1153 psh.nPages = 5;
1154 psh.nStartPage = 0;
1155 psh.phpage = ahpsp;
1156 psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
1157 psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER);
1158
1159 /* Create title font */
1160 DevInstData.hTitleFont = CreateTitleFont();
1161
1162 /* Display the wizard */
1163 PropertySheet(&psh);
1164
1165 DeleteObject(DevInstData.hTitleFont);
1166
1167 }
1168 else
1169 {
1170 InstallDriver ( &DevInstData );
1171 }
1172
1173 CleanUp();
1174 return TRUE;
1175 }
1176
1177 BOOL WINAPI
1178 ClientSideInstallW(IN HWND hWndOwner,
1179 IN DWORD dwUnknownFlags,
1180 IN LPWSTR lpNamedPipeName)
1181 {
1182 /* NOTE: pNamedPipeName is in the format:
1183 * "\\.\pipe\PNP_Device_Install_Pipe_0.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
1184 */
1185 return FALSE;
1186 }
1187
1188 BOOL WINAPI
1189 DllMain(
1190 IN HINSTANCE hInstance,
1191 IN DWORD dwReason,
1192 IN LPVOID lpReserved)
1193 {
1194 if (dwReason == DLL_PROCESS_ATTACH)
1195 {
1196 INITCOMMONCONTROLSEX InitControls;
1197
1198 DisableThreadLibraryCalls(hInstance);
1199
1200 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
1201 InitControls.dwICC = ICC_PROGRESS_CLASS;
1202 InitCommonControlsEx(&InitControls);
1203 hDllInstance = hInstance;
1204 }
1205
1206 return TRUE;
1207 }