reactos/dll/win32/newdev/newdev.c

1036 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
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
InstallDevInst(
IN HWND hWndParent,
IN LPCWSTR InstanceId,
IN BOOL bUpdate,
OUT LPDWORD lpReboot)
{
PDEVINSTDATA DevInstData = NULL;
BOOL ret;
BOOL retval = FALSE;
TRACE("InstllDevInst(%p, %s, %d, %p)\n", hWndParent, debugstr_w(InstanceId), bUpdate, lpReboot);
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
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;
}