protected void ProcessCoInstallersSection(PNPDriverINFFile pnpDriverInf, string installSectionName) { var matchingInstallSectionName = pnpDriverInf.GetMatchingInstallSectionName(installSectionName, _architectureIdentifier, _minorOSVersion); if (matchingInstallSectionName == string.Empty) { return; } var matchingCoInstallersSectionName = matchingInstallSectionName + ".CoInstallers"; var coinstallersSection = pnpDriverInf.GetSection(matchingCoInstallersSectionName); foreach (var line in coinstallersSection) { var keyAndValues = INIFile.GetKeyAndValues(line); switch (keyAndValues.Key) { case "CopyFiles": { if (keyAndValues.Value[0].StartsWith("@")) { ProcessCopyFileDirective(pnpDriverInf, keyAndValues.Value[0].Substring(1)); } else { foreach (var copyFilesSectionName in keyAndValues.Value) { ProcessCopyFilesSection(pnpDriverInf, copyFilesSectionName); } } break; } } } }
private void PreconfigureDeviceInstance(PNPDriverINFFile pnpDriverInf, ISystemRegistryHive systemRegistryHive, string enumerator, string deviceID, string deviceInstanceID, BaseDeviceService deviceService) { var driver = pnpDriverInf.ClassGUID.ToUpper() + @"\" + _classInstanceID; var manufacturerName = pnpDriverInf.GetDeviceManufacturerName(HardwareID, _installation.ArchitectureIdentifier, _installation.MinorOSVersion, _installation.ProductType); var hardwareKeyName = @"Enum\" + enumerator + @"\" + deviceID + @"\" + deviceInstanceID; systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "ClassGUID", RegistryValueKind.String, pnpDriverInf.ClassGUID); // The presence of DeviceDesc is critical for some reason, but any value can be used systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "DeviceDesc", RegistryValueKind.String, deviceService.DeviceDescription); // "Driver" is used to help Windows determine which software key belong to this hardware key. // Note: When re-installing the driver, the software key to be used will be determined by this value as well. systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "Driver", RegistryValueKind.String, driver); systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "Service", RegistryValueKind.String, deviceService.ServiceName); // ConfigFlags is not related to the hardware, it's the status of the configuration of the device by Windows (CONFIGFLAG_FAILEDINSTALL etc.) // the presence of this value tells windows the device has driver installed systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "ConfigFlags", RegistryValueKind.DWord, 0); if (PNPDriverINFFile.IsRootDevice(HardwareID)) { // Windows uses the "HardwareID" entry to determine if the hardware is already installed, // We don't have to add this value for physical devices, because Windows will get this value from the device, // but we must add this for virtual devices, or we will find ourselves with duplicity when re-installing (e.g. two Microsoft iScsi Initiators). systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "HardwareID", RegistryValueKind.MultiString, new[] { HardwareID }); } // not necessary: systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "Mfg", RegistryValueKind.String, manufacturerName); systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "Class", RegistryValueKind.String, pnpDriverInf.ClassName); }
// In-box device drivers = drivers that are shipped with Windows public static void DisableInBoxDeviceDrivers(string setupDirectory, string architectureIdentifier, int minorOSVersion, int productType, string hardwareID) { Console.WriteLine(); Console.WriteLine("Looking for drivers for your device (" + hardwareID + ") in Windows setup directory (to disable them):"); var filePaths = Directory.GetFiles(setupDirectory, "*.in_"); foreach (var filePath in filePaths) { var packedFileName = FileSystemUtils.GetNameFromPath(filePath); var unpackedFileName = packedFileName.Substring(0, packedFileName.Length - 1) + "F"; // the filename inside the archive ends with .INF and not with .IN_ var cabInfo = new CabInfo(filePath); ArchiveFileInfo fileInfo = null; try { // some files do not contain an inf file // for instance, netmon.in_ contains netmon.ini fileInfo = cabInfo.GetFile(unpackedFileName); } catch (CabException ex) { // file is invalid / unsupported Console.WriteLine("Cannot examine file '{0}': {1}", packedFileName, ex.Message); } if (fileInfo != null) { var driverInf = new PNPDriverINFFile(unpackedFileName); try { driverInf.ReadPackedFromDirectory(setupDirectory); } catch (CabException ex) { // the archive is a cab and it contains the file we are looking for, but the file is corrupted Console.WriteLine("Cannot unpack file '{0}': {1}", driverInf.PackedFileName, ex.Message); continue; } // Windows will pick up it's own signed drivers even if the added driver also match the SUBSYS, // so we have to disable in-box drivers regardless of the presence of &SUBSYS var found = driverInf.DisableMatchingHardwareID(hardwareID, architectureIdentifier, minorOSVersion, productType); if (found) { Console.WriteLine("Device driver for '{0}' found in file '{1}'.", hardwareID, packedFileName); driverInf.SavePackedToDirectory(setupDirectory); } } } Console.WriteLine("Finished looking for drivers for your device in Windows setup directory."); }
private void ProcessCopyFileDirective(PNPDriverINFFile pnpDriverInf, string sourceFileName, string destinationFileName) { var relativeSourcePath = PNPDriverIntegratorUtils.GetRelativeDirectoryPath(pnpDriverInf, sourceFileName, _architectureIdentifier); var fileToCopy = new FileToCopy(relativeSourcePath, sourceFileName, destinationFileName); if (!FileSystemUtils.IsFileExist(_driverDirectory.Path + fileToCopy.RelativeSourceFilePath)) { Console.WriteLine("Error: Missing file: " + _driverDirectory.Path + fileToCopy.RelativeSourceFilePath); Program.Exit(); } // actual copy will be performed later _driverFilesToCopy.Add(fileToCopy); }
/// <param name="sectionName"></param> /// <param name="relativeRoot"> /// The location where HKR entried will be stored, relative to 'SYSTEM\CurrentControlSet\' (or ControlSet001 for that matter) /// </param> /// <param name="pnpDriverInf"></param> private void ProcessAddRegSection(PNPDriverINFFile pnpDriverInf, string sectionName, string relativeRoot) { var section = pnpDriverInf.GetSection(sectionName); foreach (var line in section) { var values = INIFile.GetCommaSeparatedValues(line); var hiveName = values[0]; var subKeyName = INIFile.Unquote(values[1]); var valueName = INIFile.TryGetValue(values, 2); var valueType = INIFile.TryGetValue(values, 3); var valueDataUnparsed = string.Empty; if (values.Count > 3) { valueDataUnparsed = StringUtils.Join(values.GetRange(4, values.Count - 4), ","); } // byte-list is separated using commmas valueName = INIFile.Unquote(valueName); valueType = pnpDriverInf.ExpandToken(valueType); var valueTypeFlags = PNPDriverINFFile.ConvertFromIntStringOrHexString(valueType); var valueKind = PNPDriverINFFile.GetRegistryValueKind(valueTypeFlags); if (valueKind == RegistryValueKind.String) { valueDataUnparsed = pnpDriverInf.ExpandToken(valueDataUnparsed); } var valueData = HiveINIFile.ParseValueDataString(valueDataUnparsed, valueKind); if (hiveName == "HKR") { var cssKeyName = relativeRoot; if (subKeyName != string.Empty) { cssKeyName = cssKeyName + @"\" + subKeyName; } // Note that software key will stick from text-mode: SetCurrentControlSetRegistryKey(cssKeyName, valueName, valueKind, valueData); } else if (hiveName == "HKLM" && subKeyName.StartsWith(@"SYSTEM\CurrentControlSet\", StringComparison.InvariantCultureIgnoreCase)) { var cssKeyName = subKeyName.Substring(@"SYSTEM\CurrentControlSet\".Length); SetCurrentControlSetRegistryKey(cssKeyName, valueName, valueKind, valueData); } } }
private void ProcessCopyFilesSection(PNPDriverINFFile pnpDriverInf, string sectionName) { var section = pnpDriverInf.GetSection(sectionName); foreach (var line in section) { var values = INIFile.GetCommaSeparatedValues(line); var destinationFileName = values[0]; var sourceFileName = INIFile.TryGetValue(values, 1); if (sourceFileName == string.Empty) { sourceFileName = destinationFileName; } ProcessCopyFileDirective(pnpDriverInf, sourceFileName, destinationFileName); } }
protected string GetRegistryValueData(string hive, string keyName, string valueName) { var lineStart = string.Format("{0},\"{1}\",\"{2}\"", hive, keyName, valueName); string line; var lineIndex = GetLineStartIndex("AddReg", lineStart, out line); if (lineIndex >= 0) { var valueDataStartIndex = line.Substring(lineStart.Length + 1).IndexOf(",", StringComparison.Ordinal) + lineStart.Length + 2; var hexStringValueTypeFlags = line.Substring(lineStart.Length + 1, valueDataStartIndex - lineStart.Length - 2); var valueData = line.Substring(valueDataStartIndex); var valueKind = PNPDriverINFFile.GetRegistryValueKind(hexStringValueTypeFlags); return(valueKind == RegistryValueKind.MultiString ? valueData : Unquote(valueData)); } return(string.Empty); }
// http://msdn.microsoft.com/en-us/library/ff547478%28v=vs.85%29.aspx /// <returns>In the following form: 'WinNT\x86\'</returns> public static string GetRelativeDirectoryPath(PNPDriverINFFile pnpDriverInf, string sourceFileName, string architectureIdentifier) { string subdir; var diskID = GeSourceFileDiskID(pnpDriverInf, sourceFileName, architectureIdentifier, out subdir); if (diskID == string.Empty) { // file location can come from either [SourceDisksFiles] section for vendor-provided drivers // or from layout.inf for Microsoft-provided drivers. // if there is no [SourceDisksFiles] section, we assume the user used a Microsoft-provided driver // and put all the necessary files in the root driver directory (where the .inf is located) // // Note: if [SourceDisksFiles] is not present, Windows GUI-mode setup will look for the files in the root driver directory as well. return(string.Empty); } if (subdir.StartsWith(@"\")) { subdir = subdir.Substring(1); } var relativePathToDisk = GeSourceDiskPath(pnpDriverInf, diskID, architectureIdentifier); if (relativePathToDisk == null) { Console.WriteLine("Warning: Could not locate DiskID '{0}'", diskID); return(string.Empty); // Which means that the file is in the driver directory } if (relativePathToDisk == string.Empty) { // No path, which means that the disk root is the driver directory return(subdir + @"\"); } if (relativePathToDisk.StartsWith(@"\")) { // We remove the leading backslash, and return the relative directory name + subdir return(relativePathToDisk.Substring(1) + @"\" + subdir + @"\"); } Console.WriteLine("Warning: Invalid entry for DiskID '{0}'", diskID); return(subdir + @"\"); }
private void ProcessEventLogInstallSection(PNPDriverINFFile pnpDriverInf, string sectionName, string eventLogType, string eventName) { var installSection = pnpDriverInf.GetSection(sectionName); var relativeRoot = @"Services\EventLog\" + eventLogType + @"\" + eventName; foreach (var line in installSection) { var keyAndValues = INIFile.GetKeyAndValues(line); switch (keyAndValues.Key) { case "AddReg": { foreach (var registrySectionName in keyAndValues.Value) { ProcessAddRegSection(pnpDriverInf, registrySectionName, relativeRoot); } break; } } } }
protected void ProcessInstallServicesSection(PNPDriverINFFile pnpDriverInf, string installSectionName) { var installServicesSection = pnpDriverInf.GetInstallServicesSection(installSectionName, _architectureIdentifier, _minorOSVersion); foreach (var line in installServicesSection) { var keyAndValues = INIFile.GetKeyAndValues(line); switch (keyAndValues.Key) { case "AddService": { var serviceName = keyAndValues.Value[0]; var serviceInstallSection = keyAndValues.Value[2]; var eventLogInstallSection = INIFile.TryGetValue(keyAndValues.Value, 3); var eventLogType = INIFile.TryGetValue(keyAndValues.Value, 4); var eventName = INIFile.TryGetValue(keyAndValues.Value, 5); ProcessServiceInstallSection(pnpDriverInf, serviceInstallSection, serviceName); if (eventLogInstallSection != string.Empty) { // http://msdn.microsoft.com/en-us/library/ff546326%28v=vs.85%29.aspx if (eventLogType == string.Empty) { eventLogType = "System"; } if (eventName == string.Empty) { eventName = serviceName; } ProcessEventLogInstallSection(pnpDriverInf, eventLogInstallSection, eventLogType, eventName); } break; } } } }
private void RegisterDeviceService(ISystemRegistryHive systemRegistryHive, PNPDriverINFFile pnpDriverInf, BaseDeviceService deviceService) { // We ignore start type. if the user uses this program, she wants to boot something! const int startType = 0; // Note: using a different service registry key under CurrentControlSet\Services with an ImagePath entry referring to the .sys will not work in text mode setup! // Text-mode setup will always initialize services based on the values stored under Services\serviceName, where serviceName is the service file name without the .sys extension. // write all to registry: var serviceName = deviceService.ServiceName; if (deviceService.ServiceDisplayName != string.Empty) { systemRegistryHive.SetServiceRegistryKey( serviceName, string.Empty, "DisplayName", RegistryValueKind.String, deviceService.ServiceDisplayName); } systemRegistryHive.SetServiceRegistryKey(serviceName, string.Empty, "ErrorControl", RegistryValueKind.DWord, deviceService.ErrorControl); if (deviceService.ServiceGroup != string.Empty) { systemRegistryHive.SetServiceRegistryKey( serviceName, string.Empty, "Group", RegistryValueKind.String, deviceService.ServiceGroup); } systemRegistryHive.SetServiceRegistryKey(serviceName, string.Empty, "Start", RegistryValueKind.DWord, startType); systemRegistryHive.SetServiceRegistryKey(serviceName, string.Empty, "Type", RegistryValueKind.DWord, deviceService.ServiceType); if (systemRegistryHive is HiveSystemINFFile) // GUI Mode registry { systemRegistryHive.SetServiceRegistryKey( serviceName, string.Empty, "ImagePath", RegistryValueKind.String, deviceService.ImagePath); } // Note that software key will stick from text-mode: var softwareKeyName = @"Control\Class\" + pnpDriverInf.ClassGUID + @"\" + _classInstanceID; var service = deviceService as NetworkDeviceService; if (service != null) { var netCfgInstanceID = service.NetCfgInstanceID; // - sanbootconf and iScsiBP use this value, but it's not necessary for successful boot, static IP can be used instead. // - the presence of this value will stick and stay for the GUI mode // - the presence of this value during GUI Mode will prevent the IP settings from being resetted // - the presence of this value will cause Windows 2000 \ XP x86 to hang after the NIC driver installation (there is no problem with Windows Server 2003) // - the presence of this value will cause Windows XP x64 to hang during the "Installing Network" phase (there is no problem with Windows Server 2003) // we will set this value so sanbootconf / iScsiBP could use it, and if necessary, delete it before the NIC driver installation (using hal.inf) systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "NetCfgInstanceId", RegistryValueKind.String, netCfgInstanceID); if (!_installation.IsWindowsServer2003) { // delete the NetCfgInstanceId registry value during the beginning of GUI-mode setup _installation.HalInf.DeleteNetCfgInstanceIdFromNetworkAdapterClassInstance(_classInstanceID); } // The Linkage subkey is critical, and is used to bind the network adapter to TCP/IP: // - The NetCfgInstanceId here is the one Windows actually uses for TCP/IP configuration. // - The first component in one entry corresponds to the first component in the other entries: systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "Linkage", "Export", RegistryValueKind.MultiString, new[] { @"\Device\" + netCfgInstanceID }); systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "Linkage", "RootDevice", RegistryValueKind.MultiString, new[] { netCfgInstanceID }); // Windows can still provide TCP/IP without this entry systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "Linkage", "UpperBind", RegistryValueKind.MultiString, new[] { "Tcpip" }); } // We need to make sure the software key is created, otherwise two devices can end up using the same software key // Note for network adapters: // "MatchingDeviceId" is not critical for successfull boot or devices which are not network adapters, but it's critical for NICBootConf in case it's being used // Note: Windows will store the hardwareID as it appears in the driver, including &REV systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "MatchingDeviceId", RegistryValueKind.String, HardwareID.ToLower()); // not necessary. in addition, it will also be performed by GUI-mode setup if (deviceService.DeviceDescription != string.Empty) { systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "DriverDesc", RegistryValueKind.String, deviceService.DeviceDescription); } if (pnpDriverInf.DriverVersion != string.Empty) { systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "DriverVersion", RegistryValueKind.String, pnpDriverInf.DriverVersion); } if (pnpDriverInf.Provider != string.Empty) { systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "ProviderName", RegistryValueKind.String, pnpDriverInf.Provider); } }
private void ProcessCopyFileDirective(PNPDriverINFFile pnpDriverInf, string sourceFileName) { ProcessCopyFileDirective(pnpDriverInf, sourceFileName, sourceFileName); }
public void IntegrateDriver() { PNPDriverINFFile pnpDriverInf; var installSectionName = DriverDirectory.GetDeviceInstallSectionName(HardwareID, _installation.ArchitectureIdentifier, _installation.MinorOSVersion, _installation.ProductType, out pnpDriverInf); if (installSectionName == string.Empty) { Console.WriteLine("Unable to locate InstallSectionName in INF file"); Program.Exit(); } _classInstanceID = _installation.SetupRegistryHive.AllocateClassInstanceID(pnpDriverInf.ClassGUID); ProcessInstallSection(pnpDriverInf, installSectionName, _classInstanceID); ProcessInstallServicesSection(pnpDriverInf, installSectionName); // this.DeviceServices is now populated if (DeviceServices.Count == 0) { Console.WriteLine("Error: driver does not have an associated service, IntegrateDrv will not proceed."); Program.Exit(); } PrepareToPreventTextModeDriverNameCollision(DeviceServices); foreach (var deviceService in DeviceServices) { InstructToLoadTextModeDeviceService(deviceService); RegisterDeviceService(_installation.SetupRegistryHive, pnpDriverInf, deviceService); RegisterDeviceService(_installation.HiveSystemInf, pnpDriverInf, deviceService); } CopyDriverFiles(DeviceServices); // register the device: if (PNPDriverINFFile.IsRootDevice(HardwareID)) { // installing virtual device: (this is critical for some services such as iScsiPrt) var virtualDeviceInstanceID = _installation.AllocateVirtualDeviceInstanceID(pnpDriverInf.ClassName); if (DeviceServices.Count > 0) { var deviceService = DeviceServices[0]; PreconfigureDeviceInstance(pnpDriverInf, "Root", pnpDriverInf.ClassName.ToUpper(), virtualDeviceInstanceID, deviceService); } } else // physical device { RegisterPhysicalDevice(pnpDriverInf); // GUI-Mode setup will scan all of the directories listed under "DevicePath" directories, // if it will find multiple matches, it will use the .inf file that has the best match. // Microsoft does not define exactly how matching drivers are ranked, observations show that: // 1. When both .inf have the exact same hardwareID, and one of the .inf is signed and the other is not, the signed .inf will qualify as the best match. // 2. When both .inf have the exact same hardwareID, and both of the .inf files are unsigned, the .inf with the most recent version / date will qualify as the best match. // 3. When both .inf have the exact same hardwareID, and both of the .inf files are unsigned, and both has the same version / date, the .inf from the first directory listed under "DevicePath" will qualify as the best match. // We have to disable the device drivers included in windows to qualify the newly integrated drivers as best match: PNPDriverGUIModeIntegrator.DisableInBoxDeviceDrivers(_installation.SetupDirectory, _installation.ArchitectureIdentifier, _installation.MinorOSVersion, _installation.ProductType, HardwareID); } // Network Device: // We want to make the NIC driver accessible to windows GUI mode setup, otherwise no 'Network Connection' will be installed and TCP/IP configuration // for the NIC will be deleted. (and as a result, the NIC would not have TCP/IP bound to it) // Devices in general: // Windows will clear all existing Enum and / or Control\Class entries of devices that have no matching driver available during GUI-mode setup // (it will be done near the very end of GUI-mode setup) // So we let Windows GUI-Mode install the device. // Note: the driver will be modified for boot start var guiModeIntegrator = new PNPDriverGUIModeIntegrator(DriverDirectory, _installation, HardwareID); guiModeIntegrator.Integrate(); }
// unlike other types of hardware (SCSI controllers etc.), it's not enough to add a NIC to the // Criticla Device Database (CDDB) to make it usable during boot (Note that NIC driver is an NDIS // miniport driver, and the driver does not have an AddDevice() routine and instead uses NDIS' AddDevice()) // This method performs the additional steps needed for a NIC that is added to the CDDB, which are basically letting Windows // know which device class instance is related to the device (TCP/IP settings are tied to the device class instance) // The above is true for both text-mode and GUI-mode / Final Windows. // Note: it's best to use a driver that does these steps during boot, I have written NICBootConf for that purpose. /* * private void PreconfigureCriticalNetworkAdapter(PNPDriverINFFile pnpDriverInf, string enumerator, string deviceID, string deviceInstanceID, DeviceService deviceService) * { * string keyName = @"ControlSet001\Enum\" + enumerator + @"\" + deviceID + @"\" + deviceInstanceID; * m_installation.SetupRegistryHive.SetRegistryKey(keyName, "Driver", RegistryValueKind.String, pnpDriverInf.ClassGUID + @"\" + m_classInstanceID); * // The presence of DeviceDesc is critical for some reason, but any value can be used * m_installation.SetupRegistryHive.SetRegistryKey(keyName, "DeviceDesc", RegistryValueKind.String, deviceService.DeviceDescription); * * // not critical: * m_installation.SetupRegistryHive.SetRegistryKey(keyName, "ClassGUID", RegistryValueKind.String, pnpDriverInf.ClassGUID); * * // we must not specify ServiceName or otherwise kernel-PNP will skip this device * * // let kernel-PNP take care of the rest for us, ClassGUID is not critical: * m_installation.TextSetupInf.AddDeviceToCriticalDeviceDatabase(this.HardwareID, deviceService.ServiceName); * } */ /// <summary> /// When using this method, there is no need to use the Critical Device Database /// </summary> private void PreconfigureDeviceInstance(PNPDriverINFFile pnpDriverInf, string enumerator, string deviceID, string deviceInstanceID, BaseDeviceService deviceService) { PreconfigureDeviceInstance(pnpDriverInf, _installation.SetupRegistryHive, enumerator, deviceID, deviceInstanceID, deviceService); // Apparently this is not necessary for the devices to work properly in GUI-mode, because configuration will stick from text-mode setup: PreconfigureDeviceInstance(pnpDriverInf, _installation.HiveSystemInf, enumerator, deviceID, deviceInstanceID, deviceService); }
private void RegisterPhysicalDevice(PNPDriverINFFile pnpDriverInf) { if (_preconfigure && pnpDriverInf.IsNetworkAdapter && (_useLocalHardwareConfig || _enumExportPath != string.Empty)) { string deviceID; string deviceInstanceID; if (_useLocalHardwareConfig) { deviceInstanceID = PNPLocalHardwareDetector.DetectLocalDeviceInstanceID(HardwareID, out deviceID); if (deviceInstanceID == string.Empty) { Console.WriteLine( "Warning: Could not detect matching device installed locally, configuration will not be applied!"); } } else // m_enumExportPath != string.Empty { deviceInstanceID = PNPExportedHardwareDetector.DetectExportedDeviceInstanceID(_enumExportPath, HardwareID, out deviceID); if (deviceInstanceID == string.Empty) { Console.WriteLine( "Warning: Could not detect matching device in the exported registry, configuration will not be applied!"); } } if (deviceInstanceID != string.Empty) { // m_netDeviceServices is now populated if (NetworkDeviceServices.Count > 0) { // unlike other types of hardware (SCSI controllers etc.), it's not enough to add a NIC to the // Criticla Device Database (CDDB) to make it usable during boot, as mentioned in the comments above RegisterNicAsCriticalDevice() // at the very least, a CDDB entry and a "Device" registry value under Enum\Enumerator\DeviceID\DeviceInstanceID is required // (as well as DeviceDesc if not automatically added by the kernel-PNP) // here we manually register the hardware in advance, but it's better to use NICBootConf to do this during boot, // NICBootConf will also work if the NIC has been moved to another PCI slot since creating the installation media. // the first item in m_netDeviceServices should be the actual NIC (CHECKME: what about NIC / bus driver combination like nVIdia) var deviceService = NetworkDeviceServices[0]; var enumerator = PNPDriverIntegratorUtils.GetEnumeratorNameFromHardwareID(HardwareID); PreconfigureDeviceInstance(pnpDriverInf, enumerator, deviceID, deviceInstanceID, deviceService); } else { Console.WriteLine( "Warning: failed to install '{0}', because the service for this network adapter has not been registered!", HardwareID); } } } else { // if it's a NIC, We assume the user will integrate NICBootConf, which will configure the network adapter during boot. // we'll just add the device to the Criticla Device Database (CDDB), and let kernel-PNP and NICBootConf do the rest. if (pnpDriverInf.IsNetworkAdapter) { // NICBootConf needs the ClassGUID in place for each DeviceInstance Key, // if we put the ClassGUID in the CDDB, the ClassGUID will be applied to each DeviceInstance with matching hardwareID _installation.TextSetupInf.AddDeviceToCriticalDeviceDatabase(HardwareID, DeviceServices[0].ServiceName, PNPDriverINFFile.NetworkAdapterClassGUID); _installation.HiveSystemInf.AddDeviceToCriticalDeviceDatabase(HardwareID, DeviceServices[0].ServiceName, PNPDriverINFFile.NetworkAdapterClassGUID); } else { _installation.TextSetupInf.AddDeviceToCriticalDeviceDatabase(HardwareID, DeviceServices[0].ServiceName); _installation.HiveSystemInf.AddDeviceToCriticalDeviceDatabase(HardwareID, DeviceServices[0].ServiceName); } } }
private void ProcessServiceInstallSection(PNPDriverINFFile pnpDriverInf, string sectionName, string serviceName) { Console.WriteLine("Registering service '" + serviceName + "'"); var serviceInstallSection = pnpDriverInf.GetSection(sectionName); var displayName = string.Empty; var serviceBinary = string.Empty; var serviceTypeString = string.Empty; var errorControlString = string.Empty; var loadOrderGroup = string.Empty; //string guiModeRelativeRoot = @"Services\" + serviceName; foreach (var line in serviceInstallSection) { var keyAndValues = INIFile.GetKeyAndValues(line); switch (keyAndValues.Key) { case "AddReg": { // http://msdn.microsoft.com/en-us/library/ff546326%28v=vs.85%29.aspx // AddReg will always come after ServiceBinaryServiceBinary var relativeRoot = @"Services\" + serviceName; foreach (var registrySectionName in keyAndValues.Value) { ProcessAddRegSection(pnpDriverInf, registrySectionName, relativeRoot); } break; } case "DisplayName": { displayName = INIFile.TryGetValue(keyAndValues.Value, 0); break; } case "ServiceBinary": { serviceBinary = INIFile.TryGetValue(keyAndValues.Value, 0); break; } case "ServiceType": { serviceTypeString = INIFile.TryGetValue(keyAndValues.Value, 0); break; } case "ErrorControl": { errorControlString = INIFile.TryGetValue(keyAndValues.Value, 0); break; } case "LoadOrderGroup": { loadOrderGroup = INIFile.TryGetValue(keyAndValues.Value, 0); break; } } } displayName = pnpDriverInf.ExpandToken(displayName); displayName = INIFile.Unquote(displayName); var fileName = serviceBinary.Replace(@"%12%\", string.Empty); var imagePath = PNPDriverINFFile.ExpandDirID(serviceBinary); var serviceType = PNPDriverINFFile.ConvertFromIntStringOrHexString(serviceTypeString); var errorControl = PNPDriverINFFile.ConvertFromIntStringOrHexString(errorControlString); var deviceDescription = pnpDriverInf.GetDeviceDescription(_hardwareID, _architectureIdentifier, _minorOSVersion, _productType); BaseDeviceService deviceService; if (pnpDriverInf.IsNetworkAdapter) { // this is a nic, we are binding TCP/IP to it // we need a unique NetCfgInstanceID that will be used with Tcpip service and the nic's class var netCfgInstanceID = "{" + Guid.NewGuid().ToString().ToUpper() + "}"; deviceService = new NetworkDeviceService(deviceDescription, serviceName, displayName, loadOrderGroup, serviceType, errorControl, fileName, imagePath, netCfgInstanceID); _deviceServices.Add(deviceService); } else { deviceService = new BaseDeviceService(deviceDescription, serviceName, displayName, loadOrderGroup, serviceType, errorControl, fileName, imagePath); _deviceServices.Add(deviceService); } }
private void CopyDriverToSetupDriverDirectoryAndRegisterIt(PNPDriverINFFile pnpDriverInf) { Console.WriteLine(); Console.WriteLine("Making the driver available to GUI mode setup."); // build list of source files: var driverFiles = new List <string>(); foreach (var fileToCopy in DriverFilesToCopy) { DisableInBoxDeviceDriverFile(_installation.SetupDirectory, fileToCopy.DestinationFileName); driverFiles.Add(fileToCopy.RelativeSourceFilePath); } // make sure the .inf file will be copied too driverFiles.Add(pnpDriverInf.FileName); if (pnpDriverInf.CatalogFile != string.Empty) { if (File.Exists(DriverDirectory.Path + pnpDriverInf.CatalogFile)) { // add the catalog file too (to suppress unsigned driver warning message if the .inf has not been modified) // the catalog file is in the same location as the INF file ( http://msdn.microsoft.com/en-us/library/windows/hardware/ff547502%28v=vs.85%29.aspx ) driverFiles.Add(pnpDriverInf.CatalogFile); } } // Note that we may perform some operations on the same directory more than once, // the allocate / register methods are supposed to return the previously allocated IDs on subsequent calls, // and skip registration of previously registered directories foreach (var relativeFilePath in driverFiles) { var fileName = FileSystemUtils.GetNameFromPath(relativeFilePath); var relativeDirectoryPath = relativeFilePath.Substring(0, relativeFilePath.Length - fileName.Length); // we need to copy the files to the proper sub-directories var sourceDir = DriverDirectory.Path + relativeDirectoryPath; var pathParts = sourceDir.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); var destinationDir = pnpDriverInf.ClassName + '\\' + pathParts[pathParts.Length - 1] + relativeDirectoryPath + Path.DirectorySeparatorChar; _installation.CopyFileToSetupDriverDirectory(sourceDir + fileName, destinationDir, fileName); var sourceDirectoryInMediaRootForm = _installation.GetSourceDriverDirectoryInMediaRootForm(HardwareID + @"\" + relativeDirectoryPath); // note that we may violate ISO9660 - & is not allowed var sourceDiskID = _installation.TextSetupInf.AllocateSourceDiskID(_installation.ArchitectureIdentifier, sourceDirectoryInMediaRootForm); var destinationWinntDirectory = _installation.GetDriverDestinationWinntDirectory(HardwareID + @"\" + relativeDirectoryPath); var destinationWinntDirectoryID = _installation.TextSetupInf.AllocateWinntDirectoryID(destinationWinntDirectory); _installation.TextSetupInf.SetSourceDisksFileEntry(_installation.ArchitectureIdentifier, sourceDiskID, destinationWinntDirectoryID, fileName, FileCopyDisposition.AlwaysCopy); // dosnet.inf: we add the file to the list of files to be copied to local source directory if (!_installation.IsTargetContainsTemporaryInstallation) { _installation.DOSNetInf.InstructSetupToCopyFileFromSetupDirectoryToLocalSourceDriverDirectory( sourceDirectoryInMediaRootForm, fileName); } _installation.HiveSoftwareInf.RegisterDriverDirectory(destinationWinntDirectory); if (_installation.Is64Bit) { // hivsft32.inf _installation.HiveSoftware32Inf.RegisterDriverDirectory(destinationWinntDirectory); } } // set inf to boot start: { var sourceDir = DriverDirectory.Path; var pathParts = sourceDir.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); var destinationDir = pnpDriverInf.ClassName + '\\' + pathParts[pathParts.Length - 1]; var setupDriverDirectoryPath = _installation.GetSetupDriverDirectoryPath(destinationDir + Path.DirectorySeparatorChar); var installSectionName = pnpDriverInf.GetDeviceInstallSectionName(HardwareID, _installation.ArchitectureIdentifier, _installation.MinorOSVersion, _installation.ProductType); pnpDriverInf.SetServiceToBootStart(installSectionName, _installation.ArchitectureIdentifier, _installation.MinorOSVersion); pnpDriverInf.SaveToDirectory(setupDriverDirectoryPath); // finished setting inf to boot start } }
// DDInstall Section in a Network INF File: // http://msdn.microsoft.com/en-us/library/ff546329%28VS.85%29.aspx protected void ProcessInstallSection(PNPDriverINFFile pnpDriverInf, string installSectionName, string classInstanceID) { var installSection = pnpDriverInf.GetInstallSection(installSectionName, _architectureIdentifier, _minorOSVersion); var softwareKeyName = @"Control\Class\" + pnpDriverInf.ClassGUID + @"\" + classInstanceID; foreach (var line in installSection) { var keyAndValues = INIFile.GetKeyAndValues(line); switch (keyAndValues.Key) { case "AddReg": { foreach (var registrySectionName in keyAndValues.Value) { ProcessAddRegSection(pnpDriverInf, registrySectionName, softwareKeyName); } break; } case "CopyFiles": { if (keyAndValues.Value[0].StartsWith("@")) { ProcessCopyFileDirective(pnpDriverInf, keyAndValues.Value[0].Substring(1)); } else { foreach (var copyFilesSectionName in keyAndValues.Value) { ProcessCopyFilesSection(pnpDriverInf, copyFilesSectionName); } } break; } case "BusType": { if (pnpDriverInf.IsNetworkAdapter) { // Some NICs (AMD PCNet) won't start if BusType is not set (CM_PROB_FAILED_START) var busType = Convert.ToInt32(keyAndValues.Value[0]); SetCurrentControlSetRegistryKey(softwareKeyName, "BusType", RegistryValueKind.String, busType.ToString(CultureInfo.InvariantCulture)); } break; } case "Characteristics": { if (pnpDriverInf.IsNetworkAdapter) { // No evidence so far that the presence of this value is critical, but it's a good practice to add it var characteristics = PNPDriverINFFile.ConvertFromIntStringOrHexString(keyAndValues.Value[0]); SetCurrentControlSetRegistryKey(softwareKeyName, "Characteristics", RegistryValueKind.DWord, characteristics); } break; } } } }