65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (24投票s)

2004年3月9日

CPOL

2分钟阅读

viewsIcon

89032

downloadIcon

690

使用 C# 进行设备配置(第一部分)

引言

在之前的文章中,我展示了系统编程的应用。 我记得很多年前,我喜欢深入研究系统表或验证系统设施。 当然,那并不是一台真正的个人电脑,而是像 IBM360 或 PDP11 或 microVAX 这样的计算机,但那感觉很棒。 现在,多年以后,我仍然喜欢做 COM 接口、DLL 库、硬件配置等事情。 现在对我来说和以前一样有趣……嗯……系统编程……我永远爱你。

目标

普遍认为 C# 是一种“儿童语言”。 我不这么认为。 我认为这完全是不正确的。 为了证明这一点,我决定编写三个应用程序,显示有关硬件设备配置的信息。 我将演示 C# 如何使用 Win32 API 函数(甚至 DDK 中的函数)来访问有关配置的信息。 那些使用 C# 的人知道,这可以通过 P/Invoke 实现。 C# 成功解决的另一个问题是从非结构化的非托管数据(通常是执行 Win32 API 函数的结果)到托管结构的数据转换。 最后,可以使用此处讨论的技术与 Windows Forms 一起使用,使应用程序看起来很漂亮。

设备类

系统中的所有设备都加入到设备类中。 正如您在下图中所看到的,该类具有名称和 Guid(因此可以在注册表中找到)。 该类还可以具有描述。 例如,对于类“端口”,描述是“端口(COM 和 LPT)”。 类还具有存在于配置中的设备。

系统设备管理器提供有关(包括隐藏的)存在于 PC 上的类的信息

下面是 C# 中的代码,它将枚举 PC 上所有存在的设备类。 正如我所说,此代码使用 P/Invoke 来访问 DDK (cfgmgr32.dll) 和 SDK (setupapi.dll) DLL。

using System;
using System.Runtime.InteropServices;
using System.Text;


namespace DevClasses
{
 /// <summary>
 /// Summary description for Class.
 /// </summary>
 class DeviceClasses
 {
  /// <summary>
  /// The main entry point for the application.
  /// </summary>
  public const int MAX_NAME_PORTS=7;
  public const int RegDisposition_OpenExisting=(0x00000001); 
    // open key only if exists
  public const int CM_REGISTRY_HARDWARE=(0x00000000);

  public const int CR_SUCCESS = (0x00000000);
  public const int CR_NO_SUCH_VALUE = (0x00000025);
  public const int CR_INVALID_DATA = (0x0000001F);
  public const int DIGCF_PRESENT = (0x00000002);
  public const int DIOCR_INSTALLER = (0x00000001);
// MaximumAllowed access type to Reg.
  public const int MAXIMUM_ALLOWED = (0x02000000);
[StructLayout(LayoutKind.Sequential)]

 public class SP_DEVINFO_DATA
 {
 public int cbSize;
 public Guid ClassGuid;
 public int DevInst; // DEVINST handle
 public ulong Reserved;
 };


  [DllImport("cfgmgr32.dll")]
  public static extern UInt32
  CM_Open_DevNode_Key(IntPtr dnDevNode, UInt32 samDesired, 
         UInt32 ulHardwareProfile,
         UInt32 Disposition,IntPtr phkDevice, UInt32 ulFlags);

  [DllImport("cfgmgr32.dll")]
  public static extern UInt32
  CM_Enumerate_Classes(UInt32 ClassIndex,ref Guid ClassGuid, UInt32 Params);

  [DllImport("setupapi.dll")]//
  public static extern Boolean
   SetupDiClassNameFromGuidA(ref Guid ClassGuid,
            StringBuilder ClassName, //char * ?
   UInt32 ClassNameSize, ref UInt32 RequiredSize);

  [DllImport("setupapi.dll")]
  public static extern IntPtr
   SetupDiGetClassDevsA(ref Guid ClassGuid, UInt32 Enumerator,
   IntPtr  hwndParent, UInt32 Flags);

  [DllImport("setupapi.dll")]
  public static extern Boolean
   SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, UInt32 MemberIndex,
   ref SP_DEVINFO_DATA  DeviceInfoData);

