/* * 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 #include /* 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 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; }