Exposing COM interfaces of a .NET class library for Late Binding

原创 2004年08月22日 11:16:00

Introduction

For my last project, I developed a nice library in VB.Net for Credit Card Processing. It used sockets and the message format between our servers and those of Citibank was based on a variant of ISO 8583. Calling this library from ASP.Net pages was working fine. But, my Project Manager wanted it to be called from some old VB 6 and classical ASP applications too. So, this scenario demanded that there should be some sort of COM interface to access that component. Also, our Tech. Lead wanted to use Late Binding (i.e. "CREATEOBJECT (PROG ID)") to instantiate this component / class library.

So, I was asked to build COM interface for this class library. I did some research and found some very useful articles that dealt with the same problem. However, I found them somewhat difficult to follow. However, I managed to complete my development using those articles. Now, I want to to share my own experience in a somewhat easier manner (at least I believe so) to make life easier for other developers. The only prerequisite for this article is that you should have Microsoft Visual Studio .Net and should have some basic knowledge of COM.

Problem

Obviously, I cannot present the actual class here. In stead, I will use a very simple class for demo purposes. This class is written in VB.Net as a Class Library. Now, the requirement is that it is to be accessed from clients (VB 6 , classic ASP or even ASP.Net application using Late Binding) with

CreateObject (PROG ID of the component).
If you follow this example, you can apply the same procedure for very complex classes too.
Public class demo
    Private csError As String ' stores the error message
    Public ReadOnly Property ErrorMsg() As String
        Get
            Return csError
        End Get
    End Property
    Public Function Concat(ByVal str1 As String, ByVal str2 As String) As STRING
        return Concat = str1 + " " + str2
    End function

End class 

This class demo which has a property ErrorMsg and one function Concat, built as a class library project using Visual Studio.Net, has been given a Strong Name using the strong name tool sn.exe. It is important to note that you can avoid strong naming your assembly. however, I would advise you against it. If you do not want to use the strong name, then keep your component and the calling client in the same directory.

Solution

As I found out, there are two ways to solve this problem. One is very easy while the other one is a bit hard. Unfortunately, I came to know the hard one first and discovered the second one after I had implemented my component using the hard method.

Solution 1 : To create a COM object using the COM class template of Visual Studio . Net

The easiest way to create COM objects is by using the COM class template of Visual Studio .Net. The COM class template creates a new class, then configures your project to generate the class as a COM object and registers it with the operating system automatically. All the background work will be done by Visual Studio (how nice !!).
Here are the steps involved using Visual Studio .Net:

  1. Open a New Windows Application project by clicking New on the File menu, and then clicking Project. The New Project dialog box will appear.
  2. With Visual Basic Projects highlighted in the Project Types list, select Class Library from the Templates list, and then click OK. The new project will be displayed.
  3. Select Add New Item from the Project menu. The Add New Item dialog box will be displayed.
  4. Select COM Class from the Templates list, and then click Open. Visual Basic .NET will add a new class and configure the new project for COM interop.
  5. Add code, such as properties, methods, and events to the COM class. In our case we will just copy the code for property ErrorMsg and method Concat into the class and rename the class to class demo.
  6. Select Build Solution from the Build menu. Visual Basic .NET will build the assembly and register the new COM object with the operating system automatically.

What 's next ? nothing folks. Your COM component is ready to be accessed from any VB or classic ASP page etc. using Createobject(...).

Solution 2 : Do it yourself approach

This is a little bit difficult as compared to method number 1. But, if you are a programmer who likes to go little bit deeper into details, you will be inclined to go this way. Some basic knowledge about COM is required.
Once you complete all the steps for this method, your class will look quite similar to this one.

Imports System.Runtime.InteropServices

