logo
vbRad Home
Source Code
Book Reviews
Forum
Links
About Us
Contribute

Compare Databases with SQL Effects Clarity
 
 Real Stories of .NET Interop: C#, VB.NET and VB6

Posted on
4/29/2004
Author:
Robert Gelb
Email:
Not Shown
Applies To OS:
NT, 9x, 2000
Product:
N/A



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)>
	C#:	[ClassInterface(ClassInterfaceType.AutoDual)]
	
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: Ok, I've added the GuidAttribute and ClassInterface attribute. Now my code doesn't compile.

This one is easy. Add a an Imports/using statement at the top of the classes using these attributes:
	VB.NET:	Imports System.Runtime.InteropServices
	C#:	using System.Runtime.InteropServices;
	
Thanks to Simon Card for pointing this out.

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 - this 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.





Add Your Comment  

Name: Email Address: all fields optional
Notify me via email when someone responds to this message (valid email required).

Enter the word:
 



Comments
#1. By andrew. Posted on 3/16/2006 9:06:18 AM
Very helpful. Thanks! Real Stories is a great tool for developers.

#2. By Kevin. Posted on 5/4/2006 11:19:29 PM
Thanks for this article. Very cool and useful stuff. May I add if you have static functions in your .NET object, they will not be exposed to VB6.

#3. By Kevin. Posted on 5/9/2006 4:44:49 PM
Thanks for this article. Very cool and useful stuff. May I add if you have static functions in your .NET object, they will not be exposed to VB6.

#4. By Kevin. Posted on 5/9/2006 4:45:00 PM
Thanks for this article. Very cool and useful stuff. May I add if you have static functions in your .NET object, they will not be exposed to VB6.

#5. By Anonymous. Posted on 5/23/2006 2:05:12 AM
Thanks for the great write-up. This answers many questions that arise when using interop with C# and does so in understandable language.

#6. By Padma B Jayaraman. Posted on 5/25/2006 6:23:01 PM
Excellent article as quick reference to fix the common challenges using interops.

#7. By vineesh. Posted on 6/6/2006 5:37:38 AM
How to import an vb.net file into c#.net project

#8. By Anupam. Posted on 6/18/2006 4:12:57 PM
Hi Robert,

Thanks for the article.
I have the GUID set in my VB.net class, I register the dll using regasm, I can see the class & its methods from the VB6 app, it compiles and runs as well when I create the exe. Now, when I add another method in the vb.net class, build the dll and deploy it to the same location as it was before, the VB6 exe that is generated earlier does not run. It throws the "Runtime error '430' Class does not support Automation or does not support expected interface." Is there any way to solve this without recompiling the VB6 APP?

Thanks in advance.
Anupam Bhattacharya

#9. By Author. Posted on 6/19/2006 2:34:57 AM
Anupan,

I am afraid, this is impossible (as far as I know). But keep in mind that I am no COM expert. I just know enough to be dangerous.
I think you have to do a recompile.

Regards.

#10. By Anupam. Posted on 6/19/2006 2:41:18 PM
Rob,
Thanks for your reply.
I know that a recompile does the magic.
But in my case, the dll is used by several applications, and I am afraid that for one change in one dll, recompiling ALL the applications would not be feasible. That's why was looking for some alternatives.

I tried forcing the same CLSID to be generated, but event hough it is same, and it looks into the same CLSID in the registry, still it throws the error. Is there any other place like GAC or so, where I have to do some trick for this?

I understand that its not so easy to find out. And that is why I am here. :)
Any light thrown on this would be very much helpful.

Thanks
Anupam

#11. By Author. Posted on 6/19/2006 6:11:10 PM
Sorry, this is beyond my knowledge of COM. As an alternative, you might want to create a separate .NET DLL just to be used in your VB6 application. At least this way, you don't destroy other apps.

#12. By Anupam. Posted on 6/19/2006 6:44:55 PM
Well, that's a good idea. In fact I was thinking of creating a separate interface for this as well. But, I have to find out the feasibility for both the options. Thanks Rob.

#13. By Anupam. Posted on 6/19/2006 7:31:04 PM
Well, that's a good idea. In fact I was thinking of creating a separate interface for this as well. But, I have to find out the feasibility for both the options. Thanks Rob.

#14. By Anupam. Posted on 6/22/2006 10:02:54 AM
Rob,
Now that I have reverted back ALL the interface related changes and recompiled the DLL, it still doesn't work with the existing VB6 applications.I get the same 430 error.
I unregistered the old dll and registered the new dll using REGASM.

