Call Unmanaged DLL Functions

The .NET Framework provides functions for the sake of compatibility with unmanaged (COM or C) codes. In this section, I’ll introduce the technique of Platform Invoke (PInvoke).

Platform Invoke is the process of calling unmanaged functions which lives in DLLs from managed code. You need to take four steps:

  1. Identify functions in DLLs.
  2. Create a class to hold DLL functions.
  3. Create prototypes in managed code.
  4. Call the DLL functions.

To identify functions in DLLs, you should know at least the name of the DLL and of the function. Without it, you are doomed, there won’t be any platform invoke.

I think you can handle the brutal work of creating a class for holding the DLL functions, let’s concentrate on those prototypes. To create those prototypes, you’ll need to define a static extern method, and mark it with the DllImportAttribute. A quick example:

class Win32
{
[DllImportAttribute(“user32.dll”)]
public static extern IntPtr MessageBox(int hWnd, string Text, string Caption, uint Type);
}

Calling this DLL function is easy, call it as if it would be any other static method.

You can also create wrapper classes for DLL functions, however, it’s not compulsory. But look how much cooler is the following code:

class WrapWin32
{
  public enum BoxTyes {Ok=0, OkCancel, AbortRetryIgnore, YesNoCancel, etc};
  public static void ShowMessageBox(string Caption, string Text)
    {
      Win32.MessageBox(0, Text, Caption, 0);
    }
public static void ShowMessageBox(string Caption, string Text, BoxTypes type)
  {
    Win32.MessageBox(0, Text, Caption, (int)type);
   }
}

Weigh more cooler, I say! DllImportAttribute defines the following named parameters, which you’ll constantly use:

  • BestFitMapping(bool):                 enables or disables best-fit mapping behavior when converting Unicode characters to ANSI characters.
  • CallingConvention(CallingConvention): defines the calling convention.
  • Charset(Charset): values: ANSI, Auto, None, Unicode.
  • EntryPoint(string): the name of the function you wish to call. It is useful when you’d like your method name to be different from the function name. In the above example, you’d set it to MessageBox, and the method then could be called anything.
  • PreserveSig(bool): indicates whether or not to convert HRESULTS into exceptions.
  • ThrowOnUnmappableChar(bool): enables or disables throwing an exception when an Unicode character cannot be mapped to an ANSI.

When you need to work with functions that require callback functions, you can pass a delegate to the parameter list, define a managed method, and process the callback there. An example:

public delegate bool CallBack(int hwnd, int lParam);
public class Win32
{
  [DllImport(“User32.dll”)]
  public static extern int EnumWindows(CallBack x, int y);
  public static bool CallBackMethod(int hwnd, int lParam)
    {
      Console.WriteLine(“Window handle is: {0}”, hwnd);
      return true;
    }
public static void Main()
  {
    CallBack myCallBack = new CallBack(CallBackMethod);
    EnumWindows(myCallBack, 0);
  }
}

So long for the DllImport attribute. A bit different objective is to map an exception to an HRESULT. To do so, derive a new class from Exception, and set its HRESULT value in the constructor, example:

public class MyException: Exception
{
  public MyException()
    {
      this.HResult =  01234567;
    }
}

OK, this wasn’t too difficult. Now last but not least, I’ll introduce the Marshal class and the MarshalAs attribute. MarshalAs attribute indicates how to marshal data between managed and unmanaged applications. It can be applied to parameters, fields and return values. You aren’t required to explicitly use this attribute, because every data type has a default marshaling behavior. The Type Library Explorer will take into account your marshaling preferences when it’ll export your type. A little note: MarshalAs doesn’t support generic collections.

The Marshal class provides a set of static methods to help you work with unmanaged code. You’ll typically use this class when your are trying to form a bridge between managed and unmanaged code. Because the Marshal class has so many methods, I wouldn’t like to list them here. You’ll find it among the links at the end of this post.

I think we’ve covered a great deal of platform invoke and marshaling, at least after I viewed the appropriate questions on MeasureUp. The information provided here should be enough for the exam.

Further Readings

Creating Prototypes in Managed Code
Implement Callback Functions
MarshalAs Attribute
Marshal Members

Advertisements

Tags: , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: