.NET - 深入系统编程 - 第 2 部分






4.88/5 (15投票s)
使用 C# 配置设备(第 2 部分)。如何枚举设备。
引言
在第 1 部分中,我演示了如何枚举设备类。现在让我们看看如何枚举该类的设备。
设备枚举
首先,我们再次看一下设备管理器信息图。这很简单 - 设备管理器在我们展开设备类树时枚举设备。
设备枚举的思路并不难理解
- 使用设备类名获取类 GUID(
SetupDiClassGuidsFromNameA
函数) - 获取设备类的设备信息集(
SetupDiGetClassDevsA
函数) - 为每个设备获取设备信息数据(
SetupDiGetClassDevsA
函数,此函数的第二个参数是设备类中的顺序设备索引,因此以设备索引 = 0, 1 等循环调用此函数)。 - 通过
SetupDiGetDeviceRegistryPropertyA
函数从注册表中获取设备名称。
下面是 C# 代码,它将为 PC 的选定设备类枚举设备。
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace DevInfo
{
class DeviceInfo
{
public const int DIGCF_PRESENT = (0x00000002);
public const int MAX_DEV_LEN = 1000;
public const int SPDRP_FRIENDLYNAME = (0x0000000C);
// FriendlyName (R/W)
public const int SPDRP_DEVICEDESC = (0x00000000);
// DeviceDesc (R/W)
[StructLayout(LayoutKind.Sequential)]
public class SP_DEVINFO_DATA
{
public int cbSize;
public Guid ClassGuid;
public int DevInst; // DEVINST handle
public ulong Reserved;
};
[DllImport("setupapi.dll")]//
public static extern Boolean
SetupDiClassGuidsFromNameA(string ClassN, ref Guid guids,
UInt32 ClassNameSize, ref UInt32 ReqSize);
[DllImport("setupapi.dll")]
public static extern IntPtr //result HDEVINFO
SetupDiGetClassDevsA(ref Guid ClassGuid, UInt32 Enumerator,
IntPtr hwndParent, UInt32 Flags);
[DllImport("setupapi.dll")]
public static extern Boolean
SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, UInt32 MemberIndex,
SP_DEVINFO_DATA DeviceInfoData);
[DllImport("setupapi.dll")]
public static extern Boolean
SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
[DllImport("setupapi.dll")]
public static extern Boolean
SetupDiGetDeviceRegistryPropertyA(IntPtr DeviceInfoSet,
SP_DEVINFO_DATA DeviceInfoData, UInt32 Property,
UInt32 PropertyRegDataType, StringBuilder PropertyBuffer,
UInt32 PropertyBufferSize, IntPtr RequiredSize);
public static int EnumerateDevices(UInt32 DeviceIndex,
string ClassName,
StringBuilder DeviceName)
{
UInt32 RequiredSize = 0;
Guid guid=Guid.Empty;
Guid[] guids=new Guid[1];
IntPtr NewDeviceInfoSet;
SP_DEVINFO_DATA DeviceInfoData= new SP_DEVINFO_DATA();
bool res=SetupDiClassGuidsFromNameA(ClassName,
ref guids[0],RequiredSize,
ref RequiredSize);
if(RequiredSize==0)
{
//incorrect class name:
DeviceName=new StringBuilder("");
return -2;
}
if(!res)
{
guids=new Guid[RequiredSize];
res=SetupDiClassGuidsFromNameA(ClassName,ref guids[0],RequiredSize,
ref RequiredSize);
if(!res || RequiredSize==0)
{
//incorrect class name:
DeviceName=new StringBuilder("");
return -2;
}
}
//get device info set for our device class
NewDeviceInfoSet=SetupDiGetClassDevsA(ref guids[0],0,IntPtr.Zero,
DIGCF_PRESENT);
if( NewDeviceInfoSet.ToInt32() == -1 )
if(!res)
{
//device information is unavailable:
DeviceName=new StringBuilder("");
return -3;
}
DeviceInfoData.cbSize = 28;
//is devices exist for class
DeviceInfoData.DevInst=0;
DeviceInfoData.ClassGuid=System.Guid.Empty;
DeviceInfoData.Reserved=0;
res=SetupDiEnumDeviceInfo(NewDeviceInfoSet,
DeviceIndex,DeviceInfoData);
if(!res) {
//no such device:
SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
DeviceName=new StringBuilder("");
return -1;
}
DeviceName.Capacity=MAX_DEV_LEN;
if(!SetupDiGetDeviceRegistryPropertyA(NewDeviceInfoSet,
DeviceInfoData,
SPDRP_FRIENDLYNAME,0,DeviceName,MAX_DEV_LEN,IntPtr.Zero) )
{
res = SetupDiGetDeviceRegistryPropertyA(NewDeviceInfoSet,
DeviceInfoData,SPDRP_DEVICEDESC,0,DeviceName,MAX_DEV_LEN,
IntPtr.Zero);
if(!res){
//incorrect device name:
SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
DeviceName=new StringBuilder("");
return -4;
}
}
return 0;
}
[STAThread]
static void Main(string[] args)
{
StringBuilder devices=new StringBuilder("");
UInt32 Index=0;
int result=0;
if(args.Length != 1)
{
Console.WriteLine("command line format:");
Console.WriteLine("DevInfo <CLASSNAME>");
return;
}
while(true)
{
result=EnumerateDevices(Index, args[0], devices);
Index++;
if(result == -2)
{
Console.WriteLine("Incorrect name of Class = {0}",
args[0]);
break;
}
if(result == -1)break;
if(result == 0)Console.WriteLine("Device{0} is {1}",
Index, devices);
}
}
}
}
此控制台应用程序的命令行 - DevInfo classname
classname
- 设备类的名称。您可以使用上一篇文章中的应用程序来查找正确的设备类名称。运行应用程序后,您可以在 PC 上查看任何设备类的设备。
摘要
现在我们可以将第一篇文章和这篇文章的代码结合起来,添加有关设备的信息(例如,资源,如 IRQ、端口等),并将其放入 Windows Forms 应用程序中。但这将是第 3 部分的主题。