Home
    Shop
    Advertise
    Write For Us
    Affiliate
    Newsletter
    Contact

Interoperating with Unmanaged Code - PInvoke

Introduction

At the time .NET Framework is firstly introduced by Microsoft, the concept of managed code and unmanaged code as two different programming models is introduced as well.

 

Microsoft defines that managed code is the code generated by the .NET Framework and could be executed by the common language runtime (CLR). At the other hand the unmanaged code is any other code that doesn't match the pervious definition. As a result, all the code created and generated before the .NET Framework is released considered unmanaged code. This unmanaged code contains WIN32 APIs, valuable external libraries, COM components, and COM+ services, and all of these are so useful and important.

The dilemma now is: the .NET Framework which is the current development environment only accepts managed code. We have already made valuable libraries and components but all are unmanaged code. We need to use this valuable unmanaged code while we are working under the .NET Framework environment. What is the solution of this dilemma ???

To solve this problem and for backward compatibility Microsoft fires another concept and calls it "Interoperating with unmanaged code". Which is how to call or use unmanaged code form within managed code and vice versa. Then it divided this process into two categories which are:

  1. - How to call WIN APIs and DLLs (unmanaged code) form within the .NET Framework (managed code) using the Platform Invoke (PInvoke) technique.
  2. - How to use COM components (unmanaged code) from within the .NET Framework (managed code) using the COM Interop technique.

The first item in the pervious list is the subject of this tutorial. We will try to highlight the main differences between unmanaged and managed code. Then we will create an example showing how to call unmanaged DLL function from within the .NET Framework managed code using the platform invoke technique.

To download the example created in this tutorial just click here.

Dissimilarities Between managed and unmanaged Programming Models

Managed and unmanaged programming models are dissimilar in many aspects. The following paragraphs highlight some of those aspects with a brief description about each of them.

Type definition or information is mandatory for all types in the managed programming model while it is optional for only public types in the unmanaged programming model. Managed model use metadata for type definition while unmanaged model use type libraries. Interoperating services tools convert type libraries to metadata in assemblies and metadata to type libraries to overcome the interoperation process.

Type safety is highly achieved in managed code rather than unmanaged code. The unmanaged programming model is not type safe while the managed one is optionally type safe. In unmanaged model compilers provide no type checking on pointer types which may lead to potentially harmful activity. You can still use pointers in managed code but this will put restrictions on that code due to its unsafe behavior. It will be marked as untrusted code. Interoperation services prevent untrusted managed code form accessing unmanaged code.

Type compatibility is not achieved between managed and unmanaged code. Types differ between the two models and also among different programming languages.

Coding models are differ. The unmanaged objects always communicate via interfaces, while managed objects can pass data directly without implementing interfaces. Interoperating services especially COM interop generates interfaces to the managed objects to expose their functionalities to COM objects.

Identity used in unmanaged model is GUID, while managed model uses strong names. Unmanaged model uses the GUID to identify a specific type. Managed model uses strong name consists of a unique assembly name and a type name for the same purpose. Interoperating services generate GUIDs and strong names as required.

Error handling mechanism in managed code is exceptions. COM methods return an HRESULT as a result to indicate wither the call succeeded or failed. COM interop maps managed exceptions to failure HRESULT.

Consuming Unmanaged DLL Functions Using PInvoke

Consuming unmanaged DLL function means that we need to call a function located in an unmanaged DLL library from within the .NET framework. Platform invoke or PInvoke is the technique used to make this happens. When platform invoke calls an unmanaged function it firstly locates the DLL containing the function and then loads it into memory. It searches for the function in memory and locates its memory address. After that it pushes the function arguments into the stake and marshaling data as required. Finally the control is transferred to the unmanaged function. Platform invoke throws exceptions generated by the unmanaged function to the managed caller.

To call a specific function within a specific DLL you have to follow the following steps:

  1. - First you have to locate this DLL, know its name, and know the function name you need to call.
  2. - After that you have to create a class to hold that DLL function. You can use an existing class, create a new class for each DLL function, or collect related DLL functions in one class.
  3. - After creating the class (or module in Visual Basic) you have to create a new managed prototype for that unmanaged function declared inside the created class.
  4. - Finally you are ready to call that DLL function from within your application.

