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