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