Posted in October 2009

Interops – COM <-> .NET

@Mysore

In my last post I mentioned ,

There are two ways that C# code can directly call unmanaged code:

  1. Directly call a function exported from DLL
  2. Call an interface method on a COM object

In this post lets concentrate on how to call an interface method on a COM object and how this can be implemented for managed environment.

.NET framework provides following facilities to perform COM Interop

  1. Creating COM objects
  2. Determining if a COM interface is implemented by an object
  3. Calling methods on COM interfaces
  4. Implementing objects and interfaces that can be called by COM clients.

Additionally, .NET framework also handles reference counting issues with COM Interop so there is no need to call or implement Addref and Release.

COM Interop provides access to existing COM components without requiring that the original components need to be modified and for this we can use a COM Interop utility (Tlbimp.exe).  Type library importer converts the type definitions found within a COM type library into equivalent definitions in a CLR assembly.

Type library Importer performs following conversions :

  1. COM coclasses are converted to C# classes with a parameter less constructor
  2. COM structs are converted to C# structs with public fields.

Microsoft Intermediate Language Disassembler provides a great way to check out the output of Tlbimp.exe to view the result of the conversion.

In addition to this, COM Interop allows programmers to access managed objects as easily as they access other COM objects Here COM Interop provides a Assembly Registration Tool  that exports the managed types into a type library and registers the managed component as a traditional COM component.

I referred MSDN for following steps and key points are as follows

Creating a COM Class Wrapper

Tlbimp converts a COM type library into .NET framework metadata- effectively creating a managed wrapper that can be called from any managed language.

  1. .NET framework metadata created with Tlbimp can be included in a C# build via /R compiler option.
  2. Using Visual Studio we need to add only COM type library and conversion is done automatically.

Important attributes in understanding COM mapping are

  1. ComImport
  2. GUID
  3. Interface Type
  4. PreserveSig

Declaring and Creating Comcoclass object

COM coclasses are represented as a classes with parameterless constructors  in C#. ComImport attribute is a must for them. Creating instance of this class using the new operator is the C# equivalent of calling CoCreateInstance.

Additional restrictions are as follows

  1. The class must not inherit from any other class
  2. The class must implement no interfaces
  3. GUID for the class

Declaring a COM Interface

  1. COM interfaces are represented in C# as interfaces with COMImport and GUID attributes.
  2. COM Interfaces declared in C# must include declarations for all members of their base interfaces with the exception of members of IUnknown and IDispatch. These are added by .NET framework automatically.
  3. COM interfaces which derive from IDispatch must be marked with the InterfaceType attribute.
  4. When calling a COM interface method from C# code, CLR runtime must marshal the parameters and return values to/ from the COM object.
  5. Common way to return success or failure is to return an HRESULT and have an out paramter marked as “retval” in MIDL for the real return value of method.

Apart from this following are the links, one should must see for        COM <-> .NET interoperability given on MSDN

Introduction to COM Interop

COM Interop Part 1: C# Client Tutorial

COM Interop Part 2: C# Server Tutorial

COM Callable Wrapper

Exposing .NET Framework Components to COM

Advanced COM Interoperability

Simplify App Deployment with ClickOnce and Registration-Free COM

I will be writing few more posts on Interops and some of the interesting aspects discovered using this. Meanwhile, do let me know your feedback and expectations from this blog.

Interops – Win32 <-> .NET

lamp

Technorati Tags: ,

As discussed in my first post , a common scenario where Interops are needed is accessing a legacy code written using Win32 APIs  in .NET applications for various reasons.

There are two ways that C# code can directly call unmanaged code:

  1. Directly call a function exported from DLL
  2. Call an interface method on a COM object

Luckily Platform Invoke (P/Invoke) service provided by .NET framework supports invoking unmanaged code residing in DLLs to be called in .NET environment.

C# provides a mechanism for providing declarative tags, called attributes which can be placed in certain entities in source code to specify additional information. Information contained in attributes can be ret rived through reflection, or one can use predefined attributes.

Use of DllImport can be made as follows in C# for calling MathFuncimportClass from unmanaged DLL.

[DllImport] public class MathFuncimportClass { … }

In addition to this , we can have few named parameters as well as unnamed(positional) parameters.

[DllImport("user32.dll", SetLastError=false,ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false,SetLastError=false)]
[DllImport("user32.dll")]

For a broader look one must have a reading of DllImportAttribute Members

An excellent info on EntryPoint, Charset, SetLastError and CallingConventions is given on Jason Clark’s post on MSDN Magazine. These are all optional properties in DllImportAttribute.

Data Marshaling

While transferring data between managed and unmanaged combination of code , CLR follows number of rules that one must know so as to tackle any tricky scenario.

While passing parameter to a Windows API function important points needs to be considered as follows

  1. Is the data in a form of integer or float ?
  2. Is the data signed integer or unsigned integer ?
  3. Bitwise presentation of integer data
  4. Floating point data and its precision.

Some special scenarios encountered while marshalling are

  1. Marshaling pointers
  2. Marshaling Opaque pointers
  3. Marshaling Text
  4. Marshaling a complex structure.

A detailed explanation for all these four points is here on MSDN Magazine. Figure 4 on this link also describes actual MSIL signature seen by CLR in various cases.

Copying and Pinning

While CLR performs Data Marshaling , it used two options copying and pinning .

1) While marshaling the data, the interop marshaler can copy or pin the data being marshaled. Copying the data will place a copy of data from one memory to another memory location.

Value types passed by value and by reference explains this scenario.

2) Pinning temporarily locks the data in its current memory location, and thus it is kept away from relocating by CLR’s garbage collector.

A clear scenario can be visualized here at Reference types passed by value and by reference

P/Invoke Interop Assistant

For quickly figuring out the P/Invoke signature for Win32 API function PInvoke Interop Assistant can be very useful. This tool assists developers with conversion from C++ to managed P/Invoke signatures and vice a versa.

This tool is available for download on codeplex website.

Follow

Get every new post delivered to your Inbox.