http://www.developer.com/net/net/article.php/1730971/COM-Interoperability-and-NET.htm
There are fundamental architecture differences, possibly the understatement of the year, that render COM and .NET objects incompatible. Key differences include, but are not limited to, the following: Companies have resources, in the form of time and money, invested in building and/or buying COM components. In many cases, it is not justifiable to simply throw away these investments. You then have no choice but to wait to until the application has outlived its lifetime and can be replaced in order to benefit from .NET. Thus, a need exists to allow organizations to leverage current COM investments and also benefit from the advantages of .NET applications by easing them into their applications. This is the role COM Interop plays and the benefit it provides. It stands to reason that the work required to get the .NET and COM components to interoperate is going to be on the .NET-side because it is the newer technology. If you had to change all of your COM components to operate with .NET, it would make sense to just rewrite them in .NET and you wouldn't be reading this article on COM Interop. To allow communication between .NET and COM objects, the CLR provides wrappers to make each object think it is talking to an object from its own architecture. A .NET client calling a COM object results in the CLR using a runtime callable wrapper (RCW) to make the .NET client think it is talking to a .NET object. A COM client calling a .NET object results in the CLR using a COM callable wrapper (CCW) that makes the COM client think it is talking to another COM object. The wrappers facilitate built-in rules for marshaling data between .NET and COM, such as conversion of string to BSTR and vice versa. Typically, the generated wrappers provide adequate marshaling of types between .NET and COM. There are ways to adjust way these wrappers are generated, but that is beyond this initial look at COM Interop. It is important to understand strong naming because it plays a role in COM Interop. A strong name is one that is globally unique to the particular assembly. This helps to avoid common DLL conflicts, a.k.a. DLL hell, such as naming conflicts and versioning issues. They also provide a security check that the contents of the assembly have not changed since it was last compiled. If the .NET object calling a COM component is strong named, the COM component needs to be strong named as well; otherwise, the advantages of strong naming are lost. If it is a COM client calling a .NET object, the .NET object needs to be strong named so that the CLR can resolve the name to the appropriate assembly. If you are doing new development using .NET and you need to utilize existing COM investments, this is the section for you. In my opinion, this is the most likely case in which you will need to use COM Interop. The process is different if you are planning to use strong naming for your assemblies or not. Both scenarios are outlined below, followed by an example scenario with some supporting code. Because the .NET client is strong named, we must make sure that all of the components utilized are also strong named; otherwise, we lose the benefits of strong naming. For the sake of this example, we have a COM object that contains a function that will pad the left side of a string with a specified string until it reaches a desired length. We'll pretend this is the greatest version of a pad function ever written and that we are compelled to reuse it in its current form. This function has been compiled in a Visual Basic 6.0 class called clsCommon that is part of an ActiveX dll called SampleUtil.dll when compiled. The code for the COM component is located below, and the client .NET code is located in the trailing section. I did not use a strong name for this example, so the only thing required to reference and use the COM component was to simply go through the Visual Studio .NET menus and add a reference to the SampleUtil COM component. The sample .NET client is below. There are several reasons why you may want to use a .NET object in a COM application. A likely scenario is that you are making changes to an existing COM component and you want to leverage some new functionality that was built using .NET. If you intend to call .NET objects from COM, there are a few items to remember due to the different capabilities of .NET and COM. A list of some of the items is outlined below. The process for using a .NET object in a COM client is described below. Let's use the scenario where we have an existing COM application. We can't simply rewrite the whole thing at once, so we are going to transition into development with .NET. We found a great and efficient benefit to do our left pad function with .NET that we had previously done in COM. We'll write it in .NET and then utilize it inside our existing COM application. Here is the class code for our assembly. I generated the GUID in this example by using the steps above within Visual Studiousing System: Here are the relevant entries from the AssemblyInfo.cs file: In order to test this, I simply created a new standard EXE project in Visual Basic 6.0. I added a reference to the newly registered DLL with the description "CodeGuru COM Interop Sample" as it was dictated in AssemblyInfo. Here is the output from executing the application. In past columns, we've built some starter objects that you can grow and develop to fit your needs. In this column, we did not build any such objects. As a result, the possible enhancements this time around involve additional COM Interop concepts you can consider exploring. The next column is yet to be determined. It is likely I am going to dive into some of the items in the EnterpriseServices namespace. If you have something in particular that you would like to see explained here, you can reach me at mstrawmyer@crowechizek.com. Mark Strawmyer, MCSD, MCSE (NT4/W2K), MCDBA is a Senior Architect of .NET applications for large and mid-size organizations. Mark is a technology leader with Crowe Chizek in Indianapolis, Indiana. He specializes in architecture, design, and development of Microsoft-based solutions. You can reach Mark at mstrawmyer@crowechizek.com.
COM Interoperability and .NET
February 27, 2003
Why We Need COM Interop
How COM Interop Works
Strong Naming
How to Make an Assembly Strong Named
Use an Unmanaged COM Object in a Managed .NET Application
Option 1: .NET Client Object is not Strong Named
Option 2: .NET Client Object is Strong Named
Sample COM Object
'****************************************************************' Description: Left pad the given string with the given string' until it reaches a string of the desired length.'' Parameters: v_strInput - string to pad' v_strPad - string to pad with' v_intLength - desired string length'' Return Val: String - string left padded with given char'****************************************************************Function leftPad(ByVal v_strInput As String, _ ByVal v_strPad As String, _ ByVal v_intLength As Integer) As StringOn Error GoTo ErrorCode Dim intCount As Integer ' Loop controlDim intLenPad As Integer ' Length of the pad stringDim strOutput As String ' Output string intCount = Len(v_strInput) intLenPad = Len(v_strPad) strOutput = v_strInput While (intCount < v_intLength) strOutput = v_strPad & strOutput intCount = intCount + intLenPad Wend leftPad = strOutput ErrorCode: If (Err.Number <> 0) Then leftPad = v_strInput End IfEnd Function
Sample .NET Application
/// <remarks>/// Sample client to use the SampleUtil COM component./// </remarks>public class SampleUtilClient{ public SampleUtilClient() { SampleUtil.clsCommon utility = new SampleUtil.clsCommon(); string test = utility.leftPad("testing", "0", 50); }}Use a Managed .NET Object in an Unmanaged COM Application
Sample .NET Object
namespace COMInteropUtil{ /// <remarks> /// Utility class to be called by a COM component. /// </remarks> [System.Runtime.InteropServices.Guid("6CF0486C-692B-4591-80D5-0C84D6CD5901")] public class SampleUtil { /// <summary> /// Left pad a string until it reaches a string of the /// desired length. /// </summary> /// <param name="source">Source string</param> /// <param name="padPhrase">Phrase to pad with</param> /// <param name="totalWidth">Total length of padded /// string</param> /// <returns></returns> public string LeftPad(string source, string padPhrase, int totalWidth) { int count = source.Length; int lengthPad = padPhrase.Length; string output = source; while( count < totalWidth ) { output = padPhrase + output; count += lengthPad; } return output; } }}[assembly: AssemblyTitle("CodeGuru COM Interop Sample")][assembly: AssemblyDescription("CodeGuru COM Interop Sample")][assembly: AssemblyKeyFile("..\\..\\key.snk")]Sample COM Application
Private Sub Form_Load() Dim strTest As String Dim objInterop As New COMInteropUtil.SampleUtil strTest = objInterop.LeftPad("test", "pad", 50) MsgBox strTestEnd Sub
Possible Enhancements
Future Columns
About the Author