2 * New device installer (newdev.dll)
4 * Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
5 * 2005 Christoph von Wittich (Christoph@ActiveVB.de)
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.
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.
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
25 WINE_DEFAULT_DEBUG_CHANNEL(newdev
);
27 /* Global variables */
28 HINSTANCE hDllInstance
;
34 UpdateDriverForPlugAndPlayDevicesW(
36 IN LPCWSTR HardwareId
,
37 IN LPCWSTR FullInfPath
,
38 IN DWORD InstallFlags
,
39 OUT PBOOL bRebootRequired OPTIONAL
)
41 DEVINSTDATA DevInstData
;
45 LPCWSTR CurrentHardwareId
; /* Pointer into Buffer */
46 BOOL FoundHardwareId
, FoundAtLeastOneDevice
= FALSE
;
49 DevInstData
.hDevInfo
= INVALID_HANDLE_VALUE
;
51 TRACE("UpdateDriverForPlugAndPlayDevicesW(%p %S %S 0x%lx %p)\n",
52 hwndParent
, HardwareId
, FullInfPath
, InstallFlags
, bRebootRequired
);
54 /* FIXME: InstallFlags bRebootRequired ignored! */
57 /* FIXME: if (InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE))
59 DPRINT("Unknown flags: 0x%08lx\n", InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE));
60 SetLastError(ERROR_INVALID_FLAGS);
64 /* Enumerate all devices of the system */
65 DevInstData
.hDevInfo
= SetupDiGetClassDevsW(NULL
, NULL
, hwndParent
, DIGCF_ALLCLASSES
| DIGCF_PRESENT
);
66 if (DevInstData
.hDevInfo
== INVALID_HANDLE_VALUE
)
68 DevInstData
.devInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
71 if (!SetupDiEnumDeviceInfo(DevInstData
.hDevInfo
, i
, &DevInstData
.devInfoData
))
73 if (GetLastError() != ERROR_NO_MORE_ITEMS
)
75 TRACE("SetupDiEnumDeviceInfo() failed with error 0x%lx\n", GetLastError());
78 /* This error was expected */
83 HeapFree(GetProcessHeap(), 0, Buffer
);
86 while (!SetupDiGetDeviceRegistryPropertyW(
88 &DevInstData
.devInfoData
,
95 if (GetLastError() == ERROR_FILE_NOT_FOUND
)
100 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
102 TRACE("SetupDiGetDeviceRegistryPropertyW() failed with error 0x%lx\n", GetLastError());
105 /* This error was expected */
106 HeapFree(GetProcessHeap(), 0, Buffer
);
107 Buffer
= HeapAlloc(GetProcessHeap(), 0, BufferSize
);
110 TRACE("HeapAlloc() failed\n", GetLastError());
111 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
118 /* Check if we match the given hardware ID */
119 FoundHardwareId
= FALSE
;
120 for (CurrentHardwareId
= Buffer
; *CurrentHardwareId
!= UNICODE_NULL
; CurrentHardwareId
+= wcslen(CurrentHardwareId
) + 1)
122 if (wcscmp(CurrentHardwareId
, HardwareId
) == 0)
124 FoundHardwareId
= TRUE
;
128 if (!FoundHardwareId
)
131 /* We need to try to update the driver of this device */
133 /* Get Instance ID */
134 HeapFree(GetProcessHeap(), 0, Buffer
);
136 if (SetupDiGetDeviceInstanceIdW(DevInstData
.hDevInfo
, &DevInstData
.devInfoData
, NULL
, 0, &BufferSize
))
138 /* Error, as the output buffer should be too small */
139 SetLastError(ERROR_GEN_FAILURE
);
142 else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
144 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", GetLastError());
147 else if ((Buffer
= HeapAlloc(GetProcessHeap(), 0, BufferSize
)) == NULL
)
149 TRACE("HeapAlloc() failed\n", GetLastError());
150 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
153 else if (!SetupDiGetDeviceInstanceIdW(DevInstData
.hDevInfo
, &DevInstData
.devInfoData
, Buffer
, BufferSize
, NULL
))
155 TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%lx\n", GetLastError());
158 TRACE("Trying to update the driver of %S\n", Buffer
);
160 /* Search driver in the specified .inf file */
161 if (!SearchDriver(&DevInstData
, NULL
, FullInfPath
))
163 TRACE("SearchDriver() failed with error 0x%lx\n", GetLastError());
167 /* FIXME: HACK! We shouldn't check of ERROR_PRIVILEGE_NOT_HELD */
168 //if (!InstallCurrentDriver(&DevInstData))
169 if (!InstallCurrentDriver(&DevInstData
) && GetLastError() != ERROR_PRIVILEGE_NOT_HELD
)
171 TRACE("InstallCurrentDriver() failed with error 0x%lx\n", GetLastError());
175 FoundAtLeastOneDevice
= TRUE
;
178 if (FoundAtLeastOneDevice
)
180 SetLastError(NO_ERROR
);
185 TRACE("No device found with HardwareID %S\n", HardwareId
);
186 SetLastError(ERROR_NO_SUCH_DEVINST
);
190 if (DevInstData
.hDevInfo
!= INVALID_HANDLE_VALUE
)
191 SetupDiDestroyDeviceInfoList(DevInstData
.hDevInfo
);
192 HeapFree(GetProcessHeap(), 0, Buffer
);
200 UpdateDriverForPlugAndPlayDevicesA(
202 IN LPCSTR HardwareId
,
203 IN LPCSTR FullInfPath
,
204 IN DWORD InstallFlags
,
205 OUT PBOOL bRebootRequired OPTIONAL
)
208 LPWSTR HardwareIdW
= NULL
;
209 LPWSTR FullInfPathW
= NULL
;
211 int len
= MultiByteToWideChar(CP_ACP
, 0, HardwareId
, -1, NULL
, 0);
212 HardwareIdW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
215 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
218 MultiByteToWideChar(CP_ACP
, 0, HardwareId
, -1, HardwareIdW
, len
);
220 len
= MultiByteToWideChar(CP_ACP
, 0, FullInfPath
, -1, NULL
, 0);
221 FullInfPathW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
224 HeapFree(GetProcessHeap(), 0, HardwareIdW
);
225 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
228 MultiByteToWideChar(CP_ACP
, 0, FullInfPath
, -1, FullInfPathW
, len
);
230 Result
= UpdateDriverForPlugAndPlayDevicesW(
237 HeapFree(GetProcessHeap(), 0, HardwareIdW
);
238 HeapFree(GetProcessHeap(), 0, FullInfPathW
);
243 /* Directory and InfFile MUST NOT be specified simultaneously */
246 IN PDEVINSTDATA DevInstData
,
247 IN LPCTSTR Directory OPTIONAL
,
248 IN LPCTSTR InfFile OPTIONAL
)
250 SP_DEVINSTALL_PARAMS DevInstallParams
= {0,};
253 DevInstallParams
.cbSize
= sizeof(SP_DEVINSTALL_PARAMS
);
254 if (!SetupDiGetDeviceInstallParams(DevInstData
->hDevInfo
, &DevInstData
->devInfoData
, &DevInstallParams
))
256 TRACE("SetupDiGetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
259 DevInstallParams
.FlagsEx
|= DI_FLAGSEX_ALLOWEXCLUDEDDRVS
;
263 DevInstallParams
.Flags
|= DI_ENUMSINGLEINF
;
264 _tcsncpy(DevInstallParams
.DriverPath
, InfFile
, MAX_PATH
);
268 DevInstallParams
.Flags
&= ~DI_ENUMSINGLEINF
;
269 _tcsncpy(DevInstallParams
.DriverPath
, Directory
, MAX_PATH
);
272 *DevInstallParams
.DriverPath
= _T('\0');
274 ret
= SetupDiSetDeviceInstallParams(
275 DevInstData
->hDevInfo
,
276 &DevInstData
->devInfoData
,
280 TRACE("SetupDiSetDeviceInstallParams() failed with error 0x%lx\n", GetLastError());
284 ret
= SetupDiBuildDriverInfoList(
285 DevInstData
->hDevInfo
,
286 &DevInstData
->devInfoData
,
290 TRACE("SetupDiBuildDriverInfoList() failed with error 0x%lx\n", GetLastError());
294 DevInstData
->drvInfoData
.cbSize
= sizeof(SP_DRVINFO_DATA
);
295 ret
= SetupDiEnumDriverInfo(
296 DevInstData
->hDevInfo
,
297 &DevInstData
->devInfoData
,
300 &DevInstData
->drvInfoData
);
303 if (GetLastError() == ERROR_NO_MORE_ITEMS
)
305 TRACE("SetupDiEnumDriverInfo() failed with error 0x%lx\n", GetLastError());
313 IsDots(IN LPCTSTR str
)
315 if(_tcscmp(str
, _T(".")) && _tcscmp(str
, _T(".."))) return FALSE
;
320 GetFileExt(IN LPTSTR FileName
)
325 int i
= _tcsclen(FileName
);
326 while ((i
>= 0) && (FileName
[i
] != _T('.')))
329 FileName
= _tcslwr(FileName
);
338 SearchDriverRecursive(
339 IN PDEVINSTDATA DevInstData
,
343 TCHAR DirPath
[MAX_PATH
];
344 TCHAR FileName
[MAX_PATH
];
345 TCHAR FullPath
[MAX_PATH
];
346 TCHAR LastDirPath
[MAX_PATH
] = _T("");
347 TCHAR PathWithPattern
[MAX_PATH
];
350 HANDLE hFindFile
= INVALID_HANDLE_VALUE
;
352 _tcscpy(DirPath
, Path
);
354 if (DirPath
[_tcsclen(DirPath
) - 1] != '\\')
355 _tcscat(DirPath
, _T("\\"));
357 _tcscpy(PathWithPattern
, DirPath
);
358 _tcscat(PathWithPattern
, _T("\\*"));
360 for (hFindFile
= FindFirstFile(PathWithPattern
, &wfd
);
361 ok
&& hFindFile
!= INVALID_HANDLE_VALUE
;
362 ok
= FindNextFile(hFindFile
, &wfd
))
365 _tcscpy(FileName
, wfd
.cFileName
);
366 if (IsDots(FileName
))
369 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
371 /* Recursive search */
372 _tcscpy(FullPath
, DirPath
);
373 _tcscat(FullPath
, FileName
);
374 if (SearchDriverRecursive(DevInstData
, FullPath
))
382 LPCTSTR pszExtension
= GetFileExt(FileName
);
384 if ((_tcscmp(pszExtension
, _T(".inf")) == 0) && (_tcscmp(LastDirPath
, DirPath
) != 0))
386 _tcscpy(LastDirPath
, DirPath
);
388 if (_tcsclen(DirPath
) > MAX_PATH
)
389 /* Path is too long to be searched */
392 if (SearchDriver(DevInstData
, DirPath
, NULL
))
403 if (hFindFile
!= INVALID_HANDLE_VALUE
)
404 FindClose(hFindFile
);
409 InstallCurrentDriver(
410 IN PDEVINSTDATA DevInstData
)
414 TRACE("Installing driver %S: %S\n", DevInstData
->drvInfoData
.MfgName
, DevInstData
->drvInfoData
.Description
);
416 ret
= SetupDiCallClassInstaller(
417 DIF_SELECTBESTCOMPATDRV
,
418 DevInstData
->hDevInfo
,
419 &DevInstData
->devInfoData
);
422 TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%lx\n", GetLastError());
426 ret
= SetupDiCallClassInstaller(
428 DevInstData
->hDevInfo
,
429 &DevInstData
->devInfoData
);
432 TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%lx\n", GetLastError());
436 ret
= SetupDiCallClassInstaller(
437 DIF_NEWDEVICEWIZARD_PREANALYZE
,
438 DevInstData
->hDevInfo
,
439 &DevInstData
->devInfoData
);
442 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%lx\n", GetLastError());
446 ret
= SetupDiCallClassInstaller(
447 DIF_NEWDEVICEWIZARD_POSTANALYZE
,
448 DevInstData
->hDevInfo
,
449 &DevInstData
->devInfoData
);
452 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%lx\n", GetLastError());
456 ret
= SetupDiCallClassInstaller(
457 DIF_INSTALLDEVICEFILES
,
458 DevInstData
->hDevInfo
,
459 &DevInstData
->devInfoData
);
462 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%lx\n", GetLastError());
466 ret
= SetupDiCallClassInstaller(
467 DIF_REGISTER_COINSTALLERS
,
468 DevInstData
->hDevInfo
,
469 &DevInstData
->devInfoData
);
472 TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%lx\n", GetLastError());
476 ret
= SetupDiCallClassInstaller(
477 DIF_INSTALLINTERFACES
,
478 DevInstData
->hDevInfo
,
479 &DevInstData
->devInfoData
);
482 TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%lx\n", GetLastError());
486 ret
= SetupDiCallClassInstaller(
488 DevInstData
->hDevInfo
,
489 &DevInstData
->devInfoData
);
492 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%lx\n", GetLastError());
496 ret
= SetupDiCallClassInstaller(
497 DIF_NEWDEVICEWIZARD_FINISHINSTALL
,
498 DevInstData
->hDevInfo
,
499 &DevInstData
->devInfoData
);
502 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%lx\n", GetLastError());
506 ret
= SetupDiCallClassInstaller(
507 DIF_DESTROYPRIVATEDATA
,
508 DevInstData
->hDevInfo
,
509 &DevInstData
->devInfoData
);
512 TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%lx\n", GetLastError());
525 IN HINSTANCE hInstance
,
526 IN LPCWSTR InstanceId
,
529 PDEVINSTDATA DevInstData
= NULL
;
536 /* XP kills the process... */
537 ExitProcess(ERROR_ACCESS_DENIED
);
540 DevInstData
= HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA
));
543 TRACE("HeapAlloc() failed\n");
544 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
548 /* Clear devinst data */
549 ZeroMemory(DevInstData
, sizeof(DEVINSTDATA
));
550 DevInstData
->devInfoData
.cbSize
= 0; /* Tell if the devInfoData is valid */
552 /* Fill devinst data */
553 DevInstData
->hDevInfo
= SetupDiCreateDeviceInfoListExW(NULL
, NULL
, NULL
, NULL
);
554 if (DevInstData
->hDevInfo
== INVALID_HANDLE_VALUE
)
556 TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%lx\n", GetLastError());
560 DevInstData
->devInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
561 ret
= SetupDiOpenDeviceInfoW(
562 DevInstData
->hDevInfo
,
566 &DevInstData
->devInfoData
);
569 TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId
);
570 DevInstData
->devInfoData
.cbSize
= 0;
574 SetLastError(ERROR_GEN_FAILURE
);
575 ret
= SetupDiGetDeviceRegistryProperty(
576 DevInstData
->hDevInfo
,
577 &DevInstData
->devInfoData
,
579 &DevInstData
->regDataType
,
581 &DevInstData
->requiredSize
);
583 if (!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
&& DevInstData
->regDataType
== REG_SZ
)
585 DevInstData
->buffer
= HeapAlloc(GetProcessHeap(), 0, DevInstData
->requiredSize
);
586 if (!DevInstData
->buffer
)
588 TRACE("HeapAlloc() failed\n");
589 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
593 ret
= SetupDiGetDeviceRegistryProperty(
594 DevInstData
->hDevInfo
,
595 &DevInstData
->devInfoData
,
597 &DevInstData
->regDataType
,
598 DevInstData
->buffer
, DevInstData
->requiredSize
,
599 &DevInstData
->requiredSize
);
604 TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId
);
608 if (SetupDiGetDeviceRegistryProperty(
609 DevInstData
->hDevInfo
,
610 &DevInstData
->devInfoData
,
613 (BYTE
*)&config_flags
,
614 sizeof(config_flags
),
617 if (config_flags
& CONFIGFLAG_FAILEDINSTALL
)
619 /* The device is disabled */
625 TRACE("Installing %S (%S)\n", DevInstData
->buffer
, InstanceId
);
627 /* Search driver in default location */
628 if (SearchDriver(DevInstData
, NULL
, NULL
))
630 /* Driver found ; install it */
631 retval
= InstallCurrentDriver(DevInstData
);
634 else if (Show
== SW_HIDE
)
636 /* We can't show the wizard. Fail the install */
640 /* Prepare the wizard, and display it */
641 retval
= DisplayWizard(DevInstData
, hWndParent
, IDD_WELCOMEPAGE
);
646 if (DevInstData
->devInfoData
.cbSize
!= 0)
648 if (!SetupDiDestroyDriverInfoList(DevInstData
->hDevInfo
, &DevInstData
->devInfoData
, SPDIT_COMPATDRIVER
))
649 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
651 if (DevInstData
->hDevInfo
!= INVALID_HANDLE_VALUE
)
653 if (!SetupDiDestroyDeviceInfoList(DevInstData
->hDevInfo
))
654 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
656 HeapFree(GetProcessHeap(), 0, DevInstData
->buffer
);
657 HeapFree(GetProcessHeap(), 0, DevInstData
);
669 IN DWORD dwUnknownFlags
,
670 IN LPWSTR lpNamedPipeName
)
672 /* NOTE: pNamedPipeName is in the format:
673 * "\\.\pipe\PNP_Device_Install_Pipe_0.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
681 IN HINSTANCE hInstance
,
683 IN LPVOID lpReserved
)
685 if (dwReason
== DLL_PROCESS_ATTACH
)
687 INITCOMMONCONTROLSEX InitControls
;
689 DisableThreadLibraryCalls(hInstance
);
691 InitControls
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
692 InitControls
.dwICC
= ICC_PROGRESS_CLASS
;
693 InitCommonControlsEx(&InitControls
);
694 hDllInstance
= hInstance
;