Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to query miniport driver information (802.11 OIDs) using the DeviceIOControl() function

0.00/5 (No votes)
10 Apr 2009 1  
Query 802.11 OIDs using DeviceIOControl from a C# application.

Introduction

With this article, I would like to demonstrate how to query 802.11 OIDs from a C# .NET application. Noramlly, we use the DeviceIOControl API for querying an NDIS miniport driver. The DeviceIOControl API sends a control code directly to a specified device driver and the device performs the corresponding operation.

How to use the DeviceIOControl function from a C# application is ambiguous. Because the developer has to implement the platform invoke mechanism and need to take care of the marshaling of data between managed and unmanaged code.

I have seen a lot of queries in discussion forums about accessing a miniport driver from a C# application. This article demonstrates how to use the DeviceIOControl function from a C# application. As an example, we will see how to query for the signal strength of a wireless network.

Background

Device Driver programmers are familiar with the NDIS miniport driver. An NDIS miniport driver has two main functions: managing the network card and interfacing with other drivers like a protocol driver. Miniport drivers that support 802.11 interfaces for network interface cards must support all mandatory native IEEE 802.11 OIDs.

Using the code

In this article, I will show you a C# console application which queries the signal strength of the currently connected wireless network. This application uses the platform invoke mechanism and calls the DeviceIOControl function with control code OID_802_11_RSSI.

A OID_802_11_RSSI OID requests the miniport driver to return the signal strength of the wireless network.

