Programming with COM
Abstract
This article commences by taking a brief backward glimpse at COM then compares it with the way that components interact in .NET, and finally it takes a look at the tool provided by Microsoft to let these two technologies coordinate together. Essentially, COM is the antecedent technology to .NET. COM defines a component prototypical where components can be written in dissimilar programming languages. In addition to, they can be cast-off inside a process, across a process or across the network (DCOM). But the COM technology became more and more complicated in terms of implementation and turn out not to be extensible enough. However, the .NET justifies the similar goals as COM had, but introduces new conceptions to make job easier.
Learn Digital Forensics
Prerequisites
In order to, implement COM components interoperability with .NET framework, following stuffs are required;
- Visual Studio 6 with VC++ (optional)
- Visual Studio 2010 with VC++.Net features
COM
Before delving into .NET-COM interoperability, it is important to be aware about legacy COM (Component Object Model) itself. COM was Microsoft's first attempt at creating a language- independent standard for programs, the idea was that interfaces between components would be defined or invoked according to a binary standard. This would have inferred that you could invoke a VC++ component from a VB application and vice versa. A COM component implements one or more interfaces which defines the various methods that an application may invoke during marshaling.
COM in Practice
To see how a .NET application can use a Legacy COM component, you first have to create a COM component using VC++ because creating COM component is not possible with C# or VB.net;
- To create a COM component with ATL and C++, create a new ATL project. Set the name to comServerTest and with application setting, select Dynamic Linking Library, and finally click Finish.
- The first thing, you have to define the class as mathLib then place the methods Addition() and Square() definition in the ImathLib interface. Once this is done, look at the comServerTest.idl file which depicted all the methods definition as;
[plain]
// comServerTest.idl : IDL source for comServerTest
//// This file will be processed by the MIDL tool to
// produce the type library (comServerTest.tlb) and marshalling code.import "oaidl.idl";
import "ocidl.idl";[
object,
uuid(DFC4EDDD-1115-4B36-90A3-15F547018FE8),
dual,
nonextensible,
pointer_default(unique)
]
interface ImathLib : IDispatch{
[id(1)] HRESULT Addition([in] LONG val1, [in] LONG val2, [out,retval] LONG* val);
[id(2)] HRESULT Square([in] LONG val1, [out,retval] LONG* val);
};
[
uuid(F2DBF0C9-8136-4F38-BED2-333A365ED980),
version(1.0),
]
library comServerTestLib
{
importlib("stdole2.tlb");
[
uuid(C670DD23-8B50-445D-9E53-17D6248EF1DA)
]
coclass mathLib
{
[default] interface ImathLib;
};
};
[/plain] -
Now implement the business logic of those methods into the mathLib.cpp class as:
[plain]
STDMETHODIMP CmathLib::Addition(LONG val1, LONG val2, LONG* val)
{
*val= val1+ val2;
return S_OK;
}STDMETHODIMP CmathLib::Square(LONG val1, LONG* val)
{
*val= val1 * val1;
return S_OK;
}
[/plain] - Finally build the component. The build process also configures the component in the registry.
If you are developing your client .NET application on the same machine, you don't need to manually register it. However, if you are working entirely on a new machine, you need to register this component with regsvr32.exe utility as:
.NET Interoperability
The mechanism where data passed from COM components to .NET and vice-versa is called marshaling. The foremost concern during this process is the conversion of passed data types because, both technologies have different data type's definition schemes. But .NET and COM have a common representation for some data types such as int, long, short and byte where conversion isn't required during marshaling, is called Blittable data types.
In nonblitabble data types the conversion is required during data pass because these data types have a higher overhead. The following table lists some nonblittable to related blittable types as:
You can use the previously created COM component, comServerTest.dll from within the .NET application. We are going to implement the COM component method within a Windows Form project. First, we add the reference of the COM component then instantiate the MathLib class to invoke the methods.
- Create a C# Window Form project name as comServerTestClient.
-
Design the form with appropriate control as following;
-
Add the COM component reference as the following;
- Place the following code for a "both button" click event as:
[c language="sharp"]
using System;
using System.Windows.Forms;
using comServerTestLib;namespace comServerTestClient
{
public partial class Form1 : Form
{
mathLib obj = new mathLib();
public Form1()
{
InitializeComponent();}
private void btnAdd_Click(object sender, EventArgs e)
{
int x = Int32.Parse(txtX.Text);
int y = Int32.Parse(txtY.Text);txtResult.Text = obj.Addition(x, y).ToString();
}private void btnSquare_Click(object sender, EventArgs e)
{
int x = Int32.Parse(txtX.Text);
txtResult.Text = obj.Square(x).ToString();
}
}
}
[/c] - Finally compile, and run the application.
Runtime Callable Wrapper
In the preceding example, we have done lots of activities. Every time you create a default interop assembly by importing COM dll into Visual Studio. So, it might be better to do a wrapping once, and then let your application import the resulting .NET assembly instead of a COM component. The RCW would spare the hassle of repeatedly dealing with COM characteristics because it hides the IUknown and IDsipatch interface and deals with the reference count of the COM object.
RCW can be created by using the command line utility tlbimp.exe; here, we are creating a new.dll from the COM component which contains a .NET assembly with the wrapper class as following:
COM Callable Wrapper
So far, we have seen how to access a COM component from a .NET application with RCW. Equally interesting is to find a solution for accessing .NET component from a COM client by using COM Callable Wrapper (CCW)
In the following example, we create a simple C# class library project. Then add some interface to define methods which are invoked from a COM client.
[c language="sharp"]
using System;
namespace NETcomponent
{
[ComVisible(true)]
public interface ITest
{
string Hello(string msg);
}
public class Test : ITest
{
public string Hello(string msg)
{
return "Hello " + msg;
}
}
}
Now compile this class library project. Before the, .NET components can be used as a COM object. It is necessary to configure it in the registry you can use the regasm.exe utility to configure the components inside the registry as:
Now open the Visual Studio command prompt to create a COM wrapper class using tlbexp.exe utility as the following:
As you notice in the directory of the solution, NewLib.tlb file created after executing tlbexp.exe command. You can view the type library with OLE/COM object viewer utility, which resides in Visual Studio Tools as:
In the generated code, you can see that the interface ITest are defined as COM interface and all the methods defined in the C# code are listed here in the type library.
Active-X
ActiveX controls are COM objects with a user interface. They are used by many different containers such as Word, Excel, IE and Windows Forms. Similarly, to RCW, we can also create a wrapper for ActiveX controls using aximp.exe command line utility.
Conclusion
Learn Digital Forensics
In this article, you have learned how the .NET application interoperates with COM and vice-versa using RCW and CCW. You also come across with couple of underlying utilities such as tlbimp to import type library, tlbexp to export type library from .NET assemblies, regasm and regsvr32 to register a .NET component in register. You also incorporate the ActiveX control into the .NET user interface.