Send a suggestion!

We're building a brand new version of the site, and we'd love to hear your ideas

Members

Technology Zones

IBM Learning Center

Articles

Hosted By

MaximumASP

Info

Rated
Read 83,054 times

Contents

Related Categories

DeviceIoControl & USB using Managed C++ & C# - Marshalling

Bill Burris

Marshalling

And here is one way you can create a managed data structure which you can easily marshal to the unmanaged world.

[StructLayout(LayoutKind::Explicit, Size=18, CharSet=CharSet::Auto)]
public __gc class UsbDeviceDescriptor
{
  public:
    [FieldOffset(0)] System::Byte bLength;
    [FieldOffset(1)] System::Byte bDescriptorType;
    [FieldOffset(2)] System::UInt16 bcdUSB;
    [FieldOffset(4)] System::Byte bDeviceClass;
    [FieldOffset(5)] System::Byte bDeviceSubClass;
    [FieldOffset(6)] System::Byte bDeviceProtocol;
    [FieldOffset(7)] System::Byte bMaxPacketSize0;
    [FieldOffset(8)] System::UInt16 idVendor;
    [FieldOffset(10)] System::UInt16 idProduct;
    [FieldOffset(12)] System::UInt16 bcdDevice;
    [FieldOffset(14)] System::Byte iManufacturer;
    [FieldOffset(15)] System::Byte iProduct;
    [FieldOffset(16)] System::Byte iSerialNumber;
    [FieldOffset(17)] System::Byte bNumConfigurations;
};

Use LayoutKind::Explicit in the attribute and FieldOffset in front of each field to make sure the memory layout is the same as the unmanaged stuct that this one will be marshaled to.  Using CharSet=CharSet::Auto will let the compiler choose between Ansi or Unicode. The CharSet probably doesn't matter on this structure since there are no strings involved.

Here is how you define a managed class in C++:

public __gc class Usb

Now I will show you some bits and pieces of the code which is contained in the Usb class.  If you want to see how it all fits together, take a look at the code in the download.

I wanted to report Win32 errors to my GUI layer, so I added an event.  In hindsight it would have been better to use exceptions for this.  Being able to trigger events in C++ is useful, so I will discuss this here instead of converting the code to use exceptions.  Here is the C++ syntax for your delegate & event, which goes in the public section of your class.

__delegate void ErrorMessage( Object* sender, ErrorEventArgs* e );
__event ErrorMessage* OnErrorMessage;

Here is the code to fire the event:

void ReportError( String* msg )
{
  if( OnErrorMessage )
  {
    OnErrorMessage( this, new ErrorEventArgs( msg ) );
  }
}
void CheckWin32Error()
{
  int errCode = GetLastError();
  if( errCode != 0 )
  {
    char msg[256];
    FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, errCode, 0, msg, 256, NULL );
    ReportError( msg );
  }
}

ReportError and CheckWin32Error, are declared as private. Note that the GetLastError and FormatMessage functions from the Win32 API is being used here.  The ability to mix managed and unmanaged code like this is one of the reasons for using managed C++ instead of C# for this code.

If you were writing this code in C# you would want to use:

int errCode = Marshal.GetLastWin32Error();

to obtain the Win32 last error code. We need to obtain a HANDLE to the device driver using CreateFile. The HANDLE is defined as private:

HANDLE _hEzUsb;

And the public function Open, which is just a wrapper around the API function CreateFile, with some error checking.

bool Open( String* driverName )
{
  char* lpFileName = new char[driverName->Length + 10];
  sprintf( lpFileName, "\\\\.\\%s", driverName );
  _hEzUsb = CreateFile( lpFileName,
      GENERIC_WRITE,
      FILE_SHARE_WRITE,
      NULL,
      OPEN_EXISTING,
      0,
      NULL);
  if( _hEzUsb == INVALID_HANDLE_VALUE )
  {
      CheckWin32Error();
  }
  delete lpFileName;
  return( _hEzUsb != INVALID_HANDLE_VALUE );
}

Make sure the HANDLE gets closed, when you are finished.  I have defined a Close function which can be called from the C# code:

void Close() { CloseHandle( _hEzUsb ); }

If you forget to call Close, before calling Open again, strange things will happen.  I spent a lot of time trying to figure out why I the code on the EZ-USB FX board wouldn't run a second time.  After adding calls to Close in my test routines, the problem disappeared.

Comments

  • Re: [4392] DeviceIoControl & USB using Managed C++ & C#

    Posted by Yosef on 16 Aug 2006

     

    I want to build an application to Set/Get USB requests using the OS drivers, Can I do that ? How can I send request to USB for example : Set_Feature ?

     
    ...

  • IJW

    Posted by edinl on 15 Sep 2005

    Hei!

    You can not use IJW if you are programming with C#. You can use P/Invoke where you import unmanaged dll or to make a managed wrapper class in c++ and then write a class in C# to use unmanaged ...

  • Buggy C++ code

    Posted by dmw on 23 Nov 2004

    Be advised that there are bugs in this C++.

    Firstly, there is a line of code that reads

    (long *) &nBytes,

    where nBytes is declared as an int. This will lead to a stack corruption whenever siz...

  • Marshalling an argument of "char*" using IJW metho

    Posted by halise on 04 Nov 2004

    hello,

    i am trying to wrap an unmanaged C++ code to managed one so that i can use it within c#, and i am using IJW - "It Just Works" - method for that. In the code, there is a function which takes...