/// <summary>
/// Print Signal Strength value of currently connected wireless network
/// </summary>
public void printSignalStrength(string wlanInterfaceGuid)
{
    int hFileHandle = new int();
    IntPtr ptrOutput = IntPtr.Zero;
    IntPtr ptrInput = IntPtr.Zero;

    try
    {
        hFileHandle = INVALID_HANDLE_VALUE;
        string devName = string.Format("\\\\.\\{0}", wlanInterfaceGuid);

        //open handle
        hFileHandle = CreateFile(devName, GENERIC_READ | GENERIC_WRITE,
                    0,
                    (IntPtr)0,
                    OPEN_EXISTING,
                    0,
                    NULL);

        if (hFileHandle == INVALID_HANDLE_VALUE)
        {
            Console.WriteLine("Cannot open driver handle");
            return;
        }
        else
        {
            //OID - IOCTL_NDIS_QUERY_GLOBAL_STATS
            int IOCTL_NDIS_QUERY = new int();
            IOCTL_NDIS_QUERY = IOCTL_NDIS_QUERY_GLOBAL_STATS();

            //OID length
            uint oidCodeLength = 4; //bytes
            //size of output buffer
            uint OutputBufferSize = 1000;

            //bytes returned
            int bytesReturned = new int();
            //passing NDIS driver OID into DeviceIOControl
            GCHandle handle = GCHandle.Alloc(OID_802_11_RSSI,  GCHandleType.Pinned);

            ptrInput = handle.AddrOfPinnedObject();
          
            //Output buffer
            ptrOutput = Marshal.AllocHGlobal((int)OutputBufferSize);
            ZeroMemory(ptrOutput, (int)OutputBufferSize);

            //calling DeviceIOControl
            if (DeviceIoControl(hFileHandle, IOCTL_NDIS_QUERY, ptrInput, 
                oidCodeLength, ptrOutput, OutputBufferSize, out bytesReturned, 0))
            {
                Console.WriteLine("DeviceIOControl success");
     
                //Marshing data back into .net data type
                Int32 rssi = (Int32)Marshal.PtrToStructure(ptrOutput, typeof(Int32));
                //recived signal strength 
                Console.WriteLine("Received Signal Strength: {0}", rssi);
 
               if (ptrOutput != IntPtr.Zero)
               {
                   Marshal.FreeHGlobal(ptrOutput);
                   ptrOutput = IntPtr.Zero;
               }

               handle.Free();

            }
            else
            {
                Console.WriteLine("DeviceIOControl failed");
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine("Exception: {0}", e.Message);
    }
    finally
    {
        //free allocated
        if (ptrOutput != IntPtr.Zero)
        Marshal.FreeHGlobal(ptrOutput);
        //close device handle
        CloseHandle(hFileHandle);
    }
}

The above code snippet shows how to query a 802.11 OID using the DeviceIOControl function. Let me explain the details here.

string devName = string.Format("\\\\.\\{0}", wlanInterfaceGuid);
//open handle
hFileHandle = CreateFile(devName, GENERIC_READ | GENERIC_WRITE,
            0,
            (IntPtr)0,
            OPEN_EXISTING,
            0,
            NULL);

if (hFileHandle == INVALID_HANDLE_VALUE)
{
    Console.WriteLine("Cannot open driver handle");
} 
else
{
    //DeviceIOControl query
}

The CreateFile() function opens a handle to the device. In this case, the device is a wireless network adapter. The first argument accepts the device name in the format “\\\\.\\{A5128180-8811-451C-BBBD-2BE2F69F65C9}”. “{A5128180-8811-451C-BBBD-2BE2F69F65C9}” specifies the GUID for the wireless card. I have hardcoded this card GUID for my wireless card. You can check the system Registry for the list of available cards in your machine. This is available under the following Registry key:

  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\Current Version\NetworkCards

This key lists down all the available network adapters in the system. The ‘ServiceName’ Registry sub-key specifies the GUID value for that card. Network adapters can be enumerated using IPHelper functions also. For more reference about enumerating network cards, please go through this MSDN link: http://msdn2.microsoft.com/en-us/library/aa365798(VS.85).aspx.

Next, we will see the DeviceIOControl() calling section.

//calling DeviceIOControl
if (DeviceIoControl(hFileHandle, IOCTL_NDIS_QUERY, ptrInput, oidCodeLength, 
    ptrOutput, OutputBufferSize, out bytesReturned, 0))
{
      Console.WriteLine("DeviceIOControl success");
}

DeviceIOControl() accepts the following arguments:

  • Handle to the network adapter
  • IO control code; in our case, it’s IOCTL_NDIS_QUERY_GLOBAL_STATS
  • Pointer to an input buffer that contains 802.11 OID
  • Specifies the size of the input buffer used to query 802.11 OID
  • Pointer to the output buffer that receives the result
  • Specifies the output buffer size
  • Pointer to the buffer that contains the actual size of the result
  • Specifies ‘0’ for a synchronous query

I am not going to explain more about the GCHandle and Marshal classes as that is beyond the scope of this article.

If DeviceIOControl returns a non-zero value, it indicates that the query is success, and the result can be received in the output buffer.

if (DeviceIoControl(hFileHandle, IOCTL_NDIS_QUERY, ptrInput, 
    oidCodeLength, ptrOutput, OutputBufferSize, out bytesReturned, 0))
{
    Console.WriteLine("DeviceIOControl success");

    //Marshing data back into .net data type
    Int32 rssi = (Int32)Marshal.PtrToStructure(ptrOutput, typeof(Int32));
                        
    //recived signal strength 
    Console.WriteLine("Received Signal Strength: {0}", rssi);

    if (ptrOutput != IntPtr.Zero)
    {
        Marshal.FreeHGlobal(ptrOutput);
        ptrOutput = IntPtr.Zero;
    }

    handle.Free();
}

Now, the result is available in the output buffer and we have to marshal that data and transfer it into a .NET data type.

//Marshing data back into .net data type
Int32 rssi = (Int32)Marshal.PtrToStructure(ptrOutput, typeof(Int32));

Marshal.PtrToStructure() will do the marshaling of the unmanaged data to managed data, and the user can see the received signal strength value in the console window.

Conclusion

This article demonstrates how to query 802.11 OIDs using the DeviceIOControl() function from a C# application. As a sample, we have seen querying the signal strength of the currently connected wireless network. In my next article, I will show you how to access the same 802.11 OID using the Windows Management Instrumentation (WMI) mechanism.

References

  1. How to query miniport driver information (802.11 OIDs) using Windows Management Instrumentation (WMI) mechanism
  2. How to access wireless network parameters using native WiFi API

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here