Am I missing something?

Thanks
Anupam

#15. By Anupam. Posted on 6/22/2006 10:20:26 AM
Rob,
Now that I have reverted back ALL the interface related changes and recompiled the DLL, it still doesn't work with the existing VB6 applications.I get the same 430 error.
I unregistered the old dll and registered the new dll using REGASM.

Am I missing something?

Thanks
Anupam

#16. By Anupam. Posted on 6/22/2006 10:52:00 AM
Rob,
Now that I have reverted back ALL the interface related changes and recompiled the DLL, it still doesn't work with the existing VB6 applications.I get the same 430 error.
I unregistered the old dll and registered the new dll using REGASM.

Am I missing something?

Thanks
Anupam

#17. By Anupam. Posted on 6/22/2006 11:32:55 AM
Rob,
Now that I have reverted back ALL the interface related changes and recompiled the DLL, it still doesn't work with the existing VB6 applications.I get the same 430 error.
I unregistered the old dll and registered the new dll using REGASM.

Am I missing something?

Thanks
Anupam

#18. By Author. Posted on 6/22/2006 5:44:42 PM
Anupan,

Your GUIDs must be out of sync. Recompile and Re-Regasm and check the GUIDs on the old and new DLLs/TLBs using a tool like OLE View or something like that.

Regards

#19. By Anupam. Posted on 6/22/2006 8:07:01 PM
You are right Rob, I checked both the old and the new TLB using OLE VIEW and the UUIDs of the assembly as well as of all the classes are different. Is there any way I can get back my original UUIDs in the asembly as well as in all the classes inside it?

Thanks
Anupam

#20. By Author. Posted on 6/23/2006 2:13:54 AM
Anupan. I don't know how to do this trick.

#21. By boB. Posted on 8/2/2006 4:29:11 PM
Great stuff; really! However, I have a .NET class that I've created as a DLL. This class implements an Interface I've created in the same DLL and reads an XML that it retrieves the Path from the ...GetExecutingAssembly().GetName() methodology. The function of the class is to call a WebService class that retrieves AD information which also reads an App.Config file. Then I created a VB6 wrapper that calls it so that it could be used in SQL Server 2000. This all worked fine. Then, I recompiled the 1st DLL because I needed a small change to the code (not signatures) and now, no matter what I do, it won't work. I keep getting "429 - can't create ActiveX component" when I use the Set obj As New MyObject. I have it in the GAC (with a strong name of course), I have TLB's for both DLL's, both DLL's are in the System32 folder (though I know they don't have to be), they both have GUID's assigned, and yet still the same error. Can you point me in the right direction?

#22. By Anupam. Posted on 8/2/2006 6:06:30 PM
Bob,
I would suggest you to place the old dll which was working and run RegAsm to unregister it. Then replace it with the new dll and run RegAsm to register it.

Thanks,
Anupam

#23. By Ron. Posted on 8/29/2006 8:09:41 PM
Very Helpful info - I wish I could have had this info in this concise form a few years ago.

I also know just what I need to, to get the job done here but thought I'd respond to some of the questions on how to deal with changes to the interop assembly if it's being used by multiple programs.

A few years ago, we created a .net interop assembly with a bunch of generic routines to be used as a foundation for all the programs we produce. Things like generic error handling, logging, simplified access to registry, etc. etc. This .net assembly is now used by dozens of other programs - some VB6 and some VB.NET. Every time we have any change to make in the interop assembly, we faced the same issues mentioned here - every existing program that uses it will need to be recompiled, in order to reference the new interop. Here's the steps we took - there very well could be better ways, but this has been working fine for us for years.

- In each project that references the interop, make sure the "Copy Local" setting of the reference is set to TRUE. This puts a copy of the latest interop into the bin folder

- When deploying the solution, copy everything from the bin folder to the target folder on the destination PC, including the interop assembly. Do the resasm on the interop assembly that is in that folder.

That results in each program having its own copy of the interop. Not at all efficient with disk space but that's a cheap resource any more and this completely avoids the issue of conflicts when a new version is made. The new interop is delivered only with any executables that need it, or have other changes to be deployed. No other executables are affected at all.

Hope this helps.

#24. By Ron. Posted on 8/29/2006 8:11:01 PM
Very Helpful info - I wish I could have had this info in this concise form a few years ago.

I also know just what I need to, to get the job done here but thought I'd respond to some of the questions on how to deal with changes to the interop assembly if it's being used by multiple programs.

A few years ago, we created a .net interop assembly with a bunch of generic routines to be used as a foundation for all the programs we produce. Things like generic error handling, logging, simplified access to registry, etc. etc. This .net assembly is now used by dozens of other programs - some VB6 and some VB.NET. Every time we have any change to make in the interop assembly, we faced the same issues mentioned here - every existing program that uses it will need to be recompiled, in order to reference the new interop. Here's the steps we took - there very well could be better ways, but this has been working fine for us for years.

- In each project that references the interop, make sure the "Copy Local" setting of the reference is set to TRUE. This puts a copy of the latest interop into the bin folder

- When deploying the solution, copy everything from the bin folder to the target folder on the destination PC, including the interop assembly. Do the resasm on the interop assembly that is in that folder.

That results in each program having its own copy of the interop. Not at all efficient with disk space but that's a cheap resource any more and this completely avoids the issue of conflicts when a new version is made. The new interop is delivered only with any executables that need it, or have other changes to be deployed. No other executables are affected at all.

Hope this helps.

#25. By Ron. Posted on 9/20/2006 7:18:04 PM
This is great. I have a problem though. My vb6 apps calls my .net app fine on my machine, but when I transfer the dlls to a users machine they will not work. I put vb6 on one machine to trace the error. I get it can't find the .net com dll

What are the steps to deploy this. Any help would be appreciated.

#26. By RonF. Posted on 9/20/2006 7:55:04 PM
We have a number of legacy VB6 apps and also VB.NET apps that make calls to our com assembly, each using its own copy as I described above.

Sounds like all you're missing is that you need to register the assembly. We have a batch file in each executable's main folder, that knows everything it needs to do to implement a new version of it. Here's the line from one of the batch files that does the registration (MaranathaCommon is the com assembly) :

%WinDir%\Microsoft.Net\Framework\v1.1.4322\REGASM ".\MARANATHACOMMON.DLL"

Note that the framework directory is specific to one version of .NET

Since we don't want to keep track of whether or not your assembly changed since the last time you deployed your executable, we just always deploy the latest assembly into the same target directory at the same time as the executable. Then we run the batch file for that executable (which does the REGASM), and then it will run on the target PC.

Of course, if this is the first time anything .net is running on the target PC, you would need to run dotnetfx.exe on it first, to install the framework.

In our case, we'll normally have a bunch of different user PC's that may be using a given program we're deploying and we don't want to have to go around to each PC to deploy it. So we actually put the executable (and .net assembly) in a certain directory on the customer's main server. We then have some additional stuff so that when the user double-clicks their icon for the program, it will automatically checks to see if a new version is available on the server. If so, all the right stuff gets copied to the user's PC, the latest .net assembly is registered, and the new version is started up. Bottom line is that we put the new app and assembly on the server and all the users just automatically get it without having to do anything further. If you've got a similar setup, you may also want to set up something like this.

#27. By Ron. Posted on 9/20/2006 7:56:55 PM
This is great. I have a problem though. My vb6 apps calls my .net app fine on my machine, but when I transfer the dlls to a users machine they will not work. I put vb6 on one machine to trace the error. I get it can't find the .net com dll

What are the steps to deploy this. Any help would be appreciated.

#28. By RonF. Posted on 9/20/2006 8:00:09 PM
We have a number of legacy VB6 apps and also VB.NET apps that make calls to our com assembly, each using its own copy as I described above.

Sounds like all you're missing is that you need to register the assembly. We have a batch file in each executable's main folder, that knows everything it needs to do to implement a new version of it. Here's the line from one of the batch files that does the registration (MaranathaCommon is the com assembly) :

%WinDir%\Microsoft.Net\Framework\v1.1.4322\REGASM ".\MARANATHACOMMON.DLL"

Note that the framework directory is specific to one version of .NET

Since we don't want to keep track of whether or not your assembly changed since the last time you deployed your executable, we just always deploy the latest assembly into the same target directory at the same time as the executable. Then we run the batch file for that executable (which does the REGASM), and then it will run on the target PC.

Of course, if this is the first time anything .net is running on the target PC, you would need to run dotnetfx.exe on it first, to install the framework.

In our case, we'll normally have a bunch of different user PC's that may be using a given program we're deploying and we don't want to have to go around to each PC to deploy it. So we actually put the executable (and .net assembly) in a certain directory on the customer's main server. We then have some additional stuff so that when the user double-clicks their icon for the program, it will automatically checks to see if a new version is available on the server. If so, all the right stuff gets copied to the user's PC, the latest .net assembly is registered, and the new version is started up. Bottom line is that we put the new app and assembly on the server and all the users just automatically get it without having to do anything further. If you've got a similar setup, you may also want to set up something like this.

#29. By RonF. Posted on 9/20/2006 8:00:16 PM
We have a number of legacy VB6 apps and also VB.NET apps that make calls to our com assembly, each using its own copy as I described above.

Sounds like all you're missing is that you need to register the assembly. We have a batch file in each executable's main folder, that knows everything it needs to do to implement a new version of it. Here's the line from one of the batch files that does the registration (MaranathaCommon is the com assembly) :

%WinDir%\Microsoft.Net\Framework\v1.1.4322\REGASM ".\MARANATHACOMMON.DLL"

Note that the framework directory is specific to one version of .NET

Since we don't want to keep track of whether or not your assembly changed since the last time you deployed your executable, we just always deploy the latest assembly into the same target directory at the same time as the executable. Then we run the batch file for that executable (which does the REGASM), and then it will run on the target PC.

Of course, if this is the first time anything .net is running on the target PC, you would need to run dotnetfx.exe on it first, to install the framework.

In our case, we'll normally have a bunch of different user PC's that may be using a given program we're deploying and we don't want to have to go around to each PC to deploy it. So we actually put the executable (and .net assembly) in a certain directory on the customer's main server. We then have some additional stuff so that when the user double-clicks their icon for the program, it will automatically checks to see if a new version is available on the server. If so, all the right stuff gets copied to the user's PC, the latest .net assembly is registered, and the new version is started up. Bottom line is that we put the new app and assembly on the server and all the users just automatically get it without having to do anything further. If you've got a similar setup, you may also want to set up something like this.

#30. By Ron. Posted on 9/20/2006 8:25:39 PM
This is great. I have a problem though. My vb6 apps calls my .net app fine on my machine, but when I transfer the dlls to a users machine they will not work. I put vb6 on one machine to trace the error. I get it can't find the .net com dll

What are the steps to deploy this. Any help would be appreciated.

#31. By Ron. Posted on 9/20/2006 8:26:37 PM
This is great. I have a problem though. My vb6 apps calls my .net app fine on my machine, but when I transfer the dlls to a users machine they will not work. I put vb6 on one machine to trace the error. I get it can't find the .net com dll

What are the steps to deploy this. Any help would be appreciated.

#32. By Ron. Posted on 9/20/2006 8:34:31 PM
I keep getting
Run-time error '-2147024894 (80070002)':

Automation error
The system cannot find the file specified.

I am using a file srv.tlb in my vb6.reference. I have the srv.tlb and srv.dll in the application directory.

I registered using regasm srv.dll /tlb:srv.tlb and received a messages that the file was registered.

#33. By RonF. Posted on 9/20/2006 8:59:24 PM
It sounds like you're taking the right steps. If you're confident you put everything in the right place, I can't think what could be going wrong.

Some things to consider ...

Our programs get run by the user double-clicking an icon. The icon uses the application directory as the current directory. Make sure your current dir is the application dir when you run it.

make sure you REGASM the srv.dll that's in the same dir

we don't use the /tlb switch you are using. I don't know what the switch does or if it might be impacting you.

if the app or srv.dll is using any other products (i.e Crystal) that need thier own libraries, those may need to be copied to the app dir and REGASM'd also.

If you have WISE installer or something similar for VB6 could try building a SETUP and running it on the client. That would ensure you get all the right 3rd party and other stuff there once, then srv.dll can be updated from there.

If none of that helps, I'm not sure what's wrong.

#34. By rama kant. Posted on 1/10/2007 2:52:08 PM
IN VS.NET it does not take sqlconnection method in C# webapoplication. but it takes webapplication which developed in vb
That is runtime error

#35. By mohhmed. Posted on 3/12/2007 10:04:15 AM
i want to know how to use dll vb6 file in asp.net 2005

#36. By sajit. Posted on 5/18/2007 8:46:08 AM
how to use a class developed in C#.net into a application made in VB.NET

#37. By Anonymous. Posted on 5/20/2007 4:28:29 AM
To #36. Simply create a separate project with your c# file and then reference that project and your class from the vb.net project.

#38. By sajit. Posted on 5/21/2007 5:39:42 AM
how to transfer a file from one computer to another through windows applz...

