Deploying Interop UserControls with RegFree-COM

Deploying Interop UserControls with RegFree-COM

Rate This
  • Comments 26

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

Attachment: ARegFreeComLibrary.zip
Leave a Comment
  • Please add 6 and 6 and type the answer here:
  • Post
  • I have created an interop control that displays the MS ReportViewer control. This works well in our VB6 application on the developer machine. However I've not been able to get it to work in our application on another machine.

    The VB6 application calls various ActiveX DLLs, one of which has a form which hosts the .NET interop control. We have successfully used RegFree COM to deploy the application for a number of years (using App.exe.manifest file), so no libraries are registered on the target machine.

    I have managed to get a test application to run hosting the interop control directly on one of its own forms and using a manifest file with a dependency on the interop assembly. However, not matter how I tweak the application manifest of our real application, or even if I add a manifest file for the ActiveX DLL, I've not been able to get this to work.

    The specific error I'm getting is "component or one of its dependencies is not correctly registered a file is missing or invalid".

    Could someone please let me know if placing an interop control on an ActiveX DLL form is supported and how I should setup the manifest in this case.

    I really do not want to have to go to full registration of the components as we have been very successfully distributing the application by simple xcopy (internal environment) using regfree com.

    Thanks very much.

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

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

  • I’ve been having a look at some of the samples on the Visual Basic Resource Center to see what’s possible

  • 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?

  • 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?

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

  • Hi Guys,

    This usually indicates an error in the manifest file. I would pose the question and the manifest to the Interop forums, there are members of the interop team there answering questions (as well as the rest of the community) so it can be more responsive than me alone.

    http://social.msdn.microsoft.com/forums/en-US/vbinterop/threads/

    Sorry I can't be more of a help with this specific problem. Editing manifests is indeed error prone.

  • 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?

  • 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/

    -B

  • 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:\myprogram\myprogram.exe -- which calls the regfree com correctly

    The shortcut on a station is \\server\c\myprogram\myprogram.exe -- which will not call the refree com

    The myprogram.exe is vb6, while the com is vb2010

Page 2 of 2 (26 items) 12