Skip to content
This repository has been archived by the owner on Jul 26, 2023. It is now read-only.

Add SetupDiGetDriverInfoDetail #481

Merged
merged 2 commits into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/CfgMgr32/CfgMgr32+CM_NOTIFY_EVENT_DATA.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public unsafe ref struct CM_NOTIFY_EVENT_DATA

/// <summary>
/// A pointer to a null-terminated symbolic link path of the device interface to which the notification event data pertains.
/// Convert this to a string using <c>new string(eventData->SymbolicLink)</c>.
/// </summary>
/// <remarks>Convert this to a string by passing its value to <see cref="String(char*)"/>.</remarks>
[FieldOffset(24)]
public fixed char SymbolicLink[1];

Expand Down Expand Up @@ -79,8 +79,8 @@ public unsafe ref struct CM_NOTIFY_EVENT_DATA

/// <summary>
/// A pointer to a null-terminated device instance ID of the device to which the notification event data pertains.
/// Convert this to a string using <c>new string(eventData->InstanceId)</c>.
/// </summary>
/// <remarks>Convert this to a string by passing its value to <see cref="String(char*)"/>.</remarks>
[FieldOffset(8)]
public fixed char InstanceId[1];
}
Expand Down
45 changes: 45 additions & 0 deletions src/SetupApi.Tests/SP_DRVINFO_DETAIL_DATAFacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright © .NET Foundation and Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Runtime.InteropServices;
using Xunit;
using static PInvoke.SetupApi;

public class SP_DRVINFO_DETAIL_DATAFacts
{
[Fact]
public void Layout_Test()
{
// These values listed below have been obtained by determining the size of the struct and the offset of its
// fields using a C program which calls sizeof() and offsetof().
if (Environment.Is64BitProcess)
AArnott marked this conversation as resolved.
Show resolved Hide resolved
{
Assert.Equal(0, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.cbSize)).ToInt32());
Assert.Equal(4, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.InfDate)).ToInt32());
Assert.Equal(0xc, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.CompatIDsOffset)).ToInt32());
Assert.Equal(0x10, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.CompatIDsLength)).ToInt32());
Assert.Equal(0x18, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.Reserved)).ToInt32());
Assert.Equal(0x20, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.SectionName)).ToInt32());
Assert.Equal(0x220, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.InfFileName)).ToInt32());
Assert.Equal(0x428, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.DrvDescription)).ToInt32());
Assert.Equal(0x628, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.HardwareID)).ToInt32());

Assert.Equal(0x630, SP_DRVINFO_DETAIL_DATA.Create().cbSize);
}
else
{
Assert.Equal(0, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.cbSize)).ToInt32());
Assert.Equal(4, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.InfDate)).ToInt32());
Assert.Equal(0xc, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.CompatIDsOffset)).ToInt32());
Assert.Equal(0x10, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.CompatIDsLength)).ToInt32());
Assert.Equal(0x14, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.Reserved)).ToInt32());
Assert.Equal(0x18, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.SectionName)).ToInt32());
Assert.Equal(0x218, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.InfFileName)).ToInt32());
Assert.Equal(0x420, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.DrvDescription)).ToInt32());
Assert.Equal(0x620, Marshal.OffsetOf<SP_DRVINFO_DETAIL_DATA>(nameof(SP_DRVINFO_DETAIL_DATA.HardwareID)).ToInt32());

Assert.Equal(0x622, SP_DRVINFO_DETAIL_DATA.Create().cbSize);
}
}
}
208 changes: 123 additions & 85 deletions src/SetupApi.Tests/SetupApiFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices;
using PInvoke;
using Xunit;
using static PInvoke.SetupApi;
Expand All @@ -14,149 +13,188 @@ public unsafe class SetupApiFacts
[Fact]
public void SetupDiCreateDeviceInfoListWithoutGuidTest()
{
using (var handle = SetupApi.SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero))
{
Assert.False(handle.IsInvalid);
}
using var handle = SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero);
Assert.False(handle.IsInvalid);
}

[Fact]
public void SetupDiCreateDeviceInfoWithGuidListTest()
{
Guid processorId = SetupApi.DeviceSetupClass.Processor;
using (var handle = SetupApi.SetupDiCreateDeviceInfoList(&processorId, IntPtr.Zero))
{
Assert.False(handle.IsInvalid);
}
Guid processorId = DeviceSetupClass.Processor;
using var handle = SetupDiCreateDeviceInfoList(&processorId, IntPtr.Zero);
Assert.False(handle.IsInvalid);
}

