If you have a PH account, you can customize your PH profile.

Real Stories of .NET Interop: C#, VB.NET and VB6

Applies to

OS: NT, 9x, 2000
VB: 6, .NET Framework

This article attempts to provide a tutorial as well as help with the troubleshooting of your own interop issues. I will describe the issues with using libraries written in C# or VB.NET in your VB6 applications. The reason, this is an issue, is because there is a lot of new code available only in C# or VB.NET that access new functionality of the OS. Or it could simply be the case that there is already existing C# code that's not available as a COM library, that you want to use.

What brought this on is that I needed to integrate the Windows Task Scheduler (Start/Run/Tasks) into one of my applications. I didn't want to spend time wrapping the Task Scheduler's WinAPI calls, so I looked for a pre-cooked solution on Google. I saw a bunch of code that didn't work very well and finally settled on a pretty well debugged library (in its second version) on the CodeProject web site. This library is written in C#.

So, what most web sites tell you about Interop can essentially be boiled down to these steps:

1. Create a strong key by running sn –k mykey.snk from the command line.
2. Add the path of this generated file to your AssemblyInfo.vb or .cs file in the following manner:

VB.NET: <Assembly: AssemblyKeyFile("c:\path\mykey.snk")>
C#: [assembly: AssemblyKeyFile(@"c:\path\mykey.snk")]

3. After compiling your assembly to a DLL, you must register it for COM Interop from the command line:

regasm c:\path\MyDll.dll /tlb:MyDll.tlb

4. Finally, you should install the DLL into the Global Assembly Cache by dragging the .DLL file into the c:\windows\assembly folder

So, by all means, do these steps above as they are necessary to lay the Interop groundwork. But if that's all you are going to do before calling the library from VB6, you are in a world of hurt. Let's go over each of the issues you will run into and how to overcome them.

Complaint:I distributed my application to a client, registered the assembly for Interop, but my VB6 application does not see the library (e.g. getting error 429 - can't create ActiveX component). Or - I recompiled the C# library and now my VB6 app does not see the app.

The issue in both these complaints is that VB6 communicates to the outside libraries via GUIDs that are assigned to an object in a DLL. These GUIDs are then stored with the DLL information in the registry, which is where VB6 apps look to find the linked libraries. Therein lies the problem: .NET assemblies don't know anything about GUIDs by default. Your job is to assign them a unique GUID attribute. You have to do this for each and every public class (at least the ones that you plan to call from VB6). Here is how:

VB.NET:<GuidAttribute("BA713700-522D-466e-8DD4-225884504678")>
C#:[GuidAttribute("BA713700-522D-466e-8DD4-225884504678")]

Now where do you get the GUIDs? In VS.NET go to the Tools menu and select Create Guid. You can copy the GUID from there. Now when you recompile your .NET assembly or run regasm command on it, the assembly will have the a consistent set of GUIDs, thus never breaking binary compatibility.

Complaint:I don't see the .NET assembly in the VB6 Object Browser or I don't get any intellisense on .NET objects.

AFAIK, there are 2 types of COM interfaces. By default, the COM interface that is generated from the .NET assembly is not the one VB6 knows much about. So, the solution is to ask .NET compiler to generate the interface that VB6 does know about. To that end, add yet another attribute to all your public classes:

VB.NET:<ClassInterface(ClassInterfaceType.AutoDual)>[/b]
C#:[ClassInterface(ClassInterfaceType.AutoDual)][/b]

Recompile your .NET code and you'll now see the .NET objects in your Object browser and get the Intellisense on those entities as well.

Complaint: I can't instantiate .NET objects in VB6. Dim myObj as new DotNetObject results in an error.

.NET has a concept of parametrized constructors. For instance:

	class Stuff 
	{
		//constructor
		public Stuff(string TaskToDo)
		{
			...
		}
	}
	
	//call this class
	Stuff myStuff = new Stuff("Buy Groceries");	


As you can see the only way to create a new Stuff object is to call it with a parameter. However, you can't do this in VB6 because it does not have parametrised constructors.

VB6:
Dim myStuff as New Stuff("Buy Groceries")	
'will not work because the Stuff class in the C# assembly 
'requires a parameter in the constructor.


violates VB6 syntax

VB6:
Dim myStuff as New Stuff()	
'will not work because the Stuff class in the 


C# assembly requires a parameter in the constructor. So the only solution to this problem is to create a constructor in the C# class that takes no parameters. And, for a good measure create a property which will could replace the TaskToDo parameter. Here is the resulting C# class.

	class Stuff 
	{
		string msStuffToDo = "";
		
		//constructor without the parameter
		public Stuff()
		{
			...
		}
	
		//constructor with the parameter
		public Stuff(string TaskToDo)
		{
			...
		}
		
		public string TaskToDo 
		{
			get { return msStuffToDo;}
			set { msStuffToDo = value;}
		}		
	}
	
	//call this class from C# with parametrized constructor
	Stuff myStuff = new Stuff("Buy Groceries");	
	//call this class from C# without parametrized constructor	
	Stuff myStuff = new Stuff();
	myStuff.TaskToDo = "Buy Groceries";


Finally, we can now instantiate the Stuff class in VB6:

	Dim myStuff as New Stuff()	
        'works because our C# class now provides a constructor 
        'with no parameters
	myStuff.TaskToDo = "Buy Groceries"


Quick note, even thought I used Dim obj as New Object(), VB6 programmers should stick with this syntax, because of well-known issues, I won't go into here:

        Dim myStuff as Stuff()
			
	Set myStuff = New Stuff()
	myStuff.TaskToDo = "Buy Groceries"
	...
	Set myStuff = Nothing		


Having addressed all these issues, you can now be sure that the .NET objects will behave as seamlessly as native COM objects. By the way, these issues apply whether you are calling .NET objects from VB6, ASP or any other COM capable language, such as PHP, Delphi or Python. Happy Interoping.






 

Other Views

corner
Popular resources and forums for programmers on Programmersheaven.com
Assembly, Basic, C, C#, C++, Delphi, Java, JavaScript, Pascal, Perl, PHP, Python, Ruby, Visual Basic
© Copyright 2009 Programmersheaven.com - All rights reserved.
Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
Publisher: Lars Hagelin. Read the latest words from the publisher here.
Be the first to sign up for Lars Hagelin’s In-depth Outsourcing Newsletter here.
bootstrapLabs Logo A bootstrapLabs project.