mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 13:18:51 +00:00
![Jose Carlos Jesus](/assets/img/avatar_default.png)
[NEWDEV] Enable OK button in "Browse For Folder" only when driver is found Implement BrowseCallbackProc() function which sends BFFM_ENABLEOK message to the browse dialog whether the driver is found in the selected folder. Pass the search path to the browse dialog depending on the current index of the drop down combobox. If the index is not set, just get window text. Then, automatically expand the tree view to the specified path by sending BFFM_SETSELECTION message. Also fix a bug in SearchDriverRecursive() where a duplicate backslash was added to the PathWithPattern string variable. [SHELL32] Do not add Recycle Bin to the tree view items in FillTreeView() [SYSSETUP] Add source path to the "Installation Sources" multi-string key Each time the ProcessSetupInf() is being called, add the source path to the "Installation Sources" registry key, if it's not added there yet. The driver search path combobox will be then populated using its value.
1061 lines
30 KiB
C
1061 lines
30 KiB
C
/*
|
|
* New device installer (newdev.dll)
|
|
*
|
|
* Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
|
|
* 2005 Christoph von Wittich (Christoph@ActiveVB.de)
|
|
* 2009 Colin Finck (colin@reactos.org)
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "newdev_private.h"
|
|
|
|
#include <stdio.h>
|
|
#include <winnls.h>
|
|
|
|
/* Global variables */
|
|
HINSTANCE hDllInstance;
|
|
|
|
static BOOL
|
|
SearchDriver(
|
|
IN PDEVINSTDATA DevInstData,
|
|
IN LPCWSTR Directory OPTIONAL,
|
|
IN LPCWSTR InfFile OPTIONAL);
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
UpdateDriverForPlugAndPlayDevicesW(
|
|
IN HWND hwndParent,
|
|
IN LPCWSTR HardwareId,
|
|
IN LPCWSTR FullInfPath,
|
|
IN DWORD InstallFlags,
|
|
OUT PBOOL bRebootRequired OPTIONAL)
|
|
{
|
|
DEVINSTDATA DevInstData;
|
|
DWORD i;
|
|
LPWSTR Buffer = NULL;
|
|
DWORD BufferSize;
|
|
LPCWSTR CurrentHardwareId; /* Pointer into Buffer */
|
|
BOOL FoundHardwareId, FoundAtLeastOneDevice = FALSE;
|
|
BOOL ret = FALSE;
|
|
|
|
DevInstData.hDevInfo = INVALID_HANDLE_VALUE;
|
|
|
|
TRACE("UpdateDriverForPlugAndPlayDevicesW(%p %s %s 0x%x %p)\n",
|
|
hwndParent, debugstr_w(HardwareId), debugstr_w(FullInfPath), InstallFlags, bRebootRequired);
|
|
|
|
/* FIXME: InstallFlags bRebootRequired ignored! */
|
|
|
|
/* Check flags */
|
|
if (InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE))
|
|
{
|
|
TRACE("Unknown flags: 0x%08lx\n", InstallFlags & ~(INSTALLFLAG_FORCE | INSTALLFLAG_READONLY | INSTALLFLAG_NONINTERACTIVE));
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Enumerate all devices of the system */
|
|
DevInstData.hDevInfo = SetupDiGetClassDevsW(NULL, NULL, hwndParent, DIGCF_ALLCLASSES | DIGCF_PRESENT);
|
|
if (DevInstData.hDevInfo == INVALID_HANDLE_VALUE)
|
|
goto cleanup;
|
|
DevInstData.devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
for (i = 0; ; i++)
|
|
{
|
|
if (!SetupDiEnumDeviceInfo(DevInstData.hDevInfo, i, &DevInstData.devInfoData))
|
|
{
|
|
if (GetLastError() != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
TRACE("SetupDiEnumDeviceInfo() failed with error 0x%x\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
/* This error was expected */
|
|
break;
|
|
}
|
|
|
|
/* Get Hardware ID */
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
Buffer = NULL;
|
|
BufferSize = 0;
|
|
while (!SetupDiGetDeviceRegistryPropertyW(
|
|
DevInstData.hDevInfo,
|
|
&DevInstData.devInfoData,
|
|
SPDRP_HARDWAREID,
|
|
NULL,
|
|
(PBYTE)Buffer,
|
|
BufferSize,
|
|
&BufferSize))
|
|
{
|
|
if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
|
{
|
|
Buffer = NULL;
|
|
break;
|
|
}
|
|
else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
TRACE("SetupDiGetDeviceRegistryPropertyW() failed with error 0x%x\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
/* This error was expected */
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
|
|
if (!Buffer)
|
|
{
|
|
TRACE("HeapAlloc() failed\n", GetLastError());
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (Buffer == NULL)
|
|
continue;
|
|
|
|
/* Check if we match the given hardware ID */
|
|
FoundHardwareId = FALSE;
|
|
for (CurrentHardwareId = Buffer; *CurrentHardwareId != UNICODE_NULL; CurrentHardwareId += wcslen(CurrentHardwareId) + 1)
|
|
{
|
|
if (wcscmp(CurrentHardwareId, HardwareId) == 0)
|
|
{
|
|
FoundHardwareId = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!FoundHardwareId)
|
|
continue;
|
|
|
|
/* We need to try to update the driver of this device */
|
|
|
|
/* Get Instance ID */
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
Buffer = NULL;
|
|
if (SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, NULL, 0, &BufferSize))
|
|
{
|
|
/* Error, as the output buffer should be too small */
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%x\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
else if ((Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize * sizeof(WCHAR))) == NULL)
|
|
{
|
|
TRACE("HeapAlloc() failed\n", GetLastError());
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
else if (!SetupDiGetDeviceInstanceIdW(DevInstData.hDevInfo, &DevInstData.devInfoData, Buffer, BufferSize, NULL))
|
|
{
|
|
TRACE("SetupDiGetDeviceInstanceIdW() failed with error 0x%x\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
TRACE("Trying to update the driver of %s\n", debugstr_w(Buffer));
|
|
|
|
/* Search driver in the specified .inf file */
|
|
if (!SearchDriver(&DevInstData, NULL, FullInfPath))
|
|
{
|
|
TRACE("SearchDriver() failed with error 0x%x\n", GetLastError());
|
|
continue;
|
|
}
|
|
|
|
/* FIXME: HACK! We shouldn't check of ERROR_PRIVILEGE_NOT_HELD */
|
|
//if (!InstallCurrentDriver(&DevInstData))
|
|
if (!InstallCurrentDriver(&DevInstData) && GetLastError() != ERROR_PRIVILEGE_NOT_HELD)
|
|
{
|
|
TRACE("InstallCurrentDriver() failed with error 0x%x\n", GetLastError());
|
|
continue;
|
|
}
|
|
|
|
FoundAtLeastOneDevice = TRUE;
|
|
}
|
|
|
|
if (FoundAtLeastOneDevice)
|
|
{
|
|
SetLastError(NO_ERROR);
|
|
ret = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TRACE("No device found with HardwareID %s\n", debugstr_w(HardwareId));
|
|
SetLastError(ERROR_NO_SUCH_DEVINST);
|
|
}
|
|
|
|
cleanup:
|
|
if (DevInstData.hDevInfo != INVALID_HANDLE_VALUE)
|
|
SetupDiDestroyDeviceInfoList(DevInstData.hDevInfo);
|
|
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
UpdateDriverForPlugAndPlayDevicesA(
|
|
IN HWND hwndParent,
|
|
IN LPCSTR HardwareId,
|
|
IN LPCSTR FullInfPath,
|
|
IN DWORD InstallFlags,
|
|
OUT PBOOL bRebootRequired OPTIONAL)
|
|
{
|
|
BOOL Result;
|
|
LPWSTR HardwareIdW = NULL;
|
|
LPWSTR FullInfPathW = NULL;
|
|
|
|
int len = MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, NULL, 0);
|
|
HardwareIdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
if (!HardwareIdW)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
MultiByteToWideChar(CP_ACP, 0, HardwareId, -1, HardwareIdW, len);
|
|
|
|
len = MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, NULL, 0);
|
|
FullInfPathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
if (!FullInfPathW)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, HardwareIdW);
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
MultiByteToWideChar(CP_ACP, 0, FullInfPath, -1, FullInfPathW, len);
|
|
|
|
Result = UpdateDriverForPlugAndPlayDevicesW(
|
|
hwndParent,
|
|
HardwareIdW,
|
|
FullInfPathW,
|
|
InstallFlags,
|
|
bRebootRequired);
|
|
|
|
HeapFree(GetProcessHeap(), 0, HardwareIdW);
|
|
HeapFree(GetProcessHeap(), 0, FullInfPathW);
|
|
|
|
return Result;
|
|
}
|
|
|
|
/* Directory and InfFile MUST NOT be specified simultaneously */
|
|
static BOOL
|
|
SearchDriver(
|
|
IN PDEVINSTDATA DevInstData,
|
|
IN LPCWSTR Directory OPTIONAL,
|
|
IN LPCWSTR InfFile OPTIONAL)
|
|
{
|
|
SP_DEVINSTALL_PARAMS_W DevInstallParams = {0,};
|
|
BOOL ret;
|
|
|
|
DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS_W);
|
|
if (!SetupDiGetDeviceInstallParamsW(DevInstData->hDevInfo, &DevInstData->devInfoData, &DevInstallParams))
|
|
{
|
|
TRACE("SetupDiGetDeviceInstallParams() failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
DevInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS;
|
|
|
|
if (InfFile)
|
|
{
|
|
DevInstallParams.Flags |= DI_ENUMSINGLEINF;
|
|
wcsncpy(DevInstallParams.DriverPath, InfFile, MAX_PATH);
|
|
}
|
|
else if (Directory)
|
|
{
|
|
DevInstallParams.Flags &= ~DI_ENUMSINGLEINF;
|
|
wcsncpy(DevInstallParams.DriverPath, Directory, MAX_PATH);
|
|
}
|
|
else
|
|
{
|
|
DevInstallParams.Flags &= ~DI_ENUMSINGLEINF;
|
|
*DevInstallParams.DriverPath = '\0';
|
|
}
|
|
|
|
ret = SetupDiSetDeviceInstallParamsW(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
&DevInstallParams);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiSetDeviceInstallParams() failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiBuildDriverInfoList(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
SPDIT_COMPATDRIVER);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiBuildDriverInfoList() failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
DevInstData->drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
|
|
ret = SetupDiEnumDriverInfoW(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
SPDIT_COMPATDRIVER,
|
|
0,
|
|
&DevInstData->drvInfoData);
|
|
if (!ret)
|
|
{
|
|
if (GetLastError() == ERROR_NO_MORE_ITEMS)
|
|
return FALSE;
|
|
TRACE("SetupDiEnumDriverInfo() failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL
|
|
IsDots(IN LPCWSTR str)
|
|
{
|
|
if(wcscmp(str, L".") && wcscmp(str, L"..")) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
static LPCWSTR
|
|
GetFileExt(IN LPWSTR FileName)
|
|
{
|
|
LPCWSTR Dot;
|
|
|
|
Dot = wcsrchr(FileName, '.');
|
|
if (!Dot)
|
|
return L"";
|
|
|
|
return Dot;
|
|
}
|
|
|
|
static BOOL
|
|
SearchDriverRecursive(
|
|
IN PDEVINSTDATA DevInstData,
|
|
IN LPCWSTR Path)
|
|
{
|
|
WIN32_FIND_DATAW wfd;
|
|
WCHAR DirPath[MAX_PATH];
|
|
WCHAR FileName[MAX_PATH];
|
|
WCHAR FullPath[MAX_PATH];
|
|
WCHAR LastDirPath[MAX_PATH] = L"";
|
|
WCHAR PathWithPattern[MAX_PATH];
|
|
BOOL ok = TRUE;
|
|
BOOL retval = FALSE;
|
|
HANDLE hFindFile = INVALID_HANDLE_VALUE;
|
|
|
|
wcscpy(DirPath, Path);
|
|
|
|
if (DirPath[wcslen(DirPath) - 1] != '\\')
|
|
wcscat(DirPath, L"\\");
|
|
|
|
wcscpy(PathWithPattern, DirPath);
|
|
wcscat(PathWithPattern, L"*");
|
|
|
|
for (hFindFile = FindFirstFileW(PathWithPattern, &wfd);
|
|
ok && hFindFile != INVALID_HANDLE_VALUE;
|
|
ok = FindNextFileW(hFindFile, &wfd))
|
|
{
|
|
|
|
wcscpy(FileName, wfd.cFileName);
|
|
if (IsDots(FileName))
|
|
continue;
|
|
|
|
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
/* Recursive search */
|
|
wcscpy(FullPath, DirPath);
|
|
wcscat(FullPath, FileName);
|
|
if (SearchDriverRecursive(DevInstData, FullPath))
|
|
{
|
|
retval = TRUE;
|
|
/* We continue the search for a better driver */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LPCWSTR pszExtension = GetFileExt(FileName);
|
|
|
|
if ((_wcsicmp(pszExtension, L".inf") == 0) && (wcscmp(LastDirPath, DirPath) != 0))
|
|
{
|
|
wcscpy(LastDirPath, DirPath);
|
|
|
|
if (wcslen(DirPath) > MAX_PATH)
|
|
/* Path is too long to be searched */
|
|
continue;
|
|
|
|
if (SearchDriver(DevInstData, DirPath, NULL))
|
|
{
|
|
retval = TRUE;
|
|
/* We continue the search for a better driver */
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hFindFile != INVALID_HANDLE_VALUE)
|
|
FindClose(hFindFile);
|
|
return retval;
|
|
}
|
|
|
|
BOOL
|
|
CheckBestDriver(
|
|
_In_ PDEVINSTDATA DevInstData,
|
|
_In_ PCWSTR pszDir)
|
|
{
|
|
return SearchDriverRecursive(DevInstData, pszDir);
|
|
}
|
|
|
|
BOOL
|
|
ScanFoldersForDriver(
|
|
IN PDEVINSTDATA DevInstData)
|
|
{
|
|
BOOL result;
|
|
|
|
/* Search in default location */
|
|
result = SearchDriver(DevInstData, NULL, NULL);
|
|
|
|
if (DevInstData->CustomSearchPath)
|
|
{
|
|
/* Search only in specified paths */
|
|
/* We need to check all specified directories to be
|
|
* sure to find the best driver for the device.
|
|
*/
|
|
LPCWSTR Path;
|
|
for (Path = DevInstData->CustomSearchPath; *Path != '\0'; Path += wcslen(Path) + 1)
|
|
{
|
|
TRACE("Search driver in %s\n", debugstr_w(Path));
|
|
if (wcslen(Path) == 2 && Path[1] == ':')
|
|
{
|
|
if (SearchDriverRecursive(DevInstData, Path))
|
|
result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (SearchDriver(DevInstData, Path, NULL))
|
|
result = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
PrepareFoldersToScan(
|
|
IN PDEVINSTDATA DevInstData,
|
|
IN BOOL IncludeRemovableDevices,
|
|
IN BOOL IncludeCustomPath,
|
|
IN HWND hwndCombo OPTIONAL)
|
|
{
|
|
WCHAR drive[] = {'?',':',0};
|
|
DWORD dwDrives = 0;
|
|
DWORD i;
|
|
UINT nType;
|
|
DWORD CustomTextLength = 0;
|
|
DWORD LengthNeeded = 0;
|
|
LPWSTR Buffer;
|
|
|
|
/* Calculate length needed to store the search paths */
|
|
if (IncludeRemovableDevices)
|
|
{
|
|
dwDrives = GetLogicalDrives();
|
|
for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1)
|
|
{
|
|
if (dwDrives & i)
|
|
{
|
|
nType = GetDriveTypeW(drive);
|
|
if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
|
|
{
|
|
LengthNeeded += 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (IncludeCustomPath)
|
|
{
|
|
CustomTextLength = 1 + ComboBox_GetTextLength(hwndCombo);
|
|
LengthNeeded += CustomTextLength;
|
|
}
|
|
|
|
/* Allocate space for search paths */
|
|
HeapFree(GetProcessHeap(), 0, DevInstData->CustomSearchPath);
|
|
DevInstData->CustomSearchPath = Buffer = HeapAlloc(
|
|
GetProcessHeap(),
|
|
0,
|
|
(LengthNeeded + 1) * sizeof(WCHAR));
|
|
if (!Buffer)
|
|
{
|
|
TRACE("HeapAlloc() failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Fill search paths */
|
|
if (IncludeRemovableDevices)
|
|
{
|
|
for (drive[0] = 'A', i = 1; drive[0] <= 'Z'; drive[0]++, i <<= 1)
|
|
{
|
|
if (dwDrives & i)
|
|
{
|
|
nType = GetDriveTypeW(drive);
|
|
if (nType == DRIVE_REMOVABLE || nType == DRIVE_CDROM)
|
|
{
|
|
Buffer += 1 + swprintf(Buffer, drive);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (IncludeCustomPath)
|
|
{
|
|
Buffer += 1 + GetWindowTextW(hwndCombo, Buffer, CustomTextLength);
|
|
}
|
|
*Buffer = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
InstallCurrentDriver(
|
|
IN PDEVINSTDATA DevInstData)
|
|
{
|
|
BOOL ret;
|
|
|
|
TRACE("Installing driver %s: %s\n",
|
|
debugstr_w(DevInstData->drvInfoData.MfgName),
|
|
debugstr_w(DevInstData->drvInfoData.Description));
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_SELECTBESTCOMPATDRV,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_SELECTBESTCOMPATDRV) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_ALLOW_INSTALL,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_ALLOW_INSTALL) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_NEWDEVICEWIZARD_PREANALYZE,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_PREANALYZE) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_NEWDEVICEWIZARD_POSTANALYZE,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_POSTANALYZE) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_INSTALLDEVICEFILES,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_REGISTER_COINSTALLERS,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_INSTALLINTERFACES,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_INSTALLINTERFACES) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_INSTALLDEVICE,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_NEWDEVICEWIZARD_FINISHINSTALL,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_NEWDEVICEWIZARD_FINISHINSTALL) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ret = SetupDiCallClassInstaller(
|
|
DIF_DESTROYPRIVATEDATA,
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA) failed with error 0x%x\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
DevInstallW(
|
|
IN HWND hWndParent,
|
|
IN HINSTANCE hInstance,
|
|
IN LPCWSTR InstanceId,
|
|
IN INT Show)
|
|
{
|
|
PDEVINSTDATA DevInstData = NULL;
|
|
BOOL ret;
|
|
DWORD config_flags;
|
|
BOOL retval = FALSE;
|
|
|
|
TRACE("(%p, %p, %s, %d)\n", hWndParent, hInstance, debugstr_w(InstanceId), Show);
|
|
|
|
if (!IsUserAdmin())
|
|
{
|
|
/* XP kills the process... */
|
|
ExitProcess(ERROR_ACCESS_DENIED);
|
|
}
|
|
|
|
DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA));
|
|
if (!DevInstData)
|
|
{
|
|
TRACE("HeapAlloc() failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Clear devinst data */
|
|
ZeroMemory(DevInstData, sizeof(DEVINSTDATA));
|
|
DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
|
|
|
|
/* Fill devinst data */
|
|
DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
|
|
if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE)
|
|
{
|
|
TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
ret = SetupDiOpenDeviceInfoW(
|
|
DevInstData->hDevInfo,
|
|
InstanceId,
|
|
NULL,
|
|
0, /* Open flags */
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n",
|
|
GetLastError(), debugstr_w(InstanceId));
|
|
DevInstData->devInfoData.cbSize = 0;
|
|
goto cleanup;
|
|
}
|
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
ret = SetupDiGetDeviceRegistryProperty(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
SPDRP_DEVICEDESC,
|
|
&DevInstData->regDataType,
|
|
NULL, 0,
|
|
&DevInstData->requiredSize);
|
|
|
|
if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ)
|
|
{
|
|
DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize);
|
|
if (!DevInstData->buffer)
|
|
{
|
|
TRACE("HeapAlloc() failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else
|
|
{
|
|
ret = SetupDiGetDeviceRegistryPropertyW(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
SPDRP_DEVICEDESC,
|
|
&DevInstData->regDataType,
|
|
DevInstData->buffer, DevInstData->requiredSize,
|
|
&DevInstData->requiredSize);
|
|
}
|
|
}
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n",
|
|
GetLastError(), debugstr_w(InstanceId));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (SetupDiGetDeviceRegistryPropertyW(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
SPDRP_CONFIGFLAGS,
|
|
NULL,
|
|
(BYTE *)&config_flags,
|
|
sizeof(config_flags),
|
|
NULL))
|
|
{
|
|
if (config_flags & CONFIGFLAG_FAILEDINSTALL)
|
|
{
|
|
/* The device is disabled */
|
|
TRACE("Device is disabled\n");
|
|
retval = TRUE;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
TRACE("Installing %s (%s)\n", debugstr_w((PCWSTR)DevInstData->buffer), debugstr_w(InstanceId));
|
|
|
|
/* Search driver in default location and removable devices */
|
|
if (!PrepareFoldersToScan(DevInstData, FALSE, FALSE, NULL))
|
|
{
|
|
TRACE("PrepareFoldersToScan() failed with error 0x%lx\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
if (ScanFoldersForDriver(DevInstData))
|
|
{
|
|
/* Driver found ; install it */
|
|
retval = InstallCurrentDriver(DevInstData);
|
|
TRACE("InstallCurrentDriver() returned %d\n", retval);
|
|
if (retval && Show != SW_HIDE)
|
|
{
|
|
/* Should we display the 'Need to reboot' page? */
|
|
SP_DEVINSTALL_PARAMS installParams;
|
|
installParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
|
|
if (SetupDiGetDeviceInstallParams(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
&installParams))
|
|
{
|
|
if (installParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))
|
|
{
|
|
TRACE("Displaying 'Reboot' wizard page\n");
|
|
retval = DisplayWizard(DevInstData, hWndParent, IDD_NEEDREBOOT);
|
|
}
|
|
}
|
|
}
|
|
goto cleanup;
|
|
}
|
|
else if (Show == SW_HIDE)
|
|
{
|
|
/* We can't show the wizard. Fail the install */
|
|
TRACE("No wizard\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Prepare the wizard, and display it */
|
|
TRACE("Need to show install wizard\n");
|
|
retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE);
|
|
|
|
cleanup:
|
|
if (DevInstData)
|
|
{
|
|
if (DevInstData->devInfoData.cbSize != 0)
|
|
{
|
|
if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER))
|
|
TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
|
|
}
|
|
if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo))
|
|
TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, DevInstData->buffer);
|
|
HeapFree(GetProcessHeap(), 0, DevInstData);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
InstallDevInstEx(
|
|
IN HWND hWndParent,
|
|
IN LPCWSTR InstanceId,
|
|
IN BOOL bUpdate,
|
|
OUT LPDWORD lpReboot,
|
|
IN DWORD Unknown)
|
|
{
|
|
PDEVINSTDATA DevInstData = NULL;
|
|
BOOL ret;
|
|
BOOL retval = FALSE;
|
|
|
|
TRACE("InstllDevInstEx(%p, %s, %d, %p, %lx)\n",
|
|
hWndParent, debugstr_w(InstanceId), bUpdate, lpReboot, Unknown);
|
|
|
|
DevInstData = HeapAlloc(GetProcessHeap(), 0, sizeof(DEVINSTDATA));
|
|
if (!DevInstData)
|
|
{
|
|
TRACE("HeapAlloc() failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Clear devinst data */
|
|
ZeroMemory(DevInstData, sizeof(DEVINSTDATA));
|
|
DevInstData->devInfoData.cbSize = 0; /* Tell if the devInfoData is valid */
|
|
DevInstData->bUpdate = bUpdate;
|
|
|
|
/* Fill devinst data */
|
|
DevInstData->hDevInfo = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
|
|
if (DevInstData->hDevInfo == INVALID_HANDLE_VALUE)
|
|
{
|
|
TRACE("SetupDiCreateDeviceInfoListExW() failed with error 0x%x\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
DevInstData->devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
|
ret = SetupDiOpenDeviceInfoW(
|
|
DevInstData->hDevInfo,
|
|
InstanceId,
|
|
NULL,
|
|
0, /* Open flags */
|
|
&DevInstData->devInfoData);
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiOpenDeviceInfoW() failed with error 0x%x (InstanceId %s)\n",
|
|
GetLastError(), debugstr_w(InstanceId));
|
|
DevInstData->devInfoData.cbSize = 0;
|
|
goto cleanup;
|
|
}
|
|
|
|
SetLastError(ERROR_GEN_FAILURE);
|
|
ret = SetupDiGetDeviceRegistryProperty(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
SPDRP_DEVICEDESC,
|
|
&DevInstData->regDataType,
|
|
NULL, 0,
|
|
&DevInstData->requiredSize);
|
|
|
|
if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && DevInstData->regDataType == REG_SZ)
|
|
{
|
|
DevInstData->buffer = HeapAlloc(GetProcessHeap(), 0, DevInstData->requiredSize);
|
|
if (!DevInstData->buffer)
|
|
{
|
|
TRACE("HeapAlloc() failed\n");
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else
|
|
{
|
|
ret = SetupDiGetDeviceRegistryPropertyW(
|
|
DevInstData->hDevInfo,
|
|
&DevInstData->devInfoData,
|
|
SPDRP_DEVICEDESC,
|
|
&DevInstData->regDataType,
|
|
DevInstData->buffer, DevInstData->requiredSize,
|
|
&DevInstData->requiredSize);
|
|
}
|
|
}
|
|
|
|
if (!ret)
|
|
{
|
|
TRACE("SetupDiGetDeviceRegistryProperty() failed with error 0x%x (InstanceId %s)\n",
|
|
GetLastError(), debugstr_w(InstanceId));
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Prepare the wizard, and display it */
|
|
TRACE("Need to show install wizard\n");
|
|
retval = DisplayWizard(DevInstData, hWndParent, IDD_WELCOMEPAGE);
|
|
|
|
cleanup:
|
|
if (DevInstData)
|
|
{
|
|
if (DevInstData->devInfoData.cbSize != 0)
|
|
{
|
|
if (!SetupDiDestroyDriverInfoList(DevInstData->hDevInfo, &DevInstData->devInfoData, SPDIT_COMPATDRIVER))
|
|
TRACE("SetupDiDestroyDriverInfoList() failed with error 0x%lx\n", GetLastError());
|
|
}
|
|
if (DevInstData->hDevInfo != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!SetupDiDestroyDeviceInfoList(DevInstData->hDevInfo))
|
|
TRACE("SetupDiDestroyDeviceInfoList() failed with error 0x%lx\n", GetLastError());
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, DevInstData->buffer);
|
|
HeapFree(GetProcessHeap(), 0, DevInstData);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL
|
|
WINAPI
|
|
InstallDevInst(
|
|
IN HWND hWndParent,
|
|
IN LPCWSTR InstanceId,
|
|
IN BOOL bUpdate,
|
|
OUT LPDWORD lpReboot)
|
|
{
|
|
return InstallDevInstEx(hWndParent, InstanceId, bUpdate, lpReboot, 0);
|
|
}
|
|
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
ClientSideInstallW(
|
|
IN HWND hWndOwner,
|
|
IN HINSTANCE hInstance,
|
|
IN LPWSTR lpNamedPipeName,
|
|
IN INT Show)
|
|
{
|
|
BOOL ReturnValue = FALSE;
|
|
BOOL ShowWizard;
|
|
DWORD BytesRead;
|
|
DWORD Value;
|
|
HANDLE hPipe = INVALID_HANDLE_VALUE;
|
|
PWSTR DeviceInstance = NULL;
|
|
PWSTR InstallEventName = NULL;
|
|
HANDLE hInstallEvent;
|
|
|
|
/* Open the pipe */
|
|
hPipe = CreateFileW(lpNamedPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if(hPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
ERR("CreateFileW failed with error %u\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Read the data. Some is just included for compatibility with Windows right now and not yet used by ReactOS.
|
|
See umpnpmgr for more details. */
|
|
if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
|
|
{
|
|
ERR("ReadFile failed with error %u\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
InstallEventName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
|
|
|
|
if(!ReadFile(hPipe, InstallEventName, Value, &BytesRead, NULL))
|
|
{
|
|
ERR("ReadFile failed with error %u\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
/* I couldn't figure out what the following value means under Windows XP.
|
|
Therefore I used it in umpnpmgr to pass the ShowWizard variable. */
|
|
if(!ReadFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesRead, NULL))
|
|
{
|
|
ERR("ReadFile failed with error %u\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Next one is again size in bytes of the following string */
|
|
if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
|
|
{
|
|
ERR("ReadFile failed with error %u\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
DeviceInstance = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
|
|
|
|
if(!ReadFile(hPipe, DeviceInstance, Value, &BytesRead, NULL))
|
|
{
|
|
ERR("ReadFile failed with error %u\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
ReturnValue = DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE : SW_HIDE);
|
|
if(!ReturnValue)
|
|
{
|
|
ERR("DevInstallW failed with error %lu\n", GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
|
|
if(!hInstallEvent)
|
|
{
|
|
TRACE("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
SetEvent(hInstallEvent);
|
|
CloseHandle(hInstallEvent);
|
|
|
|
cleanup:
|
|
if(hPipe != INVALID_HANDLE_VALUE)
|
|
CloseHandle(hPipe);
|
|
|
|
if(InstallEventName)
|
|
HeapFree(GetProcessHeap(), 0, InstallEventName);
|
|
|
|
if(DeviceInstance)
|
|
HeapFree(GetProcessHeap(), 0, DeviceInstance);
|
|
|
|
return ReturnValue;
|
|
}
|
|
|
|
BOOL WINAPI
|
|
DllMain(
|
|
IN HINSTANCE hInstance,
|
|
IN DWORD dwReason,
|
|
IN LPVOID lpReserved)
|
|
{
|
|
if (dwReason == DLL_PROCESS_ATTACH)
|
|
{
|
|
INITCOMMONCONTROLSEX InitControls;
|
|
|
|
DisableThreadLibraryCalls(hInstance);
|
|
|
|
InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
|
InitControls.dwICC = ICC_PROGRESS_CLASS;
|
|
InitCommonControlsEx(&InitControls);
|
|
hDllInstance = hInstance;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|