private void RegisterDeviceService(ISystemRegistryHive systemRegistryHive, PNPDriverINFFile pnpDriverInf, DeviceService deviceService) { // We ignore start type. if the user uses this program, she wants to boot something! 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: string 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: string softwareKeyName = @"Control\Class\" + pnpDriverInf.ClassGUID + @"\" + m_classInstanceID; if (deviceService is NetworkDeviceService) { string netCfgInstanceID = ((NetworkDeviceService)deviceService).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 (!m_installation.IsWindowsServer2003) { // delete the NetCfgInstanceId registry value during the beginning of GUI-mode setup m_installation.HalInf.DeleteNetCfgInstanceIdFromNetworkAdapterClassInstance(m_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 string[] { @"\Device\" + netCfgInstanceID }); systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "Linkage", "RootDevice", RegistryValueKind.MultiString, new string[] { netCfgInstanceID }); // Windows can still provide TCP/IP without this entry systemRegistryHive.SetCurrentControlSetRegistryKey(softwareKeyName, "Linkage", "UpperBind", RegistryValueKind.MultiString, new string[] { "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, this.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 InstructToLoadTextModeDeviceService(PNPDriverINFFile pnpDriverInf, DeviceService deviceService) { // update txtsetup.sif if (deviceService.ServiceGroup == String.Empty) { // No group, which means txtsetup.sif will have effect on initialization order. // In final Windows this means the service is initialized after all other services. // To do the same in text-mode, we should load this service last (which means using the [CdRomDrivers.Load] section): m_installation.TextSetupInf.InstructToLoadCdRomDriversDriver(deviceService.TextModeFileName, deviceService.DeviceDescription); } else { // we have set a group in setupreg.hiv, so for text-mode it doesn't matter where we put the service in txtsetup.sif, // however, some of the [xxxx.Load] groups will stick and cause problems later (GUI-mode / final Windows), // see TextSetupINFFile.Load.cs to see which groups may cause problems // // Note that the service is renamed back to its original name if necessary. m_installation.TextSetupInf.InstructToLoadKeyboardDriver(deviceService.TextModeFileName, deviceService.DeviceDescription); } }
public void IntegrateDriver() { PNPDriverINFFile pnpDriverInf; string installSectionName = this.DriverDirectory.GetDeviceInstallSectionName(this.HardwareID, m_installation.ArchitectureIdentifier, m_installation.MinorOSVersion, m_installation.ProductType, out pnpDriverInf); if (installSectionName == String.Empty) { Console.WriteLine("Unable to locate InstallSectionName in INF file"); Program.Exit(); } m_classInstanceID = m_installation.SetupRegistryHive.AllocateClassInstanceID(pnpDriverInf.ClassGUID); ProcessInstallSection(pnpDriverInf, installSectionName, m_classInstanceID); ProcessInstallServicesSection(pnpDriverInf, installSectionName); // this.DeviceServices is now populated if (this.DeviceServices.Count == 0) { Console.WriteLine("Error: driver does not have an associated service, IntegrateDrv will not proceed."); Program.Exit(); } PrepareToPreventTextModeDriverNameCollision(this.DeviceServices); foreach (DeviceService deviceService in this.DeviceServices) { InstructToLoadTextModeDeviceService(pnpDriverInf, deviceService); RegisterDeviceService(m_installation.SetupRegistryHive, pnpDriverInf, deviceService); RegisterDeviceService(m_installation.HiveSystemInf, pnpDriverInf, deviceService); } CopyDriverFiles(this.DeviceServices); // register the device: if (PNPDriverINFFile.IsRootDevice(this.HardwareID)) { // installing virtual device: (this is critical for some services such as iScsiPrt) string virtualDeviceInstanceID = m_installation.AllocateVirtualDeviceInstanceID(pnpDriverInf.ClassName); if (this.DeviceServices.Count > 0) { DeviceService deviceService = this.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(m_installation.SetupDirectory, m_installation.ArchitectureIdentifier, m_installation.MinorOSVersion, m_installation.ProductType, this.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 PNPDriverGUIModeIntegrator guiModeIntegrator = new PNPDriverGUIModeIntegrator(this.DriverDirectory, m_installation, this.HardwareID); guiModeIntegrator.Integrate(); }
private void PreconfigureDeviceInstance(PNPDriverINFFile pnpDriverInf, ISystemRegistryHive systemRegistryHive, string enumerator, string deviceID, string deviceInstanceID, DeviceService deviceService) { string driver = pnpDriverInf.ClassGUID.ToUpper() + @"\" + m_classInstanceID; string manufacturerName = pnpDriverInf.GetDeviceManufacturerName(this.HardwareID, m_installation.ArchitectureIdentifier, m_installation.MinorOSVersion, m_installation.ProductType); string 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(this.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 string[] { this.HardwareID }); } // not necessary: systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "Mfg", RegistryValueKind.String, manufacturerName); systemRegistryHive.SetCurrentControlSetRegistryKey(hardwareKeyName, "Class", RegistryValueKind.String, pnpDriverInf.ClassName); }
// 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, DeviceService deviceService) { PreconfigureDeviceInstance(pnpDriverInf, m_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, m_installation.HiveSystemInf, enumerator, deviceID, deviceInstanceID, deviceService); }
private void ProcessServiceInstallSection(PNPDriverINFFile pnpDriverInf, string sectionName, string serviceName) { Console.WriteLine("Registering service '" + serviceName + "'"); List <string> serviceInstallSection = pnpDriverInf.GetSection(sectionName); string displayName = String.Empty; string serviceBinary = String.Empty; string serviceTypeString = String.Empty; string errorControlString = String.Empty; string loadOrderGroup = String.Empty; //string guiModeRelativeRoot = @"Services\" + serviceName; foreach (string line in serviceInstallSection) { KeyValuePair <string, List <string> > 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 string relativeRoot = @"Services\" + serviceName; foreach (string 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; default: break; } } displayName = pnpDriverInf.ExpandToken(displayName); displayName = INIFile.Unquote(displayName); string fileName = serviceBinary.Replace(@"%12%\", String.Empty); string imagePath = pnpDriverInf.ExpandDirID(serviceBinary); int serviceType = PNPDriverINFFile.ConvertFromIntStringOrHexString(serviceTypeString); int errorControl = PNPDriverINFFile.ConvertFromIntStringOrHexString(errorControlString); string deviceDescription = pnpDriverInf.GetDeviceDescription(m_hardwareID, m_architectureIdentifier, m_minorOSVersion, m_productType); DeviceService 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 string netCfgInstanceID = "{" + Guid.NewGuid().ToString().ToUpper() + "}"; deviceService = new NetworkDeviceService(deviceDescription, serviceName, displayName, loadOrderGroup, serviceType, errorControl, fileName, imagePath, netCfgInstanceID); m_deviceServices.Add(deviceService); } else { deviceService = new DeviceService(deviceDescription, serviceName, displayName, loadOrderGroup, serviceType, errorControl, fileName, imagePath); m_deviceServices.Add(deviceService); } }