From e4aa37f436858f17bbc4673565f09cb3611396d1 Mon Sep 17 00:00:00 2001 From: David Hall Date: Sat, 11 Feb 2023 07:35:30 -0700 Subject: [PATCH] Added SP_DRVINFO_DETAIL_DATA_MGD which will take memory tied to SP_DRVINFO_DETAIL_DATA and extract the correct values. (#374) --- PInvoke/SetupAPI/SetupAPI.cs | 102 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/PInvoke/SetupAPI/SetupAPI.cs b/PInvoke/SetupAPI/SetupAPI.cs index 2b8dd3b5..91036407 100644 --- a/PInvoke/SetupAPI/SetupAPI.cs +++ b/PInvoke/SetupAPI/SetupAPI.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Runtime.InteropServices; using Vanara.Extensions; using Vanara.InteropServices; @@ -3490,6 +3491,107 @@ namespace Vanara.PInvoke public string HardwareID; } + /// An SP_DRVINFO_DETAIL_DATA structure contains detailed information about a particular driver information structure. + /// + /// The hardware ID and compatible IDs for a device are specified in the INF Models section in the following order: + /// + /// + /// The first ID (if specified) is the hardware ID for the device. + /// + /// + /// The remaining IDs (if specified) are compatible IDs for the device. + /// + /// + /// + /// When you parse the HardwareID buffer, you must ensure that you correctly determine the end of the data in the buffer. Be + /// aware that the buffer is not necessarily double NULL terminated. + /// + /// + /// For example, depending on how the list of hardware ID and compatible IDs are specified in the INF Models section, the + /// HardwareID buffer can resemble any of the following: + /// + /// + /// + /// \0 + /// + /// + /// <HWID>\0 + /// + /// + /// <HWID>\0<COMPATID_1>\0...<COMPATID_N>\0\0 + /// + /// + /// \0<COMPATID_1>\0...<COMPATID_N>\0\0 + /// + /// + /// + /// An algorithm to correctly parse this buffer must use the CompatIDsOffset and CompatIDsLength fields to extract the + /// hardware ID and compatible IDs, as shown in the following code example: + /// + /// + /// // parse the hardware ID, if it exists if (CompatIDsOffset > 1) { // Parse for hardware ID from index 0. // This is a single NULL-terminated string } // Parse the compatible IDs, if they exist if (CompatIDsLength > 0) { // Parse for list of compatible IDs from CompatIDsOffset. // This is a double NULL-terminated list of strings (i.e. MULTI-SZ) } + /// + /// + // https://docs.microsoft.com/en-us/windows/win32/api/setupapi/ns-setupapi-sp_drvinfo_detail_data_a typedef struct + // _SP_DRVINFO_DETAIL_DATA_A { DWORD cbSize; FILETIME InfDate; DWORD CompatIDsOffset; DWORD CompatIDsLength; ULONG_PTR Reserved; + // CHAR SectionName[LINE_LEN]; CHAR InfFileName[MAX_PATH]; CHAR DrvDescription[LINE_LEN]; CHAR HardwareID[ANYSIZE_ARRAY]; } + // SP_DRVINFO_DETAIL_DATA_A, *PSP_DRVINFO_DETAIL_DATA_A; + [PInvokeData("setupapi.h", MSDNShortId = "NS:setupapi._SP_DRVINFO_DETAIL_DATA_A")] + public class SP_DRVINFO_DETAIL_DATA_MGD + { + private SP_DRVINFO_DETAIL_DATA_MGD() { } + + private SP_DRVINFO_DETAIL_DATA_MGD(DateTime infDate, string sectionName, string infFileName, string drvDescription) + { + InfDate = infDate; + SectionName = sectionName; + InfFileName = infFileName; + DrvDescription = drvDescription; + } + + /// Date of the INF file for this driver. + public DateTime InfDate { get; } + + /// + /// A string that contains the name of the INF DDInstall section for this driver. This must be the basic + /// DDInstall section name, such as InstallSec, without any OS/architecture-specific extensions. + /// + public string SectionName { get; } + + /// A string that contains the full-qualified name of the INF file for this driver. + public string InfFileName { get; } + + /// A string that describes the driver. + public string DrvDescription { get; } + + /// The hardware ID that corresponds to the ID in the INF Models section. This value may be an empty string. + public string HardwareID { get; private set; } + + /// Contains a list of compatible IDs. These IDs correspond to the compatible IDs in the INF Models section. + public string[] CompatIDs { get; private set; } + + /// Creates an instance of from allocated memory. + /// A pointer to the memory containing . + /// The number of allocated bytes behind . + /// An instance of with the extracted data. + public static SP_DRVINFO_DETAIL_DATA_MGD Create(IntPtr self, SizeT allocatedBytes) => Create(new(self, false, allocatedBytes)); + + /// Creates an instance of from allocated memory. + /// The memory containing . + /// An instance of with the extracted data. + public static SP_DRVINFO_DETAIL_DATA_MGD Create(SafeCoTaskMemStruct dataMem) + { + SP_DRVINFO_DETAIL_DATA d = dataMem.Value; + SP_DRVINFO_DETAIL_DATA_MGD ret = new(d.InfDate.ToDateTime(), d.SectionName, d.InfFileName, d.DrvDescription); + IntPtr idPtr = dataMem.GetFieldAddress(nameof(HardwareID)); + long idoffset = idPtr.ToInt64() - dataMem.DangerousGetHandle().ToInt64(); + string[] ids = idPtr.ToStringEnum(allocatedBytes: dataMem.Size - idoffset).ToArray(); + ret.HardwareID = d.CompatIDsOffset <= 1 || ids.Length == 0 ? string.Empty : ids[0]; + ret.CompatIDs = d.CompatIDsOffset == 0 || ids.Length == 0 ? new string[0] : ids.Skip(d.CompatIDsOffset == 0 ? 0 : 1).ToArray(); + return ret; + } + } + /// /// An SP_DRVINSTALL_PARAMS structure contains driver installation parameters associated with a particular driver information element. ///