You've been using the TLBEXP.EXE utility throughout this article to generate a COM type library. That's because, so far, you've only been interested in seeing how .NET exposes its structures to COM. To actually make the .NET component look like a COM component, you need to register it just like any other COM component.
I'm sure you're familiar with regsvr32: the utility for registering and unregistering COM components. This utility won't work for a .NET component. Instead, you'll need to use the .NET utility "regasm.exe" - short for "Register Assembly". This utility adds registry entries to make your .NET component "look" like a regular COM component.
The REGASM.EXE utility also has the option to generate a COM type library which can be used by VB6. The "/tlb" option on REGASM performs the same thing that TLBEXP.EXE does. Therefore, you really don't need to use TLBEXP when creating a .NET object for COM. Just use REGASM with the /tlb option. Here's an example. Go to the Visual Studio .NET 2003 Command Prompt, change to the directory of your .NET assembly, and enter:
REGASM myassem.dll /tlb:com.myassem.tlb
Your object is now registered as a COM component, and you have a COM type library you can reference from VB6 to early-bind to the component. Now all you need to do is get COM to find the .NET assembly.Local Deployment or the GAC?
Once your .NET assembly is registered as a COM component, any attempt to create an instance of one of the .NET components from COM will cause a copy of the .NET runtime to be loaded. The .NET runtime will then need to locate the assembly. Even though you're running in a COM environment, the .NET rules for finding an assembly still apply:
Tirst, the Global Assembly Cache (GAC) is checked.
Then, the local directory is checked.
The second option is a bit easier but not as flexible. For the first option, simply copy the .NET assembly to the same directory as your COM exe client and the runtime will find it. However, if you're building/debugging in the VB6 IDE, then the "local directory" is the location of VB6.EXE. In this situation, you need to copy your .NET assembly to different locations depending on whether you're running inside the VB6 IDE or not. And copying files into the same directory as VB6.EXE isn't a great idea. If you make any updates to the .NET assembly, you need to make sure you copy it to both locations. For these reasons, placing the assembly in the Global Assembly Cache (GAC) is usually the best option for COM Interop.
Before placing an assembly in the GAC, you need to make sure you've got a fixed versioning scheme and a strong-name key pair. Getting a fixed versioning scheme is simple: In your AssemblyInfo file, change the value of the AssemblyVersion attribute from the default "1.0.*" to "1.0.0.0". The version number is a key component of placing an assembly in the GAC. Leaving the "*" makes VS .NET generate a new value every time you build your project. Since other projects that reference your assembly look for a specific version number, having it change every time you build is a problem! Therefore, hard-code a specific value and as you develop new releases of your assembly, increment the version number as appropriate.
Next, you'll need to generate a strong-name key pair. Use the SN.EXE tool by going to the Visual Studio .NET 2003 Command Prompt, changing to the directory of your .NET project and enter:
sn -k mykey.snk
Now update the AssemblyKeyFile attribute in your AssemblyInfo to point to the "mykey.snk" file. Finally, recompile your .NET component. It is now ready to be added to the GAC. Go to a Visual Studio .NET 2003 Command prompt, change to the directory of your .NET assembly and enter:
gacutil -I myassembly.dll
This installs your assembly into the GAC. Now, the runtime can locate the assembly no matter which COM client instantiates your .NET component.
Summary of Best Practices
This article has covered a lot of ground. Here's a review of the best practices for hassle-free COM Interop:
Define a .NET Interface for the methods you want to expose to COM.
Assign a GUID to that interface with the "Guid" attribute.
Have your class implement your interface as the first interface.
Assign a GUID to that class with the "Guid" attribute.
Add the "ClassInterface(ClassInterfaceType.None)" attribute to prevent regasm/tlbexp from creating an empty default interface.
Hard-code a specific version number in your AssemblyVersion attribute.
Create a strong-name key pair for your assembly and point to it via the AssemblyKeyFile attribute.
Add your assembly to the GAC,
Register your assembly for COM by using the REGASM command along with the "/tlb" option to generate a COM type library.
VB6 projects can add a reference to the generated type library to receive the benefits of early binding. Scripting clients like VBScript can also access the object, but they'll only be able to access the methods on the default interface.
When it comes time to enhance your .NET component, don't touch your existing interface. If you need to add more methods, create a new interface (with a Guid) and implement that interface. Changing the existing interface could break clients already compiled against that interface.
About the Author
Patrick Steele is a Lead Software Architect for Image Process Design in Bloomfield Hills, MI. There, he architects and develops workflow solutions for insurance and healthcare companies using VB6, C#, SQL and Oracle. Through Volunteer-IT, Patrick is currently the project lead for the Michigan Senior Olympics project. He has been a Microsoft .NET MVP for the past three years and is the webmaster of the Michigan Great Lakes Area .NET Users Group (GANG) Web site.
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]
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]
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]
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]
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]
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]
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]
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]
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]
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.