Let us create a real example to examine the above four steps in more details.

PInvoke Example

This example aims to call an unmanaged DLL function exists in the WIN32 APIs library from within a new created Visual Basic application. We will use the Visual Studio 2005 as the development environment for our example. So, open up your Visual Studio 2005 and create a new Visual Basic project. Add a new class for your project and name it "Unmanged". At the top of the class file add the following imports statement to import the interoperating services capabilities to our class.

	Imports System.Runtime.InteropServices

Now to step1.

Function and DLL identification

There are three commonly used WIN32 APIs "GDI32.dll" for graphics device interface (GDI), "Kernel32.dll" for low level operating system functions, and "User32.dll" for windows management functions for message handling, menus, timers, and communications. Of course you are free to make use of any other APIs. You will find them in the "System32" directory under your windows directory.

For our example we will select the "User32.dll", so the DLL name is now identified. What about the function?, we have to know functions inside that DLL to select from. Many tools both command line and visual are existed to do this task, among them we prefer the visual tool shipped with the Visual Studio 2005 and called Microsoft dependancy walker "Depends.exe". You can run this tool from "\Common7\Tools\Bin" directory under your Visual Studio directory. The following figure shows this tool opening the "User32.dll" library in its left pane, while the right pane listing all functions located in this library.


Figure 1 - Depends.exe" tool lists the functions located at the "User32.dll" library

As the above figure implies we choose the "MessageBox" function. WIN32 APIs may contain two versions for each function that handles characters and strings. One for the ANSI version (MessageBoxA), and the other for the Unicode version (MessageBoxW). By choosing the "MessageBox" as our function the identification process is completed.

Create a class to hold the DLL function

We already made this step when we add a new class to our created project and called it "Unmanged". This process is called wrapping. Wrapping the unmanaged DLL functions in a managed class allows the platform invoke to handle the underlying exported functions automatically. You have to define a static method for each DLL function you want to call.

Create prototypes in managed code

In this step we will define the function prototype under our class using managed model rather than the unmanaged definition exists at the DLL library. To get the unmanaged prototype of the "MessageBox" function, search the MSDN library under the "win32 and COM development" section, or enter the function name in he search box then filter the result to the "Windows platform" section only. The unmanaged prototype of the "MessageBox" function is as followes.

int MessageBox(HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);

To set the new managed declaration in our new visual basic project we will use the "Declare" statement to define the function and the "Lib" keyword to identify its library name as in the following line of code.

    Declare Auto Function MessageBox Lib "User32.dll"

The "Auto" keyword is set to let the target platform determines the suitable character width (ANSI or Unicode).

Now to complete the declaration process you need to convert the unmanaged types of the function parameters to their managed counterparts. MSDN library provides a table that resolve each WIN32 API type into its managed type. You can get this table from the following link http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconplatforminvokedatatypes.asp

Now convert each unmanaged type into its managed counterpart using the above table.

Public Class Unmanged
 
    Declare Auto Function MessageBox Lib "User32.dll" _
     (ByVal Hwnd As Integer, ByVal Text As String, _
     ByVal Caption As String, ByVal Type As Integer) _
        As Integer
 
End Class

That's it. The DLL function now is ready to be called from within the current project.

Calling the DLL function

To examine the DLL function we will call it from within the "Form1" class as following.

Public Class Form1
    Private Sub Form1_Load(ByVal sender As System.Object, _
        ByVal e As System.EventArgs) Handles MyBase.Load
 
        Unmanged.MessageBox(0, "Hello every one", _
         "PInvoke Example", 0)
 
    End Sub
End Class

Now run the program and get the results.


Figure 2 - The unmanaged "MessageBox" function called from within a managed code

As figure2 implies, the function is called and a message box with the caption and text input parameters is displayed.

To download the example created in this tutorial just click here.


For further information

Refer to the online copy of Microsoft Developers Network at http://msdn.microsoft.com or use your own local copy of MSDN.


Tutorial toolbar:  Tell A Friend  |  Add to favorites  |  Feedback  |   


comments powered by Disqus