Call A C# Assembly From VB6
I have had to figure this out twice now, so I will write it down this time: how to call and debug a c# assembly from VB6 in a development environment. The first thing you have to do is set up your c# assembly so that it is exposed as a COM object. This is more or less covered here, and I am sure elsewhere, but by way of an example, let’s create a .NET assembly that reverses strings (For this purpose, we will use some techniques outlined by Mladen Prajdić at his I want some Moore blog).
I will create a String.Utilities project with a single public Reverser class. This class is implemented as follows:
1: using System;
2: using System.Collections.Generic;
3: using System.Text;
4: using System.Runtime.InteropServices;
5:
6: namespace String.Utilities {
7:
8: // ClassInterfaceType.AutoDual allows early-bound
9: // COM clients and compile-time checking. Note that
10: // it completely ignores COM versioning, and that
11: // you should recompile your COM clients every time
12: // this .NET component is changed.
13: [ClassInterface(ClassInterfaceType.AutoDual)]
14: public class Reverser {
15:
16: // Types must have a public default constructor
17: // to be instantiated through COM. Managed public
18: // types are visible to COM, but without a public
19: // default constructor (a constructor without
20: // arguments), COM clients cannot create an
21: // instance of the type.
22: public Reverser() {
23: }
24:
25: // We use this attribute to specify which public
26: // methods will be visible to COM. The default
27: // value is true for public methods, so this is
28: // not really necessary!
29: [ComVisible(true)]
30: public string Reverse(string str) {
31: // This method is from Mladen Prajdić's
32: // I want some Moore blog:
33: // http://weblogs.sqlteam.com/mladenp/archive/2006/03/19/9350.aspx
34:
35: char[] charArray = str.ToCharArray();
36: int len = str.Length - 1;
37:
38: for (int i = 0; i < len; i++, len--) {
39: charArray[i] ^= charArray[len];
40: charArray[len] ^= charArray[i];
41: charArray[i] ^= charArray[len];
42: }
43: return new string(charArray);
44: }
45:
46: [ComVisible(true)]
47: public string BetterReverse(string x) {
48: // This method is from Mladen Prajdić's
49: // I want some Moore blog:
50: // http://weblogs.sqlteam.com/mladenp/archive/2006/03/19/9350.aspx
51:
52: char[] charArray = new char[x.Length];
53: int len = x.Length - 1;
54: for (int i = 0; i <= len; i++)
55: charArray[i] = x[len - i];
56: return new string(charArray);
57: }
58: }
59: }
Code is interop ready, now we just need to set up some project settings. First, we have to update (or add) the ComVisible setting in the c# project’s AssemblyInfo.cs file (this is the thing I always forget to do):
1: // Setting ComVisible to false makes the types in this assembly not visible
2: // to COM components. If you need to access a type in this assembly from
3: // COM, set the ComVisible attribute to true on that type.
4: [assembly: ComVisible(true)]
Next, open the project’s properties and click on the Build tab. Ensure the Register for COM interop option is selected:
In order to be able to debug this while running the VB6 client from the development environment, you want to go to the Debug tab and select the Start external program option specifying the path to the VB6.exe.
Now we can build the assembly. When we debug, as specified in the debug options, VB6 will start. You can then open an existing project (or create a new one) that you want to use as a client for the .NET service. Click on the (VB6’s) project references and select the .NET assembly (which is now exposed as a COM object):
Here is my VB6 client code for calling the .NET assembly:
1: Private Sub cmdReverse_Click()
2:
3: ' Notice how the dot (".") came across as
4: ' an underscore!
5: Dim aReverser As String_Utilities.Reverser
6: Dim reversed As String
7:
8: ' Instantiate the .NET Reverser object
9: Set aReverser = New String_Utilities.Reverser
10:
11: ' Call a method in the assembly
12: reversed = aReverser.Reverse(txtString.Text)
13:
14: ' Show the user the text in reverse
15: lblReverse.Caption = reversed
16:
17: End Sub
Running the VB6 client and clicking the button gives the following:
Of course, within the VB6 environment you can fully debug the client (set breakpoints, add watches, etc.). Now, run the VB6 project again, but this time set a breakpoint at public string Reverse(string str) in the Reverser class in VS2005. When you click the button, you will break at the Reverse method in the .NET debugging environment:
Therefore we can call an assembly from a VB6 application and debug both sets of code at the same time. A couple things: (1) the assembly is only registered as a COM object for the lifetime of the debugging session initiated from VS2005. So you cannot open VB6 and debug on its own without building and registering the assembly as a COM object (you use the regasm utility). (2) there is a better way than using ClassInterfaceType.AutoDual to expose the class in COM which I will cover another day.