[Fact]
public void SetupDiOpenDeviceInfoTest()
{
using (var deviceInfoSet = SetupApi.SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero))
{
SP_DEVINFO_DATA deviceInfoData = SP_DEVINFO_DATA.Create();
using var deviceInfoSet = SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero);

// If DeviceInstanceId is NULL or references a zero-length string, SetupDiOpenDeviceInfo adds a device information element
// to the supplied device information set, if one does not already exist, for the root device in the device tree.
string deviceId = null;
Assert.True(SetupApi.SetupDiOpenDeviceInfo(deviceInfoSet, deviceId, IntPtr.Zero, SetupDiOpenDeviceInfoFlags.None, ref deviceInfoData));
}
SP_DEVINFO_DATA deviceInfoData = SP_DEVINFO_DATA.Create();

// If DeviceInstanceId is NULL or references a zero-length string, SetupDiOpenDeviceInfo adds a device information element
// to the supplied device information set, if one does not already exist, for the root device in the device tree.
string deviceId = null;
Assert.True(SetupDiOpenDeviceInfo(deviceInfoSet, deviceId, IntPtr.Zero, SetupDiOpenDeviceInfoFlags.None, ref deviceInfoData));
}

[Fact]
public void SetupDiSetSelectedDeviceTest()
{
using (var deviceInfoSet = SetupApi.SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero))
{
SP_DEVINFO_DATA deviceInfoData = SP_DEVINFO_DATA.Create();
using var deviceInfoSet = SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero);

// If DeviceInstanceId is NULL or references a zero-length string, SetupDiOpenDeviceInfo adds a device information element
// to the supplied device information set, if one does not already exist, for the root device in the device tree.
string deviceId = null;
Assert.True(SetupApi.SetupDiOpenDeviceInfo(deviceInfoSet, deviceId, IntPtr.Zero, SetupDiOpenDeviceInfoFlags.None, ref deviceInfoData));
SP_DEVINFO_DATA deviceInfoData = SP_DEVINFO_DATA.Create();

Assert.True(SetupApi.SetupDiSetSelectedDevice(deviceInfoSet, deviceInfoData));
// If DeviceInstanceId is NULL or references a zero-length string, SetupDiOpenDeviceInfo adds a device information element
// to the supplied device information set, if one does not already exist, for the root device in the device tree.
string deviceId = null;
Assert.True(SetupDiOpenDeviceInfo(deviceInfoSet, deviceId, IntPtr.Zero, SetupDiOpenDeviceInfoFlags.None, ref deviceInfoData));

deviceInfoData = SP_DEVINFO_DATA.Create();
Assert.False(SetupApi.SetupDiSetSelectedDevice(deviceInfoSet, deviceInfoData));
}
Assert.True(SetupDiSetSelectedDevice(deviceInfoSet, deviceInfoData));

deviceInfoData = SP_DEVINFO_DATA.Create();
Assert.False(SetupDiSetSelectedDevice(deviceInfoSet, deviceInfoData));
}

[Fact]
public void SetupDiGetDeviceInstallParamsTest()
{
using (var deviceInfoSet = SetupApi.SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero))
{
SP_DEVINFO_DATA deviceInfoData = SP_DEVINFO_DATA.Create();
using var deviceInfoSet = SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero);

// If DeviceInstanceId is NULL or references a zero-length string, SetupDiOpenDeviceInfo adds a device information element
// to the supplied device information set, if one does not already exist, for the root device in the device tree.
string deviceId = null;
if (!SetupApi.SetupDiOpenDeviceInfo(deviceInfoSet, deviceId, IntPtr.Zero, SetupDiOpenDeviceInfoFlags.None, ref deviceInfoData))
{
throw new Win32Exception();
}
SP_DEVINFO_DATA deviceInfoData = SP_DEVINFO_DATA.Create();

SP_DEVINSTALL_PARAMS deviceInstallParams = SP_DEVINSTALL_PARAMS.Create();
// If DeviceInstanceId is NULL or references a zero-length string, SetupDiOpenDeviceInfo adds a device information element
// to the supplied device information set, if one does not already exist, for the root device in the device tree.
string deviceId = null;
if (!SetupDiOpenDeviceInfo(deviceInfoSet, deviceId, IntPtr.Zero, SetupDiOpenDeviceInfoFlags.None, ref deviceInfoData))
{
throw new Win32Exception();
}

if (!SetupApi.SetupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData, ref deviceInstallParams))
{
throw new Win32Exception();
}
SP_DEVINSTALL_PARAMS deviceInstallParams = SP_DEVINSTALL_PARAMS.Create();

