asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search





Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

COM Interop Exposed -- Cont'd
By Patrick Steele


  • email this article to a colleague
  • suggest an article

    Taking Control

    So how do you get those methods on your .NET component to show up in VB6? You can take what you know about VB6 and COM and apply it to .NET. Basically, you need to:

    • Have an interface with your methods defined.
    • Make that interface the default interface.

    The first one is easy. Add a .NET interface that includes the methods you want to expose to COM:

    [VB.NET]

    
    Public Interface IBee
    	Sub FindFlower()
    	Sub MakeHoney()
    End Interface
    
    
    [C#]
    
    public interface IBee
    {
    	void FindFlower();
    	void MakeHoney();
    }
    
    
    Now you'll simply implement that interface in your Bee class.

    [VB.NET]

    
    Public Class Bee
    	Implements IBee
    
    	Public Sub FindFlower() Implements IBee.FindFlower
    	End Sub
    
    	Public Sub MakeHoney() Implements IBee.MakeHoney
    	End Sub
    End Class
    
    
    [C#]
    
    public class Bee : IBee
    {
    	public void FindFlower()
    	{
    	}
    
    	public void MakeHoney()
    	{
    	}
    }
    
    
    You'll compile this component, run the TLBEXP.EXE utility and check it out with OLE View. What you see may surprise you:
    
        interface IBee : IDispatch {
            ...
            HRESULT FindFlower();
            ...
            HRESULT MakeHoney();
        };
    
        coclass Bee {
            [default] interface _Bee;
            interface _Object;
            interface IBee;
        };
    
        interface _Bee : IDispatch {
        };
    
    
    The IBee interface came straight through as a standard COM interface - it even includes the methods. The "Bee" coclass even implements this class (as expected), but there's still that (empty) _Bee interface that is marked as the default interface. And that's where VB6 will look for the methods belonging to the class.

    But the IBee interface is exposed as a standard COM interface so you could do everything through that interface and it would work fine. For example, using the type library created above, this VB6 code is perfectly legal:

    
    Dim bee As IBee
    Set bee = New Bee
    bee.FindFlower
    bee.MakeHoney
    
    
    To make a cleaner integration, however, the IBee interface needs to be the default interface. That is accomplished through attributes.

    Attributes

    If you're not familiar with attributes, here's a quick summary. Attributes are a "descriptive declaration". They're used to "annotate" programming elements such as types, fields, methods, classes, etc... Attributes can have values associated with them and those values, along with the attribute information, are saved with all of the other .NET metadata. They can be used to describe code to the CLR (Common Language Runtime) or to affect application behavior at runtime.

    To control how TLBEXP.EXE creates the type library, you can use an attribute to prevent it from creating that "default" interface. The "ClassInterfaceAttribute" can be applied to a class with the "ClassInterfaceType.None" enumeration member. It can also be applied at the Assembly level where it would apply to every public class in the Assembly. Using the example above, you can make a small modification to the Bee class and apply the attribute:

    [VB.NET]

    
    Option Strict On
    Option Explicit On 
    
    Imports System.Runtime.InteropServices
    
    Namespace QuickNET
    	<ClassInterface(ClassInterfaceType.None)> _
    	Public Class Bee
    		Implements IBee
    
    		Public Sub FindFlower() Implements IBee.FindFlower
    
    		End Sub
    
    		Public Sub MakeHoney() Implements IBee.MakeHoney
    
    		End Sub
    	End Class
    End Namespace
    
    
    [C#]
    
    using System;
    using System.Runtime.InteropServices;
    
    namespace QuickNET
    {
    	[ClassInterface(ClassInterfaceType.None)]
    	public class Bee : IBee
    	{
    		public void FindFlower()
    		{
    		}
    
    		public void MakeHoney()
    		{
    		}
    	}
    }
    
    
    After compiling this and re-creating the type library, OLE View shows a much cleaner structure:
    
        interface IBee : IDispatch {
            ...
            HRESULT FindFlower();
            ...
            HRESULT FindHoney();
        };
    
        coclass Bee {
            interface _Object;
            [default] interface IBee;
        };
    
    
    Not only do you not have the "_Bee" interface, but your IBee interface is marked as the default interface. Why is that? If the ClassInterfaceAttribute specifies that no automatic interface is to be generated, TLBEXP.EXE will take the first interface implemented by the class and make it the default interface. So if you plan on exposing your .NET class to COM, take into account which interface is the first interface implemented in the source code (either through the VB.NET "Implements" keyword or the first interface listed after the ":" in your C# class definition).

    Controlling Your GUIDs

    The last thing you need to control is your GUIDs - Globally Unique Identifiers. You've probably seen a GUID before. Here's a sample:

    
    82CC3E6A-148E-4b77-866E-598DBEDC5C74
    
    
    Every interface in COM and every coclass (creatable class object) is identified by a unique GUID. VB6 controls GUID creation for you. You can "coax" VB6 into using the same GUIDs for classes and interfaces by using the "Binary Compatibility" mode of your VB6 project when recompiling. The .NET TLBEXP.EXE utility will also auto-generate a GUID for every interface and class it exports to COM. But you can use attributes to define the GUID yourself.

    Why should you care? Whenever you register a .NET object as a COM component, registry entries are created. Some of those registry entries are the GUIDs used to identify your classes and interfaces to COM. If you don't specify a specific GUID, TLBEXP.EXE will generate a new one every time you re-create your COM type library. COM clients already developed could have references to the old GUID and would no longer work since the GUIDs changed. Likewise, if you do control and define a specific GUID for your classes and interfaces, then the GUIDs aren't changing and your COM clients won't need to be recompiled and will continue to work even with new versions of your .NET component.

    You can use attributes to define a GUID for your classes and interfaces. Instead of trying to "make up" your own unique GUID, VS .NET (along with previous versions of Visual Studio) comes with a tool for generating a GUID called (interestingly enough) guidgen.exe. This should be found in the "\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools" directory. Double-click on it and you should see a screen similar to the one below:

    GUIDs are used in many different places, so guidgen supports creating a GUID in four different formats. For your purposes, you need the fourth format: Registry Format. You don't need the opening and closing braces, but you can trim those off. Press "New GUID" to generate a new GUID and then "Copy" to copy it to the clipboard.

    Now define a GUID for your IBee interface (make sure you've added the System.Runtime.InteropServices namespace to your code). Paste the clipboard into the "Guid" attribute and remove the leading and trailing braces:

    [VB.NET]

    
    <Guid("0490E147-F2D2-4909-A4B8-3533D2F264D0")> _
    Public Interface IBee
    	Sub FindFlower()
    	Sub MakeHoney()
    End Interface
    
    
    [C#]
    
    	[Guid("0490E147-F2D2-4909-A4B8-3533D2F264D0")]
    	public interface IBee
    	{
    		void FindFlower();
    		void MakeHoney();
    	}
    
    
    Now the class also needs its own GUID. Go back to guidgen, click "New GUID" and then "Copy". Now apply the Guid attribute to the class with the new GUID value (again, trim the braces):

    [VB.NET]

    
    <ClassInterface(ClassInterfaceType.None), _
    Guid("03AD5D2D-2AFD-439f-8713-A4EC0705B4D9")> _
    Public Class Bee
    	Implements IBee
    
    	Public Sub FindFlower() Implements IBee.FindFlower
    
    	End Sub
    
    	Public Sub MakeHoney() Implements IBee.MakeHoney
    
    	End Sub
    End Class
    
    
    [C#]
    
    	[ClassInterface(ClassInterfaceType.None)]
    	[Guid("03AD5D2D-2AFD-439f-8713-A4EC0705B4D9")]
    	public class Bee : IBee
    	{
    		public void FindFlower()
    		{
    		}
    
    		public void MakeHoney()
    		{
    		}
    	}
    
    
    Now tblexp will always use the same GUID.

    << Introduction •       • Deployment >>

  • Other Articles
    Feb 23, 2005 - My Feature in Visual Basic 2005
    In this article, Thiru Thangarathinam demonstrates the different classes and features available through the My namespace. By providing a speed-dial that allows you to more quickly and effectively utilize .NET framework functionalities in your application, the My feature provides huge productivity improvements for .NET developers.
    [Read This Article]  [Top]
    Oct 6, 2004 - Creating Triggers Using Managed Code in SQL Server 2005
    Thiru Thangarathinam discusses taking advantage of the integation between the .NET CLR and SQL Server 2005 in order to do things like create triggers using managed code.
    [Read This Article]  [Top]
    Sep 8, 2004 - Custom Object Data Binding with .NET
    Developers often use brute force coding to marshal data between the GUI and application objects. In this article, Luther Stanton explains how to use .NET's out-of-the box data-binding functionality to make this job much easier.
    [Read This Article]  [Top]
    Aug 17, 2004 - The Perfect Service - Part 2
    Ambrose Little provides the complete source code for his 'Perfect Service' and explains how the .NET Service Manager enables features such as drag-n-drop deployment.
    [Read This Article]  [Top]
    Aug 12, 2004 - Middle-Tier Hosting: Enterprise Services, IIS, DCOM, Web Services, and Remoting
    There is broad-reaching debate about remoting, Web services, Enterprise Services, and DCOM. In short, it is a debate about the best technology to use when implementing client/server communication in .NET. Rocky Lhotka shares his thoughts on the issue while offering clear explanations of basic application architecture terminology.
    [Read This Article]  [Top]
    Jul 21, 2004 - COM Interop Exposed
    This article provides and excellent foundation for COM Interop. It reviews COM's background, explains how VB6 interacts with COM, and then shows how to design .NET components to smoothly interact with COM.
    [Read This Article]  [Top]
    Jun 24, 2004 - The Perfect Service - Part 1
    The first article in this two-part series shows how to get Ambrose Little's .NET Service Manager running and then how to add plug-n-play services to it using drag-n-drop or XCOPY.
    [Read This Article]  [Top]
    May 25, 2004 - Generics In-Depth
    Although generics are extremely useful, they also seem to have a certain mystique that cannot be readily explained. This article hopes to remove that aura of mystery by showing just how easy it is to use generics and how useful they can be in many common situations.
    [Read This Article]  [Top]
    May 11, 2004 - SharePoint Security and .NET Impersonation
    When implementing custom components that require access to restricted resources, implicit impersonation must be used. Jay Nathan shows how to create a class that makes using .NET Impersonation a snap.
    [Read This Article]  [Top]
    Mar 23, 2004 - Exploiting .NET's Advanced Deployment Features
    Tony Arslan shows how to use VS .NET's custom deployment feature to create configuration files on the target machine during installation.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info

    Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers