Deploying Interop UserControls with RegFree-COM
One of the features of the latest Interop Forms Toolkit is the ability to develop UserControls in addition to Windows Forms. In a previous post, I showed how to create a simple Interop UserControl. I also have a video here on creating them, and one here on deploying a hybrid application using the standard Setup and Deployment project in Visual Studio 2005.
The benefit of creating Interop UserControl libraries is that you can deploy them using what's called RegFree-COM. This means that if you're deploying your VB6 applications on XP or higher OSs then you don't have to manually register the assemblies as COM components. Instead the operating system will "register" them for you on-the-fly at runtime. The COM component registry keys aren't physically created in the system's registry, keeping the system clean and allowing you to deploy COM components in a side-by-side fashion. (On your development machine the UserControls are still physically registered when you build the assemblies so that you can develop in Visual Basic 6.) This may be the way to go if you have a current setup program that you use for your VB6 application that was written with the Setup and Deployment Wizard.
Using RegFree-COM also means that you can take advantage of ClickOnce Deployment (since ClickOnce will not register COM components). The benefit of using ClickOnce deployment with your VB6 applications is that you can take advantage of a modern deployment architecture which includes automatic updates and deploying from a central web server.
What the toolkit does to enable RegFree-COM is that it gets you started with a private assembly manifest for the UserControls. When you select the Interop User Control Library template when creating a new project in Visual Studio, a InteropUserControl.manifest file is created for you along with the rest of the files. Inside this private assembly manifest is XML describing the controls inside your library. By default, the name of the UserControl that is created when you first create your library is InteropUserControl with a generated class id. This information is described in the <clrClass> node.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- You don't need to worry about anything in this file unless you're
using registration-free COM.
There should be an appropriate <clrclass> section for every InteropUserControl
defined in the project -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="InteropUserControlLibrary1"
version="1.0.0.0" />
<clrClass
clsid="{7395b9d9-da47-4262-80e7-b4eed8768d09}"
progid="InteropUserControlLibrary1.InteropUserControl"
threadingModel="Both"
name="InteropUserControlLibrary1.InteropUserControl" >
</clrClass>
</assembly>
When you change the name of InteropUserControl or the assembly name you need to also update the contents of this file as well. If you add more UserControls to your library you'll need to create a new <clrClass> node with that control's information. You can find the class ID by looking in the Interop UserControl's VB6 Interop Code Region and then in the COM Registration Region:
<ComClass(InteropUserControl.ClassId, InteropUserControl.InterfaceId, InteropUserControl.EventsId)> _
Public Class InteropUserControl
#Region "VB6 Interop Code"
#If COM_INTEROP_ENABLED Then
#Region "COM Registration"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "7395b9d9-da47-4262-80e7-b4eed8768d09"
Public Const InterfaceId As String = "739b2e94-6bdf-4417-beff-25a457e6df8f"
Public Const EventsId As String = "65029223-ea4e-4cb0-9462-27edbbf985fa"
'These routines perform the additional COM registration needed by ActiveX controls
<EditorBrowsable(EditorBrowsableState.Never)> _
<ComRegisterFunction()> _
Private Shared Sub Register(ByVal t As Type)
ComRegistration.RegisterControl(t)
End Sub
<EditorBrowsable(EditorBrowsableState.Never)> _
<ComUnregisterFunction()> _
Private Shared Sub Unregister(ByVal t As Type)
ComRegistration.UnregisterControl(t)
End Sub
#End Region
As an example, I created an Interop UserControl library called ARegFreeComLibrary. In this library I created two UserControls, one called CustomerDetails and one called OrderDetails so my manifest looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- You don't need to worry about anything in this file unless you're
using registration-free COM.
There should be an appropriate <clrclass> section for every InteropUserControl
defined in the project -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="ARegFreeComLibrary"
version="1.0.0.0" />
<clrClass
clsid="{7395b9d9-da47-4262-80e7-b4eed8768d09}"
progid="ARegFreeComLibrary.CustomerDetails"
threadingModel="Both"
name="ARegFreeComLibrary.CustomerDetails" >
</clrClass>
<clrClass
clsid="{bb58ec27-8668-49e0-90cf-3542075654a9}"
progid="ARegFreeComLibrary.OrderDetails"
threadingModel="Both"
name="ARegFreeComLibrary.OrderDetails" >
</clrClass>
</assembly>
The other manifest file you need to have for RegFree-COM to work is called a client manifest file and this needs to be manually created and then placed in the application's directory. This would be where your VB6 application is also deployed. The contents of this manifest include the name and version of the VB6 application and then the Interop UserControl assembly information:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32" name="MyVB6App" version="1.0.0.0" processorArchitecture="x86" />
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="ARegFreeComLibrary" version="1.0.0.0" />
</dependentAssembly>
</dependency>
</assembly>
Place this into a file named after your VB6 application with an extension of .manifest, in my case, MyVB6App.exe.manifest, and pop it into the same folder as the exe. It's important that you name the client manifest file the same as your VB6 application + exe.manifest extension otherwise RegFree-COM will not work. To manage the file easier, from the Project menu in Visual Studio I selected Add New Item and selected Text File to create the manifest. In the properties window I then set the "Build Action" to Content and "Copy to Output Directory" to Copy Always. I find it easier to keep track of it this way.
Next thing to do is copy your VB6 app into the release folder under \bin\Release\ and any supporting files. In my example I am using an Access mdb, but I've added this file to the library I created as a local data file so it'll get built into the Release folder as well. Note, when working with local data files you'll need to also set the Copy to Output Directory appropriately like I explain in this post. Now what the client is going to need in order to run all this is:
1) The .NET Framework 2.0
2) The VB runtime (comes with XP and up OS's) and any OCX's or other referenced components/data you use in your VB6 application
4) Your Interop UserControl assembly and any .config files and the client .exe.manifest
3) The Microsoft.InteropFormTools assembly
When creating Interop UserControls you can remove the reference to the Microsoft.InteropFormTools assembly if you aren't using it -- just remove the reference and then comment out the code at the top of the ActiveXControlHelpers.vb file. However, if you are using it then it's easy to get ClickOnce to install this as a prerequisite (just like the Framework 2.0) because the toolkit now comes with a redistributable package. (You'll see this in a minute.)
You can also add your VB6 application to the project which, in my example, includes the MyVB6App.exe and the Msdatgrd.ocx (the VB6 DataGrid I'm using). Adding them as content files and marking them to always copy to output directory will put them into the \bin\Release folder every time you build the UserControl project. You can also specify the class library project location when you make your VB6 EXE, that way all the files you need to deploy come out in one place, the \bin\Release. If you're deploying this to a machine that already has the VB6 Runtime and the .NET 2.0 Framework then you can just xcopy deploy the Release to the client machine and run.
Using ClickOnce Deployment is optional but for this example we'll set it up this way. Since you can't use ClickOnce to deploy a class library project, instead of adding the VB6 application files to the class library project, we'll add them to a new Windows Forms application instead. So I just added a simple Windows Application to my solution called InteropAppLauncher. Once you have this project created you can then add a reference to your Interop UserControl Assembly and select "Add Existing Item" on the VB6 application files as well as the client manifest file (MyVB6App.exe.manifest). In my case, since I'm using an Access.mdb file I moved this file into the launcher application as well so it can be deployed.
Next thing to do is to write a couple lines of code in the launcher's form so that it will launch your VB6 application right away and close.
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Process.Start("MyVB6App.exe")
Me.Close()
End Sub
End Class
Now we're ready to publish with ClickOnce. Select My Project and go to the Publish Tab and enter the deployment location. I just set up a local file share, but you can easily publish to a web server as well. Select the Prerequisites button and you'll see the redistributable packages available. You'll definitely need .NET Framework 2.0 but you can decide whether you need the Interop Forms Toolkit 2.0 package depending on if you left the reference to Microsoft.InteropFormTools assembly. If you did, then you'll need to include this package.
Once you've set all that up you can click the Publish Now button or select Publish from the build menu. Now you have a ClickOnce setup that will launch your VB6 application which uses RegFree-COM in order to create a friction free deployment for your Interop User Controls. I've included the sample I built for your reference. To try out RegFree-COM, just compile the solution and then run the InteropAppLauncher.exe in the \ARegFreeComLibrary\InteropAppLauncher\bin\Release\ folder. For more info on setting up ClickOnce to deploy Visual Basic 6 applications, check out Scott's article on MSDN and this LabCast to try it out yourself right now. By the way, you can use ClickOnce for deploying Visual FoxPro applications as well.
Anyone developing Visual Basic 6 (or Visual FoxPro) applications should consider taking advantage of the Interop Forms Toolkit 2.0, ClickOnce Deployment, and RegFree-COM to bring .NET's modern capabilities to your users in an easy-to-manage way.
In the next interop post I'll talk about setting up debugging across Visual Studio and VB6. (UPDATE: Here's how to debug.)
Comments
Anonymous
July 02, 2007
Excellent article! Additionally, users might want to check out this post which explains in more detail some other aspects of deployment (like how to get any prereqs installed and what to do if you cannot deploy your app with Clickonce, etc...) http://blogs.msdn.com/vbteam/archive/2007/06/04/deploying-applications-with-the-interopforms-2-0-toolkit.aspx It's very cool to have the ability to deploy VB6 apps using ClickOnce though!Anonymous
July 10, 2007
great article.Anonymous
September 04, 2007
The article seems great, and works on my development machine. However upon deploying to clients I receive an automation error "overlapping i/o" when attempting to show the .NET control. The program then crashes. I've tried manually registering the control but this doesn't help. How can this automation error be fixed?Anonymous
September 07, 2007
The comment has been removedAnonymous
October 07, 2007
Hi This article is very useful. SrinivasAnonymous
October 15, 2007
The comment has been removedAnonymous
October 17, 2007
Hi Injuninus, To get the WCF settings to be read properly all you need to do is to rename the .dll.config file that is generated for your UserControl library to the same name as your VB6 application and deploy it in the same folder. For instance MyVb6App.exe MyVb6App.exe.config <--- rename to this from MyLibrary.dll.config and place in same directory I'll be writing a blog post on this as well as how to read the My.Settings so keep an eye out. HTH, -BAnonymous
March 24, 2008
The comment has been removedAnonymous
March 31, 2008
Is it possible to deploy Interop UserControls with RegFree-COM using the same method being applied for VB6 apps with Visual FoxPro? I've followed the steps listed in your article, but get the following error message when launching my VFP 9 app: "The application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem." The client manifest file is causing this error display.Anonymous
April 02, 2008
The comment has been removedAnonymous
May 14, 2008
The comment has been removedAnonymous
May 20, 2008
I am getting a "reference in the manifest does not match the identity of the downloaded assembly" error at deployment. So, I took your sample code and published. And, I'm getting the same error. Any idea what I'm missing?Anonymous
May 23, 2008
I tested VB6 application launcher for ClickOnce deployment. It works with VB6 and C++ MFC based ocx and dll. Manifest files were automatically created by VS 2005. But I could not make it work if VB6 application has dependency C++ ATL based dll. If there something in manifest file that I need to change manually? Any aideas? ThanksAnonymous
June 03, 2008
Hi, I have created a number of vb.net 2008 Interop user controls. The controls work on the development machine but I can not get them to work on the client machines. I followed the steps mentioned in "How to: deploy hybrid application" tutorial by Beth Massi, but it does not create the project.msi file. It does create a setup.exe file but when I try to run it complains about the .msi file missing. I am posting here because I did not get any answers from the forums. Please help me I am desperate, regards NasirAnonymous
June 09, 2008
先週、 ポルトガルのリスボン と イギリスのバーミンガム での Visual Studio 2008 の発表イベントで講演する機会がありました。どちらも熱狂的な雰囲気に包まれていたのは、今回の VisualAnonymous
January 28, 2009
The comment has been removedAnonymous
March 12, 2009
Not much of a relief, but me too I am unable to use a InteropControl developed on a Vista/VS2008 machine, on any other machine with only VB6 installed. How too, thanks.Anonymous
May 13, 2009
Hi, I have worked with Interop User Controls and RegFree ok but now I need to put a third part assembly at my user control and I have a problem when I load the VB6 form with the user control unless I register it with regasm...Is there a way to use these assemblies at my User Control without register then ? Regards.Anonymous
June 05, 2009
I’ve been having a look at some of the samples on the Visual Basic Resource Center to see what’s possibleAnonymous
February 03, 2010
Hi, I need some help please. I've created a Interop User Control (IUC) wich is hosted on a VB6 form. My development machine has VB6, VS2005, Microsoft Interop Forms Toolkit 2.0, running on Win7 Ultimate 64-bit. The IUC allows me to consume a Web service and download a RecordSet containing a Image (and some other strings). In my VB6 form code, I have an Image control named Image1. I try to set Image1.DataSource = myRS, where myRS is an object of type ADODB.RecordSet. I've also managed to deploy this hybrid application using ClickOnce and Reg-Free COM. And here's the known story: "The application works fine in my development machine", but when it's installed in a new machine (XP SP3), it loads ok, but fails in displaying my image in Image1 control. The error says "Run-time error '713': Class not registered. Looking for object with CLSID:{59245250-7A2F-11D0-9482-00A0C9110ED}". I've searched for it on Internet, and found it is the CLSID of Microsoft Data Binding Collection (MSBIND.DLL). The WinXP SP3 machine does not have MSBIND.DLL. What can I do to correctly deploy my application using MS Data Bind with Registration-Free COM?Anonymous
March 19, 2010
Hi, I followed the guidelines in your article carefully but I am getting the following error during the setup process:
- Reference in the manifest does not match the identity of the downloaded assembly MyInteropControl.dll. I am pretty sure that I have the assembly identity and class ID correctly referenced in my client manifest and private assembly manifest but I think this error is coming from the manifest for the VB.NET launcher application, which is generated when I compile the solution. What am I doing wrong?
Anonymous
March 23, 2010
I've had the same problem with this error: Reference in the manifest does not match the identity of the downloaded assembly MyInteropControl.dll. Have tried with my project to include the .net control as file content and remove it as a reference within the InteropAppLauncher project. The error does not happen now but I need to verify that my VB app now uses the shipped regfree .net control.Anonymous
March 24, 2010
The comment has been removedAnonymous
April 14, 2010
Hi, I'm having real trouble deploying an interop control which is dynamically loaded inside a vb6 ocx, which is in turn loaded on to a vb6 exe. Should I create an .ocx.manifest to sit next to the vb6 ocx? Or should I create a .exe.manifest to sit next to the vb6 exe. I've tried using regasm control.dll /tlb filename.tlb /codebase. but when the vb6 ocx runs the control.add method I get error number 743 Unable to create or activate a new instance of ... However, if I run through the code in debug from .net into vb6, and then stop debugging, I can run the exe without error. Any clues?Anonymous
April 15, 2010
Hi Paul, I'm not familiar with that issue. Please ask the question in the Interop forum. There are members of the interop team there answering questions (as well as the rest of the community). http://social.msdn.microsoft.com/forums/en-US/vbinterop/threads/ -BAnonymous
May 07, 2013
is it possible to call a regfree-com across a network -- I currently have one but it only works on the server in a peer-to-peer network. The shortcut on the server is c:myprogrammyprogram.exe -- which calls the regfree com correctly The shortcut on a station is \servercmyprogrammyprogram.exe -- which will not call the refree com The myprogram.exe is vb6, while the com is vb2010