#39. By sajit. Posted on 5/30/2007 12:33:45 PM
how to find then number of comports on the host machine through .net on vs.net 2003.

#40. By Anonymous. Posted on 5/30/2007 3:41:27 PM
To #39. One easy thing to do is to loop through all 16 ports and try and open them. If you get an Invalid Port exception, that's your que that the port does not exist. There are better ways to detect available ports, but they involve API calls.

#41. By Massimo. Posted on 7/6/2007 2:43:17 PM
Great article, thanks

#42. By sajit. Posted on 7/11/2007 11:41:50 AM
In vb.net we have a provision of using WithEvent through which a method handles the variables events.For Eg:
Here I am generating an instance(ObjRs232_AVC) for serialport in VS2005.

Friend WithEvents ObjRs232_AVC As New SerialPort

With ObjRs232_AVC
.BaudRate = BaudRate
.DataBits = 8
.StopBits = StopBits.One
.Parity = Parity.None
.DtrEnable = True
.RtsEnable = True
.ReadTimeout = TimeOut
.WriteTimeout = TimeOut
End With

how do I use the instance events likewise in C# as it doesnt support WithEvent.

#43. By angelo. Posted on 10/4/2007 3:44:14 PM
Exceptional article. Helped me out instantly.

#44. By Anonymous. Posted on 10/6/2007 1:06:57 AM
Had Access 2007 whizzing out emails via VB.Net in no time.

#45. By kings. Posted on 10/24/2007 3:54:25 PM
hi.,

all works fine.,
but when i make the vb6.0 setup package and i installed into some other system which does not consist vb.net runtime evironment it brings the 429 error., and the dll file fails to register.,

thanks in advance

by
kings

#46. By Vishal. Posted on 11/13/2007 7:12:59 AM
I am working on a DLL for interop. DLL is developed in C# and will be consumed in VB6. However, I am facing an issue. One of the methods from the DLL accepts a string array. I want this array to be an optional parameter however, as C# does not support optional parameters I decided to pass it as "Nothing" from VB6 & checking it if it is null in C#. However, I guess that I can not do it that way since when I declared two distict methods to accepts different parameters it worked. Could you please tell me what I have assumed is correct or am i on wrong path somewhere?

#47. By Ishmael. Posted on 12/5/2007 3:21:59 AM
If you don't want to make all of your classes COM visible turn off "Make assembly COM-visible" in the project settings, or edit the assembly attribute ComVisible to "False" in AssemblyInfo.[vb|cs]. Then you can use the ComVisible attribute on each individual class that should be visible to COM.

You'd get something like this (in VB):
<ComVisible(True), _
ClassInterface(ClassInterfaceType.AutoDual), _
GuidAttribute("REPLACE-GUID-4d42-BF2A-B0F6618AB2ED")> _
Public Class ItemIndexException
...
End Class

#48. By Michael. Posted on 12/17/2007 8:33:03 PM
Hi,
I created a DLL which is developed in VB.Net and consumed it in VB6 to create an activeX control to process image. However, I met an issue. On my own computer, it works well. But on the other computers within the intranet, it doesn't work. I created .cab that contains erveything dependency, and installed .Net framework2.0 .
To compare, I created an activeX control1 in the same environment without consumed the VB.Net. Then it works well in any computers within the intranet.

Will you please tell me why? How can I deploy this activeX?

Thanks a lot!
Michael

#49. By Michael. Posted on 12/20/2007 6:17:52 PM
I solved the problem! The main reason that activeX control didn't appear is I used FM20.dll, after I removed this dll and change the scroll control, it works well. Another thing is I created a msi to install framework2.0.
That's it!
Merry Christmas to everyone!

Michael

#50. By Todd Beaulieu. Posted on 1/22/2008 9:20:30 PM
forum not working

#51. By Todd Beaulieu. Posted on 1/22/2008 9:25:05 PM
Does anyone know how to expose a summary (or help line) for a method or property?

We use the SUMMARY construct so that .net Visual Studio displays it as a tooltip. I want to do the same thing for the COM world. Is there an attribute I need to set for each public method? In VB, when using the object browser, you can see the sumamry line at the bottom. It's blank for my .net methods.

#52. By Todd Beaulieu. Posted on 1/23/2008 12:52:20 AM
I've been on this for a while now, and still have no solution. Of course, nothing's ever straightforward. I have an Interface defined to expose the methods and properties. I've discovered that I need to use the Description attribute as shown below in the interface, itself. Well, it works fine for methods, but not for properties. So, the first line below would work, but not the first. They compile, but I get no helpstring on the first.

