User-Mode
Binding Enumeration Code Fragments

Copyright © 2003 by Printing Communications Assoc., Inc. (PCAUSA). All rights reserved

We have written the driver dispatch handler for IOCTL_PTUSERIO_ENUMERATE that fills the the user buffer with binding information. Now we need to write user-mode code that illustrates how to call the driver for this information and how to display the binding information.

Implementation of this function is straightforward. A DeviceIoControl call will be made on the handle returned by PtOpenControlChannel. The call will pass a user-mode output buffer to the PassThru driver on IOCTL_PTUSERIO_ENUMERATE (defined in IOCommon.h). The driver's DevIoControl dispatcher will call a function that will fill the user's output buffer with an array of binding name strings..

First we make a trivial function PtEnumerateBindings that is a wrapper around DeviceIoControl. This function makes the IOCTL_PTUSERIO_ENUMERATE request to the driver and, if successful, returns a buffer that has been filled with the driver binding names.

The binding name buffer is an array of null-terminated Unicode strings with the end of the list being identified by an empty Unicode string.

The _tmain function calls PtEnumerateBindings. If the call is successful it loops through the buffer and displays binding names on the console:

If all is well running the PTUserIo application will display the binding names on the console:

PassThru User I/O Test Application
Copyright (c) 2003 Printing Communications Assoc., Inc. (PCAUSA)
All rights reserved.
Driver Bindings:
   "\Device\{67A4853E-1940-43A3-A442-74701B5133B0}"
   "\Device\{0611AD65-41D8-4BB1-8A8F-43008BB362A3}"
   "\Device\{8DA82E8E-D091-4FB2-902A-673FBEC2DA7C}"

This display is hardly human readable. However, it does confirm that the binding enumeration function works.

This test was run on a Windows XP SP1 system with three NDIS miniports installed. Using other APIs we can display additional information describing each binding:

PassThru User I/O Test Application
Copyright (c) 2003 Printing Communications Assoc., Inc. (PCAUSA)
All rights reserved.
Driver Bindings:
   "\Device\{67A4853E-1940-43A3-A442-74701B5133B0}"
      Description: " Intel 8255x-based Integrated Fast Ethernet"
      Medium: 802.3
      Mac address = 00-00-39-14-92-A9
      Media Connect Status: Disconnected
   "\Device\{0611AD65-41D8-4BB1-8A8F-43008BB362A3}"
      Description: " NdisWan Adapter"
      Medium: 802.3
      Mac address = C0-F2-20-52-41-53
      Media Connect Status: Connected
   "\Device\{8DA82E8E-D091-4FB2-902A-673FBEC2DA7C}"
      Description: "3CRWE737A AirConnect Wireless LAN PC Card"
      Medium: 802.3
      Mac address = 00-50-DA-03-4E-6C
      Media Connect Status: Connected

 

/////////////////////////////////////////////////////////////////////////////
//// PtEnumerateBindings
//
// Purpose
// Use DeviceIoControl to query the PassThru device for a list of its
// current bindings.
//
// Parameters
//   PtHandle  - Handle returned from a successful call to PtOpenControlChannel.
//   Buf       - Pointer to a unsigned character array to be filled with
//               the PassThru driver's binding information.
//   BufLength - Pointer to a DWORD. On input this variable must be filled with
//               the size (in bytes) of the buffer. On successful completion the
//               variable is used to return the number of bytes written to the
//               buffer.
//
// Return Value
//   Returns TRUE if the I/O operation was successful. In this case the
//   variable pointed to by BufLength is used to return the number of
//   bytes written to Buff.
//
//   Returns FALSE if the operation was unsuccessful. In this case additional
//   error information can be fetched by calling GetLastError. The 
//
// Remarks
//   If successful the buffer is filled with multiple wide-character strings
//   with the end of the buffer identified by an empty string.
//
//   Each binding made in the driver is represented by two strings (a tuple)
//   in the buffer:
//
//     Virtual Adapter Name - The name passed to NdisIMInitializeDeviceInstanceEx
//                            for the binding.
//     Lower Adapter Name   - The name passed to NdisOpenAdapter for the binding.
//
BOOL
PtEnumerateBindings(
   HANDLE PtHandle,
   PCHAR  Buf,
   DWORD *BufLength
   )
{
   BOOL	 bResult;
   //
   // Use DeviceIoControl to Call The Device
   //
   bResult = DeviceIoControl(
      PtHandle,
      IOCTL_PTUSERIO_ENUMERATE,
      NULL,
      0,
      Buf,
      *BufLength,
      BufLength,
      NULL
      );
   return( bResult );
}
/////////////////////////////////////////////////////////////////////////////
//// _tmain
//
// Purpose
// PTUserIo MFC console application MAIN entry point.
//
// Parameters
//
// Return Value
//
// Remarks
//
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
   int nRetCode = 0;

   //
   // Open A Handle On The PassThru Device
   //
   HANDLE PtHandle = PtOpenControlChannel();
   if( PtHandle == INVALID_HANDLE_VALUE )
   {
      cout << "PassThru Handle Open Failed" << endl;
      nRetCode = 1;
      return nRetCode;
   }
   cout << "PassThru Handle Open Successful" << endl;
   //
   // Enumerate The PassThru Bindings
   //
   WCHAR  BindingList[ 2048 ];
   DWORD  BufLength = sizeof( BindingList );
   if( PtEnumerateBindings( PtHandle, (PCHAR )BindingList, &BufLength ) )
   {
      PWCHAR   pWStr = BindingList;
      UINT     nWCHARsRead;
      INT      nBytesUnread = BufLength;
      if( !BufLength )
      {
         cout << "Binding List Is Empty" << endl;
      }
      else
      {
         cout << endl << "Driver Bindings:" << endl;
         while( pWStr && *pWStr && nBytesUnread > 0 )
         {
            //
            // Display Virtual Adapter Name
            // ----------------------------
            // This is the name passed to NdisIMInitializeDeviceInstanceEx.
            // We can call this our "virtual adapter name".
            //
            _tprintf( "   \042%ws\042\n", pWStr );
            //
            // Advance In Buffer
            //
            nWCHARsRead = wcslen( pWStr ) + 1;
            nBytesUnread -= nWCHARsRead * sizeof( WCHAR );
            if( nBytesUnread <= 0 )
            {
               pWStr = NULL;
            }
            else
            {
               pWStr += nWCHARsRead;
            }
         }
      }
   }
   else
   {
      cout << endl << "Binding Enumeration Failed" << endl;
   }
   CloseHandle( PtHandle );
   return nRetCode;
}