Click here to Skip to main content
15,884,628 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Question: Does anyone know why I can get the events to fire between a .net usercontrol and a VB6 Form hosting the user control through VBControlExtender in a reg free com environment?

The VB6 end does not seem to recognise the .net user control as an event source and is consequently not calling Advise.

I am for the most part successfully running a vb6 exe with .net components using Com interop without COM registration using sxs reg free COM manifests.

My VB6 exe uses many vb activex controls without registration with no problems, however I can only get .net user controls hosted in the VB6 exe using VBControlExtender to work one way, i.e. the control events do not fire.

If I register my dll as follows regasm mydotneusercontrol.dll the events fail to fire

If I register my dll with a type library as follow regasm mydotneusercontrol.dll /tlb:mydotneusercontrol.tlb The events fire

If I use a sxs manifest and don't register mydotneusercontrol.dll my user control is hosted in the vb6 form but again the events fail to fire


My manifest is as follows:
HTML
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestversion="1.0">
	<assemblyidentity>
		name="mydotneusercontrol" 
		version="6.8.0.0" 
		processorArchitecture="msil">
	</assemblyidentity>
	<clrclass>
		clsid="{123456AF-B555-4c06-909C-CDE19C66AD30}" 
		progid="mydotneusercontrol.myusercontrol" 
		threadingModel="Both" 
		name="mydotneusercontrol.myusercontrol" 
		runtimeVersion="">
	</clrclass>
	<file name="myusercontrol.dll" hashalg="SHA1"></file>
</assembly>


Note: I tried adding tlbid to the manifest but that made not difference

This was generated using mt as follows:
mt -managedassemblyname:myusercontrol.dll -nodependency -out:myusercontrol.dll.manifest

Then embedded in the dll as follows:
mt -manifest myusercontrol.dll.manifest -outputresource:myusercontrol.dll;#1


The .net control is as follows
C#
[assembly: Guid("E123786C-5EF5-4149-A37B-86303971F72C")]
[assembly: AssemblyVersion("6.8.0.0")]
[assembly: TypeLibVersion(1, 0)]

[ComVisible(true), Guid(myuserControl.EventsId), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface __myuserControlEvents {
	[DispId(1)]
        void myEvent();
}

[ComVisible(true)]
[Guid(container.ClassId), ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(__myuserControlEvents))]
[ProgId("mydotneusercontrol.myusercontrol")]
[ComClass(myuserControl.ClassId, myuserControl.InterfaceId, myuserControl.EventsId)]
  public partial class myuserControl.: UserControl, IMyInterface {
   // ...
  }


myuserControl.EventId ClassId InterfaceID are constants defining guids

At the VB6 end the object is created and used in a form as follows
VB
Private WithEvents EntryControl As VBControlExtender

Private Sub Form_Load()
  Set EntryControl = Me.Controls.Add("mydotneusercontrol.myusercontrol", "Entry")
End Sub

Private Sub EntryControl_ObjectEvent(Info As EventInfo)
  Select Case Info.Name
    
    Case "myEvent"
    ' this is only called when the assembly and its type lib are register
  End Select
End Sub 
Posted
Comments
Sean Defoe 13-Jul-12 8:28am    
I am trying to access a VB.NET DLL (.NET FX 4.0) from a VB6 client in a reg-free scenario.

I tried to follow the example from http://msdn.microsoft.com/en-us/library/ms973915.aspx, but with no success. I downloaded (link in the article) the sources and compiled, no success (error message: Run-time error '-2146234341 (8013101b)': Automation error"). Running from VB6 IDE using registered VB.NET DLL works.

I tried other examples where the .NET DLL is created as a COM Class (using "COM Class" template from VS2010), with manifest for referenced DLL embedded or not, but nothing worked for me.

Can you, please, help me by providing some simple source code example with manifests of VB.NET DLL (.NET FX v4) used in VB6 client in reg-free scenario?

Thanks much in advance.
ARopo 23-Jul-12 11:35am    
what is it you are trying to access from vb6? the solution in this post is for hosting a .net user control on a vb6 form.

Sounds like either your manifest is not embedded or is not correct - use mt.exe to extract and check the manifest from your .net dll. Also try using sxstrace to diagnose the problem. You also need a manifest for the VB6 exe that refers to the .net dlls as dependencies.
Sean Defoe 23-Jul-12 17:00pm    
It is a VB.NET v4.0 DLL with just two simple functions.
I posted here because I found somebody here who mention he is able to reference something in .NET from VB6 app.

DLL manifest is embedded OK and I have manifest for VB6 app too, thanks for the tips.
I have asked on another forum and I got this answer, that helped (I hope I can post link to similar forum): http://stackoverflow.com/a/11473272/1523031
I apologize for not removing the comment after I got answer over there.