  [DllImport("setupapi.dll")]
  public static extern Boolean
   SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

  [DllImport("setupapi.dll")]
  public static extern IntPtr
   SetupDiGetClassDevsA(ref Guid ClassGuid, UInt32 samDesired,
   UInt32 Flags, ref string hwndParent, IntPtr Reserved);

  [DllImport("setupapi.dll")]
  public static extern IntPtr
  SetupDiOpenClassRegKeyExA(
  ref Guid ClassGuid, UInt32 samDesired, int Flags, IntPtr MachineName,
  UInt32 Reserved);

  [DllImport("advapi32.dll")]
  public static extern UInt32
  RegQueryValueA(IntPtr KeyClass,UInt32 SubKey,
         StringBuilder ClassDescription,ref UInt32 sizeB);


  [DllImport("user32.dll")]
  public static extern Boolean
  CharToOem(String lpszSrc, StringBuilder lpszDst);

  public static int EnumerateClasses(UInt32 ClassIndex, 
   ref StringBuilder ClassName, StringBuilder ClassDescription, 
        ref bool DevicePresent)
  {
   Guid ClassGuid=Guid.Empty;
   IntPtr NewDeviceInfoSet;
   SP_DEVINFO_DATA DeviceInfoData;
   UInt32 result;
   StringBuilder name=new StringBuilder("");
   bool resNam=false;
   UInt32 RequiredSize=0;

   IntPtr ptr;

   result = CM_Enumerate_Classes(ClassIndex, ref ClassGuid,0);


    ClassName=new StringBuilder("");
    DevicePresent=false;
   //incorrect device class:
   if(result == CR_INVALID_DATA)
   {
    return -2;
   }
  //device class is absent
   if(result == CR_NO_SUCH_VALUE)
   {
    return -1;
   }
  //bad param. - fatal error
   if(result != CR_SUCCESS)
   {
    return -3;
   }


   name.Capacity=0;
   resNam=SetupDiClassNameFromGuidA(ref ClassGuid,name,RequiredSize,
         ref RequiredSize);
   if(RequiredSize > 0)
    {
    name.Capacity=(int)RequiredSize;
    resNam=SetupDiClassNameFromGuidA(ref ClassGuid,name,
           RequiredSize,ref RequiredSize);
    }

   NewDeviceInfoSet=SetupDiGetClassDevsA(
    ref ClassGuid,
    0,
    IntPtr.Zero,
    DIGCF_PRESENT);

   if(NewDeviceInfoSet.ToInt32() == -1)
    {  DevicePresent=false;
      ClassName=name;
      return 0;}

   IntPtr KeyClass=SetupDiOpenClassRegKeyExA(
    ref ClassGuid, MAXIMUM_ALLOWED, DIOCR_INSTALLER,IntPtr.Zero,0);
   if(KeyClass.ToInt32() == -1)
    {  DevicePresent=false;
      ClassName=name;
      return 0;}


   UInt32 sizeB=1000;
   String abcd="";
   StringBuilder CD=new StringBuilder("");
   ClassDescription.Capacity=1000;
  
   UInt32 res=RegQueryValueA(KeyClass,0,ClassDescription,ref sizeB);


   if(res != 0)ClassDescription=new StringBuilder("");
   SetupDiDestroyDeviceInfoList(NewDeviceInfoSet);
    ClassName=name;
    DevicePresent=true;

   return 0;

  }

  [STAThread]
  static void Main(string[] args)
  {
   StringBuilder classes=new StringBuilder("");
   StringBuilder classesDescr=new StringBuilder("");

   StringBuilder classesDescrOEM=new StringBuilder("");
   classesDescrOEM.Capacity=1000;
   Boolean DevExist=false;
   UInt32 i=0;
   while(true)
   {
   int res=EnumerateClasses(i,ref classes,classesDescr,ref DevExist);
   if(res == -1)break;
   ++i;
   if(res < -1 || !DevExist)continue;
   Console.WriteLine("ClassName={0}, Description={1}",classes,classesDescr);
   }
   return;
  }
 }
}

运行应用程序后,您将看到 PC 上的所有设备类(托管版本;我已在 Win2000 上测试过)。

© . All rights reserved.