DeviceIoControl & USB using Managed C++ & C#

Communicating with the USB

I have implemented 3 of the many functions which are needed for communicating with a USB device.  These are GetDeviceDescriptor, BulkRead, & BulkWrite.  Here is the code:

Usb::UsbDeviceDescriptor* GetDeviceDescriptor()
{
  BOOLEAN success;
  ULONG nBytes;
  PUSB_DEVICE_DESCRIPTOR pDeviceDiscriptor = new USB_DEVICE_DESCRIPTOR();
  if( _hEzUsb == INVALID_HANDLE_VALUE )
  {
      ReportError( "Driver not open." );
  }
  else
  {
      success = DeviceIoControl( _hEzUsb,
        IOCTL_Ezusb_GET_DEVICE_DESCRIPTOR,
        NULL,
        0,
        pDeviceDiscriptor,
        sizeof(USB_DEVICE_DESCRIPTOR),
        &nBytes,
        NULL );
      if( success == FALSE )
      {
        CheckWin32Error();
      }
  }
  UsbDeviceDescriptor* DeviceDiscriptor = new UsbDeviceDescriptor();
  DeviceDiscriptor = (UsbDeviceDescriptor*)Marshal::PtrToStructure(
      pDeviceDiscriptor, DeviceDiscriptor->GetType() );
  delete pDeviceDiscriptor;
  return( DeviceDiscriptor );
}
System::Byte BulkRead( int pipe ) []
{
  if( _hEzUsb == INVALID_HANDLE_VALUE )
  {
      ReportError( "Driver not open." );
      return( 0 );
  }
  char lpOutBuffer[MaxBlkSize];
  BULK_TRANSFER_CONTROL btc;
  btc.pipeNum = pipe;
  BOOL success;
  int nBytes;
  success = DeviceIoControl( _hEzUsb,
      IOCTL_EZUSB_BULK_READ,
      &btc,
      sizeof (BULK_TRANSFER_CONTROL),
      lpOutBuffer,
      MaxBlkSize,
      (unsigned long *)&nBytes,
      NULL);
  if( success == FALSE )
  {
      CheckWin32Error();
      return( 0 );
  }
  System::Byte buffer __gc[] = new System::Byte[nBytes];
  IntPtr ptr( lpOutBuffer );
  Marshal::Copy( ptr, buffer, 0, nBytes );
  return( buffer );
}
int BulkWrite( System::Byte buffer __gc[], int pipe )
{
  if( _hEzUsb == INVALID_HANDLE_VALUE )
  {
      ReportError( "Driver not open." );
      return( 0 );
  }
  char* lpOutBuffer = new char[buffer->Length];
  Marshal::Copy( buffer, 0, lpOutBuffer, buffer->Length );
  BULK_TRANSFER_CONTROL btc;
  BOOLEAN success;
  int nBytes;
  btc.pipeNum = pipe;
  success = DeviceIoControl( _hEzUsb,
      IOCTL_EZUSB_BULK_WRITE,
      &btc,
      sizeof (BULK_TRANSFER_CONTROL),
      lpOutBuffer,
      buffer->Length,
      (unsigned long *)&nBytes,
      NULL);
  if( !success )
  {
      CheckWin32Error();
  }
  delete lpOutBuffer;
  return( nBytes );
}

In the GetDeviceDescriptor function, an unmanaged version of the USB_DEVICE_DESCRIPTOR data structure is create.  A pointer to the data structure is used in the DeviceIoControl, which fills the data structure with data.  When using DeviceIoControl, you need to use macros to define what function you want to call in the device driver.  If you were calling DeviceIoControl, directly from C#, you would need a wrapper function for the macros written in C++, or duplicate their functionality it C#.  These techniques are documented in John Mueller's book.  To pass the data structure back to the managed world, I create a managed structure, then use Marshal::PtrToStructure to copy the data over.

When calling DeviceIoControl to perform a bulk read, you need to pass it a pointer to a buffer where it can place the data.  I use a char array.  I then copy the data to a managed Byte array, using Marshal::Copy.

System::Byte buffer __gc[] = new System::Byte[nBytes];
IntPtr ptr( lpOutBuffer );
Marshal::Copy( ptr, buffer, 0, nBytes );

In the call to the bulk BulkWrite function, a System::Byte buffer __gc[], is passed in.  The data in this array is copied to an unmanaged buffer using Marshal::Copy.

char* lpOutBuffer = new char[buffer->Length];
Marshal::Copy( buffer, 0, lpOutBuffer, buffer->Length );

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Never trust a programmer in a suit.” - Anonymous