1 solution

The problem was related to the type library, inserting the following lines int0 the manifest fixed the problem

HTML
<file name="myusercontrol.tlb">
<typelib tlbid="{F121823D-5EF1-4149-A37B-86303971F72C}">
         version="1.0" helpdir="" flags="HASDISKIMAGE"></typelib>
</file>


Also have to reference the typelib from the clrclass section, so the full manifest is as follows

HTML
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestversion="1.0">
	<assemblyidentity>
		name="mydotneusercontrol" 
		version="6.8.0.0" 
		processorArchitecture="msil">
	</assemblyidentity>
	<clrclass>
		clsid="{123456AF-B555-4c06-909C-CDE19C66AD30}" 
		progid="mydotneusercontrol.myusercontrol" 
                tlbid="{F121823D-5EF1-4149-A37B-86303971F72C}"
		threadingModel="Both" 
		name="mydotneusercontrol.myusercontrol" 
		runtimeVersion="">
	</clrclass>
	<file name="myusercontrol.dll" hashalg="SHA1"></file>
        <file name="myusercontrol.tlb">
        <typelib tlbid="{F121823D-5EF1-4149-A37B-86303971F72C}">
                version="1.0" helpdir="" flags="HASDISKIMAGE"></typelib>
        </file>
</assembly>


I wanted to automate the generation of this manifest file, so I use mt to generate a file based on the type lib then use it a again to generate a manifest based on the dll then I wrote a console application to merge the relevant parts of the two manifests together before merging into the dll. The process is as follows:

rem delete old manifests
del %dllmanifest% -Y
del %tlbmanifest% -Y
del %mergedmanifest% -Y

rem generate a dll manifest
mt -managedassemblyname:%dllname% -nodependency -out:%dllmanifest%

rem generate a tlb manifest
mt -tlb:b:\%tlbname% -dll:%dllname% -out:%tlbmanifest%

rem merge the typelib information into the dll information
MergeTLB %tlbmanifest% %dllmanifest% %mergedmanifest%

rem embbed the resulting manifest into the dll
mt -manifest %mergedmanifest% -outputresource:%dllname%;#1


The code for the MergeTLB Application is as follows:
C#
class Program {
    static void Main(string[] args) {
      if (args.Length == 3) {
        // get the parameters
        string tlbManifest = args[0];
        string dllManifest = args[1];
        string outManifest = args[2];

        // load in tlb document
        XmlDocument tlbXml = new XmlDocument();
        tlbXml.Load(tlbManifest);

        // the file node typelib
        XmlNode tlbFileNode = null;
        XmlAttribute tlbidAttrib = null;
        XmlNode tlbNode = FindNode(tlbXml, "typelib");
        // if we found it
        if (tlbNode != null) {
          // get the parent node
          tlbFileNode = tlbNode.ParentNode;
          // remove every thing but the tlb node
          for (int i = tlbFileNode.ChildNodes.Count - 1; i >= 0; i--) {
            if (tlbFileNode.ChildNodes[i] != tlbNode)
              // remove it
              tlbFileNode.RemoveChild(tlbFileNode.ChildNodes[i]);
          }
          // ensure that file name is correct
          XmlAttribute nameAttrib = tlbFileNode.Attributes["name"];
          nameAttrib.Value = nameAttrib.Value.Replace(".dll", ".tlb");
          // get the type lib id attribute
          tlbidAttrib = tlbNode.Attributes["tlbid"];
          // remove from this document
          tlbFileNode.ParentNode.RemoveChild(tlbFileNode);
        }

        // load in dll document
        XmlDocument dllDocument = new XmlDocument();
        dllDocument.Load(dllManifest);
        // find the clrclass node
        XmlNode clrNode = FindNode(dllDocument, "clrClass");
        // if found
        if (clrNode != null && tlbidAttrib != null) {
          
          // add the tlblib id
          clrNode.Attributes.Append((XmlAttribute) dllDocument.ImportNode(tlbidAttrib, false));
          // add the tlb file node to the the dll document
          clrNode.ParentNode.AppendChild(dllDocument.ImportNode(tlbFileNode, true));
        }

        // write out the merged file
        dllDocument.Save(outManifest);
      } else {
        Console.WriteLine("MergeTLB tlbManifest dllmanifest outmanifest");
      }

    }

    private static XmlNode FindNode(XmlDocument tlbXml, string nodeName) {
      XmlNamespaceManager xsm = new XmlNamespaceManager(tlbXml.NameTable);
      xsm.AddNamespace("x", "urn:schemas-microsoft-com:asm.v1");
      XmlNode tlbNode = tlbXml.SelectSingleNode("descendant::x:" + nodeName, xsm);
      return tlbNode;
    }
  }
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900