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());
314 IsDots(IN LPCTSTR str
)
316 if(_tcscmp(str
, _T(".")) && _tcscmp(str
, _T(".."))) return FALSE
;
321 GetFileExt(IN LPTSTR FileName
)
326 int i
= _tcsclen(FileName
);
327 while ((i
>= 0) && (FileName
[i
] != _T('.')))
330 FileName
= _tcslwr(FileName
);
339 SearchDriverRecursive(
340 IN PDEVINSTDATA DevInstData
,
344 TCHAR DirPath
[MAX_PATH
];
345 TCHAR FileName
[MAX_PATH
];
346 TCHAR FullPath
[MAX_PATH
];
347 TCHAR LastDirPath
[MAX_PATH
] = _T("");
348 TCHAR PathWithPattern
[MAX_PATH
];
351 HANDLE hFindFile
= INVALID_HANDLE_VALUE
;
353 TRACE("SearchDriverRecursive(%s)\n", Path
);
354 _tcscpy(DirPath
, Path
);
356 if (DirPath
[_tcsclen(DirPath
) - 1] != '\\')
357 _tcscat(DirPath
, _T("\\"));
359 _tcscpy(PathWithPattern
, DirPath
);
360 _tcscat(PathWithPattern
, _T("\\*"));
362 for (hFindFile
= FindFirstFile(PathWithPattern
, &wfd
);
363 ok
&& hFindFile
!= INVALID_HANDLE_VALUE
;
364 ok
= FindNextFile(hFindFile
, &wfd
))
367 _tcscpy(FileName
, wfd
.cFileName
);
368 if (IsDots(FileName
))
371 if (wfd
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
373 /* Recursive search */
374 _tcscpy(FullPath
, DirPath
);
375 _tcscat(FullPath
, FileName
);
376 if (SearchDriverRecursive(DevInstData
, FullPath
))
381 LPCTSTR pszExtension
= GetFileExt(FileName
);
383 if ((_tcscmp(pszExtension
, _T(".inf")) == 0) && (_tcscmp(LastDirPath
, DirPath
) != 0))
385 _tcscpy(LastDirPath
, DirPath
);
387 if (_tcsclen(DirPath
) > MAX_PATH
)
388 /* Path is too long to be searched */
391 if (SearchDriver(DevInstData
, DirPath
, NULL
))
402 if (hFindFile
!= INVALID_HANDLE_VALUE
)
403 FindClose(hFindFile
);
408 InstallCurrentDriver(
409 IN PDEVINSTDATA DevInstData
)
413 TRACE("Installing driver %S: %S\n", DevInstData
->drvInfoData
.MfgName
, DevInstData
->drvInfoData
.Description
);
415 ret
= SetupDiCallClassInstaller(
416 DIF_SELECTBESTCOMPATDRV
,
417 DevInstData
->hDevInfo
,
418 &DevInstData
->devInfoData
);
421 TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%lx\n", GetLastError());
425 ret
= SetupDiCallClassInstaller(
427 DevInstData
->hDevInfo
,
428 &DevInstData
->devInfoData
);
431 TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%lx\n", GetLastError());
435 ret
= SetupDiCallClassInstaller(
436 DIF_NEWDEVICEWIZARD_PREANALYZE
,
437 DevInstData
->hDevInfo
,
438 &DevInstData
->devInfoData
);
441 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%lx\n", GetLastError());
445 ret
= SetupDiCallClassInstaller(
446 DIF_NEWDEVICEWIZARD_POSTANALYZE
,
447 DevInstData
->hDevInfo
,
448 &DevInstData
->devInfoData
);
451 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%lx\n", GetLastError());
455 ret
= SetupDiCallClassInstaller(
456 DIF_INSTALLDEVICEFILES
,
457 DevInstData
->hDevInfo
,
458 &DevInstData
->devInfoData
);
461 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%lx\n", GetLastError());
465 ret
= SetupDiCallClassInstaller(
466 DIF_REGISTER_COINSTALLERS
,
467 DevInstData
->hDevInfo
,
468 &DevInstData
->devInfoData
);
471 TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%lx\n", GetLastError());
475 ret
= SetupDiCallClassInstaller(
476 DIF_INSTALLINTERFACES
,
477 DevInstData
->hDevInfo
,
478 &DevInstData
->devInfoData
);
481 TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%lx\n", GetLastError());
485 ret
= SetupDiCallClassInstaller(
487 DevInstData
->hDevInfo
,
488 &DevInstData
->devInfoData
);
491 TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%lx\n", GetLastError());
495 ret
= SetupDiCallClassInstaller(
496 DIF_NEWDEVICEWIZARD_FINISHINSTALL
,
497 DevInstData
->hDevInfo
,
498 &DevInstData
->devInfoData
);
501 TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%lx\n", GetLastError());
505 ret
= SetupDiCallClassInstaller(
506 DIF_DESTROYPRIVATEDATA
,
507 DevInstData
->hDevInfo
,
508 &DevInstData
->devInfoData
);
511 TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%lx\n", GetLastError());
524 IN HINSTANCE hInstance
,
525 IN LPCWSTR InstanceId
,
528 PDEVINSTDATA DevInstData
= NULL
;
535 /* XP kills the process... */
536 ExitProcess(ERROR_ACCESS_DENIED
);
539 DevInstData
= HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA
));
542 TRACE("HeapAlloc() failed\n");
543 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
547 /* Clear devinst data */
548 ZeroMemory(DevInstData
, sizeof(DEVINSTDATA
));
549 DevInstData
->devInfoData
.cbSize
= 0; /* Tell if the devInfoData is valid */
551 /* Fill devinst data */
552 DevInstData
->hDevInfo
= SetupDiCreateDeviceInfoListExW(NULL
, NULL
, NULL
, NULL
);
553 if (DevInstData
->hDevInfo
== INVALID_HANDLE_VALUE
)
555 TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%lx\n", GetLastError());
559 DevInstData
->devInfoData
.cbSize
= sizeof(SP_DEVINFO_DATA
);
560 ret
= SetupDiOpenDeviceInfoW(
561 DevInstData
->hDevInfo
,
565 &DevInstData
->devInfoData
);
568 TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId
);
569 DevInstData
->devInfoData
.cbSize
= 0;
573 SetLastError(ERROR_GEN_FAILURE
);
574 ret
= SetupDiGetDeviceRegistryProperty(
575 DevInstData
->hDevInfo
,
576 &DevInstData
->devInfoData
,
578 &DevInstData
->regDataType
,
580 &DevInstData
->requiredSize
);
582 if (!ret
&& GetLastError() == ERROR_INSUFFICIENT_BUFFER
&& DevInstData
->regDataType
== REG_SZ
)
584 DevInstData
->buffer
= HeapAlloc(GetProcessHeap(), 0, DevInstData
->requiredSize
);
585 if (!DevInstData
->buffer
)
587 TRACE("HeapAlloc() failed\n");
588 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
592 ret
= SetupDiGetDeviceRegistryProperty(
593 DevInstData
->hDevInfo
,
594 &DevInstData
->devInfoData
,
596 &DevInstData
->regDataType
,
597 DevInstData
->buffer
, DevInstData
->requiredSize
,
598 &DevInstData
->requiredSize
);
603 TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%lx (InstanceId %S)\n", GetLastError(), InstanceId
);
607 if (SetupDiGetDeviceRegistryProperty(
608 DevInstData
->hDevInfo
,
609 &DevInstData
->devInfoData
,
612 (BYTE
*)&config_flags
,
613 sizeof(config_flags
),
616 if (config_flags
& CONFIGFLAG_FAILEDINSTALL
)
618 /* The device is disabled */
624 TRACE("Installing %S (%S)\n", DevInstData
->buffer
, InstanceId
);
626 /* Search driver in default location */
627 if (SearchDriver(DevInstData
, NULL
, NULL
))
629 /* Driver found ; install it */
630 retval
= InstallCurrentDriver(DevInstData
);
633 else if (Show
== SW_HIDE
)
635 /* We can't show the wizard. Fail the install */
639 /* Prepare the wizard, and display it */
640 retval
= DisplayWizard(DevInstData
, hWndParent
, IDD_WELCOMEPAGE
);
645 if (DevInstData
->devInfoData
.cbSize
!= 0)
647 if (!SetupDiDestroyDriverInfoList(DevInstData
->hDevInfo
, &DevInstData
->devInfoData
, SPDIT_COMPATDRIVER
))
648 TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
650 if (DevInstData
->hDevInfo
!= INVALID_HANDLE_VALUE
)
652 if (!SetupDiDestroyDeviceInfoList(DevInstData
->hDevInfo
))
653 TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
655 HeapFree(GetProcessHeap(), 0, DevInstData
->buffer
);
656 HeapFree(GetProcessHeap(), 0, DevInstData
);
668 IN DWORD dwUnknownFlags
,
669 IN LPWSTR lpNamedPipeName
)
671 /* NOTE: pNamedPipeName is in the format:
672 * "\\.\pipe\PNP_Device_Install_Pipe_0.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
680 IN HINSTANCE hInstance
,
682 IN LPVOID lpReserved
)
684 if (dwReason
== DLL_PROCESS_ATTACH
)
686 INITCOMMONCONTROLSEX InitControls
;
688 DisableThreadLibraryCalls(hInstance
);
690 InitControls
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
691 InitControls
.dwICC
= ICC_PROGRESS_CLASS
;
692 InitCommonControlsEx(&InitControls
);
693 hDllInstance
= hInstance
;