Click here to Skip to main content
15,881,757 members
Articles / Programming Languages / C#
Article

.NET - Diving into System Programming - Part 1

Rate me:
Please Sign up or sign in to vote.
4.79/5 (28 votes)
8 Mar 2004CPOL2 min read 87K   689   75   10
Device configuration using C# (Part 1)

Introduction

In my previous articles, I have demonstrated applications for System programming.  I remember how, many years ago I liked to dig into the system tables or verify system facility. Of course, it was not really a PC, but computers like IBM360 or PDP11 or microVAX but it was wonderful. Now after these years I still like to do things like COM interfaces, DLL libraries, hardware configuration etc. Now it is as interesting for me as well as before...Uh... System Programming... I will always love you.

Objectives

It is a sufficiently common opinion that C# is a "child language". I don't think so. In my opinion it is absolutely incorrect. So to disprove it I decided to write three applications that show information about hardware device configuration. I will demonstrate how C# can use Win32 API functions (even functions from DDK) to give access to information about configuration. Those who use C# know that it is possible via P/Invoke. Another problem that C# successfully solves is data marshalling from unstructured unmanaged data (commonly obtained as a result of execution of Win32 API functions) to managed structures. And for last it is possible to use the techniques discussed here with Windows Forms so the application can look pretty.

Device classes

All devices in the system join in the device classes. As you can see in the below picture, the class has name and Guid (so it can be found in Registry). The class can also have a description. For example, for class "Ports" the description is "Ports (COM & LPT)". Class also has devices that are present in the configuration.

Image 1

System Device Manager gives information about classes (including hidden ones) that are present on PC:

Image 2

Below you see code in C# that will enumerate all present device classes for PC. As I said this code uses P/Invoke for accessing DDK (cfgmgr32.dll) and SDK (setupapi.dll) DLLs.

C#
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;
  }
 }
}

After running the application you will see all device classes on your PC (managed version; I tested for Win2000).

Image 3

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Ukraine Ukraine
I am C++ Builder developer.
I am interesting in WMI, Shell, some deep
COM interface. Beside these I am Brainbench
Win32 API Master.
Now I very like Microsoft .NET and C#. I made some firsts OPOS drivers for Ukrainian fiscal printers.

Comments and Discussions

 
QuestionWhat about exploring further into the Ports Pin
wasouthpnt21-Jan-10 4:39
wasouthpnt21-Jan-10 4:39 
Generalnot working on 64Bit Pin
Kofi Jedamzik21-Jul-08 5:01
Kofi Jedamzik21-Jul-08 5:01 
GeneralRe: not working on 64Bit Pin
Vladimir Afanasyev21-Jul-08 5:49
Vladimir Afanasyev21-Jul-08 5:49 
GeneralRe: not working on 64Bit Pin
meraydin28-Jul-10 21:01
meraydin28-Jul-10 21:01 
GeneralRe: not working on 64Bit Pin
Vladimir Afanasyev30-Jul-10 10:18
Vladimir Afanasyev30-Jul-10 10:18 
GeneralAbout System Watching Pin
Anonymous22-Aug-05 20:46
Anonymous22-Aug-05 20:46 
GeneralRe: About System Watching Pin
Vladimir Afanasyev25-Aug-05 23:17
Vladimir Afanasyev25-Aug-05 23:17 
GeneralWMI Pin
Judah Gabriel Himango10-Nov-04 6:24
sponsorJudah Gabriel Himango10-Nov-04 6:24 
Hopefully this isn't too far off-topic, but I'm curious, can we use WMI in C# (via System.Management.dll) to get the list of workgroups the machine is connected to? Also, is it possible to get a list of machines on the network using WMI?

Any remotely useful information on my blog will be removed immediately.
Judah Himango


GeneralRe: WMI Pin
Vladimir Afanasyev11-Nov-04 2:51
Vladimir Afanasyev11-Nov-04 2:51 
GeneralJust what I was looking for! Pin
User 9137321-Oct-04 16:31
User 9137321-Oct-04 16:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.