public void UnloadHive(bool commit) { if (_isLoaded) { var result = RegistryUtils.UnloadHive(HiveKeyName); _isLoaded = (result != 0); if (commit) { FileSystemUtils.ClearReadOnlyAttribute(_hivePath); ProgramUtils.CopyCriticalFile(_tempHivePath, _hivePath); } try { File.Delete(_tempHivePath); } // ReSharper disable once EmptyGeneralCatchClause catch { } if (_isLoaded) { Console.WriteLine("Warning: failed to unload setup registry hive [Code: {0}]", result); } } }
public void CopyFileToSetupDriverDirectory(string sourceFilePath, string destinationRelativeDirectoryPath, string destinationFileName) { var destinationDirectoryPath = GetSetupDriverDirectoryPath(destinationRelativeDirectoryPath); FileSystemUtils.CreateDirectory(destinationDirectoryPath); ProgramUtils.CopyCriticalFile(sourceFilePath, destinationDirectoryPath + destinationFileName); }
/* * public string FindVirtualDeviceInstanceID(string deviceClassName, string hardwareIDToFind) * { * string result = string.Empty; * string keyName = @"ControlSet001\Enum\Root\" + deviceClassName; * if (m_isLoaded) * { * RegistryKey hiveKey = Registry.Users.OpenSubKey(m_hiveKeyName); * RegistryKey key = hiveKey.OpenSubKey(keyName); * * List<string> deviceInstanceIDs = new List<string>(key.GetSubKeyNames()); * foreach (string deviceInstanceID in deviceInstanceIDs) * { * RegistryKey deviceInstanceKey = key.OpenSubKey(deviceInstanceID); * object hardwareIDEntry = deviceInstanceKey.GetValue("HardwareID", new string[0]); * if (hardwareIDEntry is string[]) * { * string hardwareID = ((string[])hardwareIDEntry)[0]; * if (string.Equals(hardwareID, hardwareIDToFind, StringComparison.InvariantCultureIgnoreCase)) * { * result = deviceInstanceID; * break; * } * } * deviceInstanceKey.Close(); * } * key.Close(); * hiveKey.Close(); * return result; * } * else * { * throw new Exception("Registry hive is not loaded"); * } * } */ public void LoadHiveFromDirectory(string directory) { _hivePath = directory + FileName; // GetTempPath() should end with backward slash: _tempHivePath = Path.GetTempPath() + FileName; try { File.Copy(_hivePath, _tempHivePath, true); } catch { // perhaps the hive is already loaded from a previous crash / break // let's try to unload it RegistryUtils.UnloadHive(HiveKeyName); ProgramUtils.CopyCriticalFile(_hivePath, _tempHivePath); // CopyCriticalFile will exit the program on failue } var result = RegistryUtils.LoadHive(HiveKeyName, _tempHivePath); _isLoaded = (result == 0); if (!_isLoaded) { Console.WriteLine("Error: failed to load registry hive '{0}', error code: {1}", FileName, result); Console.WriteLine("This may happen due to one of the following reasons:"); Console.WriteLine("- You do not have access to perform this operation"); Console.WriteLine("- The hive is already loaded and needs to be manually unloaded (HKEY_USERS\\setupreg)"); Environment.Exit(-1); } else { // if ControlSet001\Enum exist, its permissions will stick and stay for GUI-Mode \ final windows, // The default windows permissions for CurrentControlSet\Enum are: // SYSTEM -> Full Control // Everyone -> Read // so we must make sure the default permissions are granted. const string subKeyName = HiveKeyName + @"\ControlSet001\Enum"; // we're creating or opening the Enum key (if it's already exist, the permissions will simply be overwritten) // Note that we're creating ControlSet001\Enum even if we're not using it. var enumKey = Registry.Users.CreateSubKey(subKeyName, RegistryKeyPermissionCheck.ReadWriteSubTree); enumKey.Close(); RegistryKeyUtils.SetHKeyUsersKeySecutiryDescriptor(subKeyName, RegistryKeyUtils.DesiredEnumSecurityDescriptorString); } }
public void SaveRegistryChanges() { SetupRegistryHive.UnloadHive(true); if (IsTargetContainsTemporaryInstallation) { FileSystemUtils.ClearReadOnlyAttribute(BootDirectory + SetupRegistryHiveFile.FileName); try { ProgramUtils.CopyCriticalFile(SetupDirectory + SetupRegistryHiveFile.FileName, BootDirectory + SetupRegistryHiveFile.FileName); } catch { Console.WriteLine("Error: failed to copy '{0}' to '{1}' (setup boot folder)", SetupRegistryHiveFile.FileName, BootDirectory); Program.Exit(); } } }
// see comments above PrepareToPreventTextModeDriverNameCollision() ^^ /// <summary> /// Will copy PNP driver files to setup and boot directories, and update txtsetup.inf accordingly. /// The modifications support 3 different installation scenarions: /// 1. The user install using unmodified CD, use this program to integrate the drivers to the temporary installation folder that was created and then boot from it. /// 2. The user uses this program to create modified installation folder / CD, boots from Windows PE /// at the target machine, and use winnt32.exe to install the target OS. (DOS / winnt.exe should work too) /// 3. The user uses this program to create modified installation CD and boot from it. /// Note: We do not support RIS (seems too complex and can collide with our own TCP/IP integration) /// </summary> private void CopyDriverFiles(List <BaseDeviceService> deviceServices) { var serviceFileNames = new List <string>(); foreach (var deviceService in deviceServices) { serviceFileNames.Add(deviceService.FileName); } for (var index = 0; index < DriverFilesToCopy.Count; index++) { var sourceFilePath = DriverDirectory.Path + DriverFilesToCopy[index].RelativeSourceFilePath; var fileName = DriverFilesToCopy[index].DestinationFileName; var serviceWithNameCollision = false; string textModeFileName; if (fileName.ToLower().EndsWith(".sys")) { var serviceIndex = StringUtils.IndexOfCaseInsensitive(serviceFileNames, fileName); if (serviceIndex >= 0) { var serviceName = deviceServices[index].ServiceName; textModeFileName = deviceServices[index].TextModeFileName; serviceWithNameCollision = StringUtils.ContainsCaseInsensitive(_oldToNewFileName.Keys, textModeFileName); if (serviceName.Length > 8 && !_installation.IsTargetContainsTemporaryInstallation) { Console.WriteLine("Warning: Service '{0}' has name longer than 8 characters.", serviceName); Console.Write("********************************************************************************"); Console.Write("*You must use ISO level 2 compatible settings if you wish to create a working *"); Console.Write("*bootable installation CD. *"); Console.Write("*if you're using nLite, choose mkisofs over the default ISO creation engine. *"); Console.Write("********************************************************************************"); } } else { var renameIndex = StringUtils.IndexOfCaseInsensitive(_oldToNewFileName.Keys, fileName); textModeFileName = renameIndex >= 0 ? _oldToNewFileName[renameIndex].Value : fileName; } } else { textModeFileName = fileName; } if (fileName.ToLower().EndsWith(".sys") || fileName.ToLower().EndsWith(".dll")) { // we copy all the executables to the setup directory, Note that we are using textModeFileName // (e.g. e1000325.sys becomes E1000.sys) this is necessary for a bootable cd to work properly) // but we have to rename the file during text-mode copy phase for GUI-mode to work properly ProgramUtils.CopyCriticalFile(sourceFilePath, _installation.SetupDirectory + textModeFileName, true); } // see comments above PrepareToPreventTextModeDriverNameCollision() ^^ // in case of a service name collision, here we patch the service executable file that we just copied and update the name of its dependency if (serviceWithNameCollision) { // we need the renamed patched file in the setup (e.g. I386 folder) for a bootable cd to work properly PreventTextModeDriverNameCollision(_installation.SetupDirectory + textModeFileName); // we need the original file too (for GUI-mode) ProgramUtils.CopyCriticalFile(sourceFilePath, _installation.SetupDirectory + fileName); } // update txtsetup.sif: if (fileName.ToLower().EndsWith(".sys")) { // this is for the GUI-mode, note that we copy the files to their destination using their original name, // also note that if there is a collision we copy the original (unpatched) file instead of the patched one. if (serviceWithNameCollision) { // this is the unpatched file: _installation.TextSetupInf.SetSourceDisksFileDriverEntry( _installation.ArchitectureIdentifier, fileName, FileCopyDisposition.AlwaysCopy, fileName); // this is the patched file, we're not copying it anywhere, but we load this service executable so text-mode setup demand an entry (probably to locate the file source directory) _installation.TextSetupInf.SetSourceDisksFileDriverEntry( _installation.ArchitectureIdentifier, textModeFileName, FileCopyDisposition.DoNotCopy); } else { _installation.TextSetupInf.SetSourceDisksFileDriverEntry( _installation.ArchitectureIdentifier, textModeFileName, FileCopyDisposition.AlwaysCopy, fileName); } } else if (fileName.ToLower().EndsWith(".dll")) { _installation.TextSetupInf.SetSourceDisksFileDllEntry(_installation.ArchitectureIdentifier, fileName); } // finished updating txtsetup.sif if (_installation.IsTargetContainsTemporaryInstallation) { if (fileName.ToLower().EndsWith(".sys")) { // we copy all drivers by their text-mode name ProgramUtils.CopyCriticalFile( _installation.SetupDirectory + textModeFileName, _installation.BootDirectory + textModeFileName); } } else { // update dosnet.inf if (fileName.ToLower().EndsWith(".sys")) { // we already made sure all the files in the setup directory are using their textModeFileName _installation.DOSNetInf.InstructSetupToCopyFileFromSetupDirectoryToLocalSourceRootDirectory(textModeFileName, textModeFileName); _installation.DOSNetInf.InstructSetupToCopyFileFromSetupDirectoryToBootDirectory(textModeFileName, textModeFileName); if (serviceWithNameCollision) { // the unpatched .sys should be available with it's original (GUI) name in the \$WINNT$.~LS folder _installation.DOSNetInf.InstructSetupToCopyFileFromSetupDirectoryToLocalSourceRootDirectory(fileName); } } else if (fileName.ToLower().EndsWith(".dll")) { // in the case of .dll fileName is the same as textModeFileName _installation.DOSNetInf.InstructSetupToCopyFileFromSetupDirectoryToLocalSourceRootDirectory(fileName); } } } }
public void AddDriverToBootDirectory(string sourceFilePath, string fileName) { ProgramUtils.CopyCriticalFile(sourceFilePath, SetupDirectory + fileName); }
// The following combinations of kernel and HAL will enable NICs to work in text-mode setup: // (regardless of whether the machine being used has one or more than one CPU core) // // Uniprocessor kernel + ACPI PC HAL // Uniprocessor kernel + ACPI Uniprocessor PC HAL // Multiprocessor kernel + ACPI Multiprocessor PC HAL // // Other combinations will either hang or reboot. // By default, text-mode setup will use Multiprocessor kernel + ACPI Uniprocessor PC HAL (which will hang) // // Note that we can use both multiprocessor kernel and multiprocessor HAL on uniprocessor machine, // (there might be a performance penalty for such configuration) // however, this approach will not work on older machines that uses the ACPI PC HAL (Pentium 3 / VirtualBox) // so the best approach is using the uniprocessor kernel. // references: // http://support.microsoft.com/kb/309283 // http://social.technet.microsoft.com/Forums/en-AU/configmgrosd/thread/fb1dbea9-9d39-4663-9c61-6bcdb4c1253f // general information about x86 HAL types: http://www.vernalex.com/guides/sysprep/hal.shtml // Note: /kernel switch does not work in text-mode, so we can't use this simple solution. public void UseUniprocessorKernel() { if (_uniprocessorKernelEnabled) { return; } // amd64 and presumably ia64 use a single HAL for both uni and multiprocessor kernel) if (_installation.ArchitectureIdentifier != "x86") { return; } Console.WriteLine(); Console.WriteLine("By default, text-mode setup will use a multiprocessor OS kernel with a"); Console.WriteLine("uniprocessor HAL. This configuration cannot support network adapters"); Console.WriteLine("(setup will hang)."); Console.WriteLine("IntegrateDrv will try to enable uniprocessor kernel:"); string setupldrPath; if (_installation.IsTargetContainsTemporaryInstallation) { // sometimes NTLDR is being used instead of $LDR$ (when using winnt32.exe /syspart /tempdrive) // (even so, it's still a copy of setupldr.bin and not NTLDR from \I386) setupldrPath = _installation.TargetDirectory + "$LDR$"; if (!File.Exists(setupldrPath)) { setupldrPath = _installation.TargetDirectory + "NTLDR"; } } else // integration to installation media { setupldrPath = _installation.SetupDirectory + "setupldr.bin"; } if (!File.Exists(setupldrPath)) { Console.WriteLine("Error: '{0}' does not exist.", setupldrPath); Program.Exit(); } if (_installation.IsWindows2000) { PatchWindows2000SetupBootLoader(setupldrPath); } else { // Winndows XP or Windows Server 2003 PatchWindowsXP2003SetupBootLoader(setupldrPath); } if (_installation.IsTargetContainsTemporaryInstallation) { ProgramUtils.CopyCriticalFile( _installation.SetupDirectory + "ntoskrnl.ex_", _installation.BootDirectory + "ntoskrnl.ex_"); } else { // integration to installation media _installation.DOSNetInf.InstructSetupToCopyFileFromSetupDirectoryToBootDirectory("ntoskrnl.ex_"); } Console.WriteLine("Uniprocessor kernel has been enabled."); _uniprocessorKernelEnabled = true; }
public void UseMultiprocessorHal() { if (_multiprocessorHalEnabled) { return; } if (_installation.ArchitectureIdentifier != "x86") { // amd64 and presumably ia64 use a single HAL for both uni and multiprocessor kernel) return; } Console.WriteLine(); Console.WriteLine("By default, text-mode setup will use a multiprocessor OS kernel"); Console.WriteLine("with a uniprocessor HAL. This configuration cannot support network adapters"); Console.WriteLine("(setup will hang)."); Console.WriteLine("IntegrateDrv will try to enable multiprocessor HAL:"); if (_installation.IsTargetContainsTemporaryInstallation) { if (File.Exists(_installation.BootDirectory + "halmacpi.dl_")) { _installation.TextSetupInf.UseMultiprocessorHal(); _multiprocessorHalEnabled = true; Console.WriteLine("Multiprocessor HAL has been enabled."); } else if (File.Exists(_installation.SetupDirectory + "halmacpi.dl_")) { ProgramUtils.CopyCriticalFile(_installation.SetupDirectory + "halmacpi.dl_", _installation.BootDirectory + "halmacpi.dl_"); _installation.TextSetupInf.UseMultiprocessorHal(); Console.WriteLine("halmacpi.dl_ was copied from local source directory."); _multiprocessorHalEnabled = true; Console.WriteLine("Multiprocessor HAL has been enabled."); } else { int index; for (index = 3; index >= 1; index--) { var spFilename = string.Format("sp{0}.cab", index); if (File.Exists(_installation.SetupDirectory + spFilename)) { var cabInfo = new CabInfo(_installation.SetupDirectory + spFilename); if (cabInfo.GetFile("halmacpi.dll") != null) { cabInfo.UnpackFile("halmacpi.dll", _installation.BootDirectory + "halmacpi.dll"); // setup is expecting a packed "halmacpi.dl_" //cabInfo = new CabInfo(m_installation.BootDirectory + "halmacpi.dl_"); //Dictionary<string, string> files = new Dictionary<string, string>(); //files.Add("halmacpi.dll", "halmacpi.dll"); //cabInfo.PackFileSet(m_installation.BootDirectory, files); Console.WriteLine("halmacpi.dl_ was extracted from local source directory."); _installation.TextSetupInf.UseMultiprocessorHal(); _multiprocessorHalEnabled = true; Console.WriteLine("Multiprocessor HAL has been enabled."); } break; } } if (index == 0) { Console.WriteLine("Warning: could not locate halmacpi.dll, multiprocessor HAL has not been enabled!"); } } } else // integration to installation media { _installation.TextSetupInf.UseMultiprocessorHal(); _installation.DOSNetInf.InstructSetupToCopyFileFromSetupDirectoryToBootDirectory("halmacpi.dl_"); _multiprocessorHalEnabled = true; Console.WriteLine("Multiprocessor HAL has been enabled."); } }