- Interoperation with Native Libraries.
- Interoperation with COM components.
- Interoperation with ActiveX.
Interop with Native Libraries
This is the most famous form of .NET interop with unmanaged code. We usually
call this technique, Platform Invocation, or simplyPInvoke. Platform Invocation
or PInvoke refers to the technique used to call functions of native unmanaged
libraries such as the Windows API.
To PInvoke a function, you must declare it in your .NET code. That declaration
is called the Managed Signature. To complete the managed signature, you need to
know the following information about the function:
- The library file which the function resides in.
- Function name.
- Return type of the function.
- Input parameters.
- Other relevant information such as encoding.
Here comes a question, how could we handle
types in unmanaged code that aren't available in .NET (e.g. BOOL, LPCTSTR,
etc.)?
The solution is in Marshaling. Marshaling is the process of converting unmanaged
types into managed and vice versa (see figure 1.) That conversion can be done in
many ways based on the type to be converted. For example, BOOL can simply be
converted to System.Boolean, and LPCTSTR can be converted to System.String,
System.Text.StringBuilder, or even System.Char[]. Compound types (like
structures and unions) are usually don't have counterparts in .NET code and thus
you need to create them manually. Read our book about marshaling here.
Figure 1 - The Marshaling Process
To understand P/Invoke very well, we'll take an example. The following code
switches between mouse button functions, making the right button acts as the
primary key, while making the left button acts as the secondary key.
In this code, we'll use the SwapMouseButtons() function of the Win32 API which
resides in user32.dll library and has the following declaration:
BOOL SwapMouseButton(
BOOL fSwap
);
Of course, the first thing is to create the managed signature (the PInvoke
method) of the function in .NET:
// C#
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool SwapMouseButton(bool fSwap);
' VB.NET
Declare Auto Function SwapMouseButton Lib "user32.dll" _
(ByVal fSwap As Boolean) As Boolean
Then we can call it:
// C#
public void MakeRightButtonPrimary()
{
SwapMouseButton(true);
}
public void MakeLeftButtonPrimary()
{
SwapMouseButton(false);
}
' VB.NET
Public Sub MakeRightButtonPrimary()
SwapMouseButton(True)
End Sub
Public Sub MakeLeftButtonPrimary()
SwapMouseButton(False)
End Sub
Interop with COM Components
The other form of unmanaged interoperation is the COM Interop. COM Interop is very large and much harder than P/Invoke and it has many ways to implement. For the sake of our
discussion (this is just a sneak look at the technique,) we'll take a very simple example.
COM Interop includes all COM-related technologies such as OLE, COM+, ActiveX, etc.
Of course, you can't talk directly to unmanaged code. As you've seen in Platform Invocation, you have to declare your functions and types in your .NET code. How can you do this?
Actually, Visual Studio helps you almost with everything so that you simply to include a COM-component in your .NET application, you go to the COM tab of the Add Reference dialog
(figure 2) and select the COM component that you wish to add to your project, and you're ready to use it!
Figure 2 - Adding Reference to SpeechLib Library
When you add a COM-component to your .NET application, Visual Studio automatically declares all functions and types in that library for you. How? It creates a Proxy library
(i.e. assembly) that contains the managed signatures of the unmanaged types and functions of the COM component and adds it to your .NET application.
The proxy acts as an intermediary layer between your .NET assembly and the COM-component. Therefore, your code actually calls the managed signatures in the proxy library that
forwards your calls to the COM-component and returns back the results.
Keep in mind that proxy libraries also called Primary Interop Assemblies (PIAs) and Runtime Callable Wrappers (RCWs.)
Best mentioning that Visual Studio 2010 (or technically, .NET 4.0) has lots of improved features for interop. For example, now you don't have to ship a proxy/PIA/RCW assembly along
with your executable since the information in this assembly can now be embedded into your executable; this is what called, Interop Type Embedding.
Of course, you can create your managed signatures manually, however, it's not recommended especially if you don't have enough knowledge of the underlying technology and the
marshaling of functions and types (you know what's being said about COM!)
As an example, we'll create a simple application that reads user inputs and speaks it. Follow these steps:
- Create a new Console application.
- Add a reference to the Microsoft Speech Object Library (see figure 2.)
- Write the following code and run your application:
// C#
using SpeechLib;
static void Main()
{
Console.WriteLine("Enter the text to read:");
string txt = Console.ReadLine();
Speak(txt);
}
static void Speak(string text)
{
SpVoice voice = new SpVoiceClass();
voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault);
}
' VB.NET
Imports SpeechLib
Sub Main()
Console.WriteLine("Enter the text to read:")
Dim txt As String = Console.ReadLine()
Speak(txt)
End Sub
Sub Speak(ByVal text As String)
Dim voice As New SpVoiceClass()
voice.Speak(text, SpeechVoiceSpeakFlags.SVSFDefault)
End Sub
If you are using Visual Studio 2010 and .NET 4.0 and the application failed to run because of Interop problems, try disabling Interop Type Embedding feature from the properties on the
reference SpeechLib.dll.
Interop with ActiveX Controls
ActiveX is no more than a COM component that has an interface. Therefore, nearly all what we have said about COM components in the last section can be applied here except the
way we add ActiveX components to our .NET applications.
To add an ActiveX control to your .NET application, you can right-click the Toolbox, select Choose Toolbox Items, switch to the COM Components tab and select the controls that you
wish to use in your application (see figure 3.)
Figure 3 - Adding WMP Control to the Toolbox
Another way is to use the aximp.exe tool provided by the .NET Framework (located in Program Files\Microsoft SDKs\Windows\v7.0A\bin) to create the proxy assembly for the ActiveX
component:
aximp.exe "C:\Windows\System32\wmp.dll"
Not surprisingly, you can create the proxy using the way for COM components discussed in the previous section, however, you won't see any control that can be added to your form!
That way creates control class wrappers for unmanaged ActiveX controls in that component.
Summary
So, unmanaged code interoperation comes in two forms: 1) PInvoke: interop with native libraries including the Windows API 2) COM-interop which includes all COM-related technologies
like COM+, OLE, and ActiveX.To PInvoke a method, you must declare it in your .NET code. The declaration must include 1) the library which the function resides in 2) the return type of the function 3) function
arguments.COM-interop also need function and type declaration and that's usually done for you by the Visual Studio which creates a proxy (also called RCW and PIA) assembly that contains
managed definitions of the unmanaged functions and types and adds it to your project.