deviceInfoData = SP_DEVINFO_DATA.Create();
Assert.False(SetupApi.SetupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData, ref deviceInstallParams));
if (!SetupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData, ref deviceInstallParams))
{
throw new Win32Exception();
}

deviceInfoData = SP_DEVINFO_DATA.Create();
Assert.False(SetupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData, ref deviceInstallParams));
}

[Fact]
public void SetupDiGetSetDeviceInstallParamsTest()
{
using (var deviceInfoSet = SetupApi.SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero))
{
SP_DEVINFO_DATA deviceInfoData = SP_DEVINFO_DATA.Create();
using var deviceInfoSet = SetupDiCreateDeviceInfoList((Guid*)null, IntPtr.Zero);

// If DeviceInstanceId is NULL or references a zero-length string, SetupDiOpenDeviceInfo adds a device information element
// to the supplied device information set, if one does not already exist, for the root device in the device tree.
string deviceId = null;
Assert.True(SetupApi.SetupDiOpenDeviceInfo(deviceInfoSet, deviceId, IntPtr.Zero, SetupDiOpenDeviceInfoFlags.None, ref deviceInfoData));
SP_DEVINFO_DATA deviceInfoData = SP_DEVINFO_DATA.Create();

SP_DEVINSTALL_PARAMS deviceInstallParams = SP_DEVINSTALL_PARAMS.Create();
// If DeviceInstanceId is NULL or references a zero-length string, SetupDiOpenDeviceInfo adds a device information element
// to the supplied device information set, if one does not already exist, for the root device in the device tree.
string deviceId = null;
Assert.True(SetupDiOpenDeviceInfo(deviceInfoSet, deviceId, IntPtr.Zero, SetupDiOpenDeviceInfoFlags.None, ref deviceInfoData));

Assert.True(SetupApi.SetupDiSetDeviceInstallParams(deviceInfoSet, deviceInfoData, deviceInstallParams));
SP_DEVINSTALL_PARAMS deviceInstallParams = SP_DEVINSTALL_PARAMS.Create();

deviceInfoData = SP_DEVINFO_DATA.Create();
Assert.False(SetupApi.SetupDiSetDeviceInstallParams(deviceInfoSet, deviceInfoData, deviceInstallParams));
}
Assert.True(SetupDiSetDeviceInstallParams(deviceInfoSet, deviceInfoData, deviceInstallParams));

deviceInfoData = SP_DEVINFO_DATA.Create();
Assert.False(SetupDiSetDeviceInstallParams(deviceInfoSet, deviceInfoData, deviceInstallParams));
}

[Fact]
public void SetupDiBuildDriverInfoListTest()
{
Guid usbDeviceId = SetupApi.DeviceSetupClass.UsbDevice;
Guid usbDeviceId = DeviceSetupClass.UsbDevice;

using (var deviceInfoSet = SetupApi.SetupDiCreateDeviceInfoList(&usbDeviceId, IntPtr.Zero))
{
Assert.True(SetupApi.SetupDiBuildDriverInfoList(deviceInfoSet, (SP_DEVINFO_DATA*)null, DriverType.SPDIT_CLASSDRIVER));
}
using var deviceInfoSet = SetupDiCreateDeviceInfoList(&usbDeviceId, IntPtr.Zero);
Assert.True(SetupDiBuildDriverInfoList(deviceInfoSet, (SP_DEVINFO_DATA*)null, DriverType.SPDIT_CLASSDRIVER));
}