[Description("Description one.")]
string ApplicationName { get; set; }

[Description("Description two.")]
string GetLegacyAdoConnectionString(string ApplicationName);

#53. By Gyldor. Posted on 1/27/2008 12:50:45 PM
@ Todd:
Try this

string ApplicationName {
[Description("Description one.")] get; set; }

This works for me.

/Gyldor

#54. By Gyldor. Posted on 1/27/2008 6:42:47 PM
@ Todd:
Try this

string ApplicationName {
[Description("Description one.")] get; set; }

This works for me.

/Gyldor

#55. By Todd Beaulieu. Posted on 1/30/2008 4:21:27 PM
Perfect. Thanks!

#56. By Selva. Posted on 2/7/2008 4:17:31 AM
I know Interface inheritance is not supported by COM interop. Can anyone please give me an alternative way to achieve this ?

#57. By Roberto. Posted on 8/31/2008 9:49:31 PM
Excellent article! Thanks!

#58. By Pratiksha. Posted on 9/24/2008 6:26:30 AM
Thanks
Nice articles...
it helped me a lot to clear doubt about what is exactly assembly is?..
Please send me more articles about the same if u have..

#59. By Mike Jo. Posted on 9/25/2008 12:28:25 PM
All the problems with recompiling the assemblies and the effects on the COM world are very well explained in the book 'Inside C#' by Tom Archer and Andrew Whitechapel (ISBN 3-86063-669-3).
They show, that using the Attribute [ClassInterface(ClassInterfaceType.AutoDual)] is NOT the best way...
And they explain, why.
Consider the differences between
[ClassInterface(ClassInterfaceType.AutoDual)]
and
[ClassInterface(ClassInterfaceType.None)]
and
[ClassInterface(ClassInterfaceType.AutoDispatch)]

Really good book.

Mike

#60. By PARTH SHAH. Posted on 10/7/2008 6:36:52 AM
THANK YOU VERY MUCH for your real time problem solving code on inter op,keep going on, great job,

#61. By jyoti. Posted on 2/12/2009 6:04:24 AM
This article is great

#62. By lee. Posted on 3/10/2009 10:38:20 AM
THANK YOU!!! you've been very helpfull

#63. By Glenn. Posted on 4/22/2009 12:28:35 AM
I create a simple c#.net class with the strong name, [ClassInterface(ClassInterfaceType.AutoDual)]
for the class. following the instruction above. Register dll and get the tlb file. Add reference to VB6 project.

However, I still have the problem of see the the object, in the VB6 Object browser. Please help.


Here is my object class:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;


namespace GZFun
{
[GuidAttribute("BA713700-522D-466e-8DD4-225884504678")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class GZSpeak
{

public GZSpeak()
{ }

public string Speak(string myname)
{
return "Hello " + myname;
}

public string Say()
{
return "ok";
}
}
}

#64. By raman. Posted on 5/4/2009 7:15:57 AM
hai how can i get the events
public interface IReader
{
event EventHandler TagReads;

int Range
{
get;
set;
}

string Initialize();
}
help me

#65. By Mike. Posted on 7/11/2009 4:10:25 AM
in regards to the user below

" It throws the "Runtime error '430' Class does not support Automation or does not support expected interface." Is there any way to solve this without recompiling the VB6 APP?

Thanks in advance.
Anupam Bhattacharya"

The answer is simple...

If you specify in your DLL to use for example

Public Function Swap (ByRef MyValue As Long) As String
Swap = CStr(MyValue)
End Function

Then you get that error because in .NET a Long is a true Long (64 bits)
but VB5/6 only understands As Integer as a unsigned integer of 31 bits

Check your variable declarations and make sure the content is compatible in VB5/6

#66. By CodingDude. Posted on 8/30/2009 11:52:46 PM
And if all else fails on the "Runtime error '430' Class does not support Automation or does not support expected interface." Ask yourself this: What am I doing on my development machine that is different than what the user - or my test platform virtual machine - is doing? Here's what I found... My development machine uses a substituted drive to get the drive letter that is the same as my end users and my virtual machine get by a mapped network drive. Using a substituted drive on my virtual machine fixes the problem so things work just like my development machine. I'm guessing that some screwy .NET 'security' feature causes the COM interop to get disabled when the dll is accessed across a network.

#67. By nagakeciks. Posted on 3/22/2010 12:18:43 PM
dude , thanks for this article , it really help me to solve my problem :-)