<Guid("1F249C84-A090-4a5b-B592-FD64C07DAB75"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _demo
    <DispId(1)> Function Concat(Byval s1 as string, ByVal S2 As String) as string 
    <DispId(2)> readonly Property ErrorMsg() as string 

End Interface

<Guid("E42FBD03-96DF-43a7-A491-23E735B32C5C"), _
ClassInterface(ClassInterfaceType.None), _
ProgId("comDemo.demo")> Public Class demo
    Implements _demo
Private csError As String ' stores the error message
    Public ReadOnly Property ErrorMsg() As String
implements _demo.errormsg
        Get
            Return csError
        End Get
    End Property
Public Function Concat(ByVal str1 As String, ByVal str2 As String) As STRING
implements _demo.Concat
 return Concat = str1 + " " + str2
end function
end class 

STEPS INVOLVED:

1. Add the interop namespace to your class

Imports System.Runtime.InteropServices
2. Then develop an interface with the same name as of your original class, just add _ before it to make it different. For our example, it will be like
Public Interface _demo
    

End Interface 
3. Then, create a GUID for this interface. To create GUID for your COM object, click Create GUID on the Tools menu, or launch guidgen.exe to start the guidgen utility. Search for the file guidgen.exe on your machine. It is located under c:/program files/ Microsoft visual studio .net/common7/ tools directory on my computer. Run it. Then, select Registry Format from the list of formats provided by the guidgen application. Click the New GUID button to generate the GUID and click the Copy button to copy the GUID to the clipboard. Paste this GUID into the Visual Studio .Net code editor. Remove the leading and trailing braces from the GUID provided. For example, if the GUID provided by guidgen is {2C8B0AEE-02C9-486e-B809-C780A11530FE} then the GUID should appear as: 2C8B0AEE-02C9-486e-B809-C780A11530FE.
Once a guid is created, paste it into the class as
Guid("1F249C84-A090-4a5b-B592-FD64C07DAB75") 
Then use the interfacetype attribute to make it a Dispatch interface required by automation as
InterfaceType(ComInterfaceType.InterfaceIsIDispatch) 
Unless you specify otherwise, the export process converts all managed interfaces to Dual interfaces in a type library. Dual interfaces enable COM clients to choose between Early and Late Binding.You can apply the InterfaceTypeAttribute attribute to an interface to selectively indicate that the interface should be exported as a Dual interface, an IUnknown-derived interface, or a dispatch-only interface (dispinterface). All exported interfaces extend directly from either IUnknown or IDispatch, regardless of their inheritance hierarchy in managed code.

4. In the interface, expose the methods, properties etc that you want the clients to see and access. In our case, we will expose both our property and our method and will assign arbitrarily values of 1 and 2 as dispids. Our interface will look like this at this point of time

 <Guid("1F249C84-A090-4a5b-B592-FD64C07DAB75"), _
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface _demo
    <DispId(1)> Function Concat(Byval s1 as string, ByVal S2 As String) as string 
    <DispId(2)> readonly Property ErrorMsg() as string 

End Interface
5. In a similar fashion, you need to create a GUID for the actual class too.
Guid("E42FBD03-96DF-43a7-A491-23E735B32C5C") 
Next, use the interop attributes as follows
ClassInterface(ClassInterfaceType.None), _
ProgId("comDemo.demo")> Public Class demo
    Implements _demo 
You must have noticed that you have to specify the ProgID for the class here. This is the same ProgID that we will be using to call our component as follows;
set myobject = createobject ("comDemo.demo") ' vb6 or vbscript

implements _demo suggests that the class is implementing the interface. Note that we are using classinterfacetype.none for the classinterface attribute. Microsoft states that
"To reduce the risk of breaking COM clients by inadvertently reordering the interface layout, isolate all changes to the class from the interface layout by explicitly defining interfaces.Use the ClassInterfaceAttribute to disengage the automatic generation of the class interface and implement an explicit interface for the class, as the following code fragment shows:

<ClassInterface(ClassInterfaceType.None)>Public Class LoanApp
   Implements IExplicit
   Sub M() Implements IExplicit.M
…
End Class
The ClassInterfaceType.None value prevents the class interface from being generated when the class metadata is exported to a type library. In the preceding example, COM clients can access the LoanApp class only through the IExplicit interface."

6. The next step is to modify the properties and methods signatures which we want to expose. So

Public ReadOnly Property ErrorMsg() As String 
becomes
Public ReadOnly Property ErrorMsg() As String implements _demo.errormsg 
and
Public Function Concat(ByVal str1 As String, ByVal str2 As String) As String
becomes
Public Function Concat (ByVal str1 As String, ByVal str2 As String) 
  As String implements _demo.Concat
7. Once you make these changes to your class , you are all set. Just one more change is required to make it complete. Right click the project to bring the project properties, there under the Build properties check the interop check box. When building the project, this will ensure that a type library is created for the COM Interface and is registered too. If you do not want to use this option, you can use Regasm utility to do the same. For Regasm, the syntax would be
regasm demo.dll /tlb: demo.tlb
It will create the type library and will register it to for you.

That was it

You can build the project and can access it
  1. Through Late binding : using createobject("comDemo.demo") or
  2. Through Early binding: by setting reference to this component in you project

Strong Name Requirement

It is recommended that your assembly should have a strong name. For that, you can use the strong name tool sn.exe. If you would not create the strong name, then you will have to keep the component and the calling program in the same directory.

Data Binding Library(数据绑定库)

正常情况下,互联网APP都会从服务器抓取数值,然后在 Activity中 findViewById 再进行setText等等。这篇文章就是用来解放你的双手劳动力 的,使用数据绑定库可以不用去find...
  • yang786654260
  • yang786654260
  • 2016年06月02日 22:26
  • 5660

JSF中UI控件binding属性的用法

以下内容为我在CSDN上转载的,版权归属原作者!    在.Net中,binding是个十分容易理解的东西,但最近学习JSF,总理解不了binding属性的用法,查了一些资料,都是简单的说明,对...
  • nash603
  • nash603
  • 2014年11月05日 15:08
  • 1119

Windows Hook经验总结之四:COM组件Hook原理及实践

前面已经介绍过API的hook方法及具体实践,本文则讲述COM组件的Hook方式。COM组件可简单理解为一个二进制可执行程序或DLL,内部包含一系列的接口和函数。Hook COM本质上也是进行函数地址...
  • u011559599
  • u011559599
  • 2016年11月17日 14:31
  • 1083

C#开发COM组件

原文:http://blog.csdn.net/soudog/article/details/1593346 1.    概述        Microsoft在解决和以往的COM和SDK开发...
  • jiftlixu
  • jiftlixu
  • 2016年03月09日 14:20
  • 3100

从OLE到COM,再到ActiveX,再到.NET

微软从OLE到COM,再到ActiveX,再到.NET的发展历史的简介
  • just0kk
  • just0kk
  • 2016年03月02日 21:31
  • 767

ubuntu中界面网络配置networkmanager与interfaces网络配置

【Server版本】 在UbuntuServer版本中,因为只存有命令行模式,所以要想进行网络参数设置,只能通过修改/etc/network/interfaces。具体设置方法如下: (1) Ub...
  • jiangheng0535
  • jiangheng0535
  • 2013年08月25日 00:38
  • 5133

COM组件与.Net组件的比较

1、COM组件与.Net组件的比较        COM技术要早于.Net技术。COM定义了一个组件模型,在该模型中,组件可以使用不同的编程语言进行编写,其可以在本地进程中使用,也可以跨进程使用或...
  • Chinamming
  • Chinamming
  • 2013年11月21日 13:47
  • 3479

C#开发COM组件供其他开发环境或工具调用介绍

由于工作原因涉及到这一块的开发,由于之前并未接触过,所以本篇文章也是在参考了各种资料后,自己实现并通过通过测试之后所整理的备忘录以及一些个人观点。 希望对刚接触这类型开发的朋友有所帮助,若有不足...
  • xiunai78
  • xiunai78
  • 2013年09月10日 11:23
  • 6199

.Net之路(十四)com组件、OLEDB导入EXCEL

.NET com组件
  • chenfanglincfl
  • chenfanglincfl
  • 2014年06月13日 23:55
  • 1991

解决Intellij idea Java JDK多重选择提示问题

问题引出 当前我们对idea 写Java的程序进行编译时,会报如下的错误提示,原因在于 idea 检测到了两个位置有jdk,它不知道选哪一个,就随便选了一个。 objc[63766]: C...
  • odeng888
  • odeng888
  • 2017年07月03日 16:46
  • 1138
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Exposing COM interfaces of a .NET class library for Late Binding
举报原因:
原因补充:

(最多只允许输入30个字)