[Fact]
public void SetupDiEnumDriverInfoListTest()
{
Guid usbDeviceId = SetupApi.DeviceSetupClass.Net;
Guid usbDeviceId = DeviceSetupClass.Net;

using (var deviceInfoSet = SetupApi.SetupDiCreateDeviceInfoList(&usbDeviceId, IntPtr.Zero))
using var deviceInfoSet = SetupDiCreateDeviceInfoList(&usbDeviceId, IntPtr.Zero);

Assert.True(SetupDiBuildDriverInfoList(deviceInfoSet, (SP_DEVINFO_DATA*)null, DriverType.SPDIT_CLASSDRIVER));

uint i = 0;
SP_DRVINFO_DATA driverInfoData = SP_DRVINFO_DATA.Create();
Collection<SP_DRVINFO_DATA> driverInfos = new Collection<SP_DRVINFO_DATA>();
while (SetupDiEnumDriverInfo(deviceInfoSet, null, DriverType.SPDIT_CLASSDRIVER, i++, ref driverInfoData))
{
Assert.True(SetupApi.SetupDiBuildDriverInfoList(deviceInfoSet, (SP_DEVINFO_DATA*)null, DriverType.SPDIT_CLASSDRIVER));
driverInfos.Add(driverInfoData);
}

uint i = 0;
// We should have enumerated at least one driver
Assert.NotEmpty(driverInfos);

SP_DRVINFO_DATA driverInfoData = SP_DRVINFO_DATA.Create();
var loopbackDrivers =
driverInfos
.Where(d => new string(d.Description).IndexOf("loopback", StringComparison.OrdinalIgnoreCase) >= 0).ToArray();

Collection<SP_DRVINFO_DATA> driverInfos = new Collection<SP_DRVINFO_DATA>();
var loopbackDriver = Assert.Single(loopbackDrivers);

while (SetupApi.SetupDiEnumDriverInfo(deviceInfoSet, null, DriverType.SPDIT_CLASSDRIVER, i, ref driverInfoData))
{
driverInfos.Add(driverInfoData);
i += 1;
}
Assert.Equal("Microsoft KM-TEST Loopback Adapter", new string(loopbackDriver.Description));
Assert.Equal(DriverType.SPDIT_CLASSDRIVER, loopbackDriver.DriverType);
Assert.NotEqual(0u, loopbackDriver.DriverVersion);
Assert.Equal("Microsoft", new string(loopbackDriver.MfgName));
Assert.Equal("Microsoft", new string(loopbackDriver.ProviderName));
}

[Fact]
public unsafe void SetupDiGetDriverInfoDetailTest()
{
Guid usbDeviceId = DeviceSetupClass.Net;

using var deviceInfoSet = SetupDiCreateDeviceInfoList(&usbDeviceId, IntPtr.Zero);

Assert.True(SetupDiBuildDriverInfoList(deviceInfoSet, (SP_DEVINFO_DATA*)null, DriverType.SPDIT_CLASSDRIVER));

uint i = 0;
SP_DRVINFO_DATA driverInfoData = SP_DRVINFO_DATA.Create();
Collection<SP_DRVINFO_DATA> driverInfos = new Collection<SP_DRVINFO_DATA>();
while (SetupDiEnumDriverInfo(deviceInfoSet, null, DriverType.SPDIT_CLASSDRIVER, i++, ref driverInfoData))
{
driverInfos.Add(driverInfoData);
}

// We should have enumerated at least one driver
Assert.NotEmpty(driverInfos);
// We should have enumerated at least one driver
Assert.NotEmpty(driverInfos);

var loopbackDrivers =
driverInfos
.Where(d => d.DescriptionString.IndexOf("loopback", StringComparison.OrdinalIgnoreCase) >= 0).ToArray();
var loopbackDrivers =
driverInfos
.Where(d => new string(d.Description).IndexOf("loopback", StringComparison.OrdinalIgnoreCase) >= 0).ToArray();

var loopbackDriver = Assert.Single(loopbackDrivers);
var loopbackDriver = Assert.Single(loopbackDrivers);

byte[] buffer = new byte[0x1000];
fixed (byte* ptr = buffer)
{
var drvInfoDetailData = (SP_DRVINFO_DETAIL_DATA*)ptr;
*drvInfoDetailData = SP_DRVINFO_DETAIL_DATA.Create();

if (!SetupDiGetDriverInfoDetail(
deviceInfoSet,
null,
&loopbackDriver,
ptr,
buffer.Length,
out int requiredSize))
{
throw new Win32Exception();
}

Assert.Equal("Microsoft KM-TEST Loopback Adapter", loopbackDriver.DescriptionString);
Assert.Equal(DriverType.SPDIT_CLASSDRIVER, loopbackDriver.DriverType);
Assert.NotEqual(0u, loopbackDriver.DriverVersion);
Assert.Equal("Microsoft", loopbackDriver.MfgNameString);
Assert.Equal("Microsoft", loopbackDriver.ProviderNameString);
Assert.Equal(0, (int)drvInfoDetailData->CompatIDsLength);
Assert.Equal(0x8, drvInfoDetailData->CompatIDsOffset);
Assert.Equal("Microsoft KM-TEST Loopback Adapter", new string(drvInfoDetailData->DrvDescription));
Assert.NotEqual(0, drvInfoDetailData->InfDate.dwHighDateTime);
Assert.NotEqual(0, drvInfoDetailData->InfDate.dwLowDateTime);
Assert.Equal(@"C:\WINDOWS\INF\netloop.inf", new string(drvInfoDetailData->InfFileName), ignoreCase: true);
Assert.Equal("kmloop.ndi", new string(drvInfoDetailData->SectionName), ignoreCase: true);
Assert.Equal("*msloop", new string(drvInfoDetailData->HardwareID));
}
}
}
Loading