There is, as you've probably noticed, a number of approaches that are presented in the documentation as optional.
The following is a short description, or presentation, that showing you the correct way to expose VB.Net objects but it's limited to that without all the optional approaches.

The easiest way is to simply check the "Register for COM interop" checkbox on the project setting dialog box.
However, as you have noticed, doing so will only support late binding.
VB.Net will not automatically create the private dual interface fir a class that allows both early and late binding, you'll just have to do that yourself.
So the correct way is to write the interface and explicitly define it in the Class.
VB Code:
  1. Imports System.Runtime.InteropServices
  2. Public Interface _CallableFromCOM
  3.     Function SomeMethod(ByVal i As Integer) As Integer
  4.     '... all other methods
  5. End Interface
  6.  
  7. Public Class CallableFromCOM
  8.     Implements _CallableFromCOM 'implement the interface
  9.     Public Function SomeMethod(ByVal i As Integer) As Integer Implements _CallableFromCOM.SomeMethod
  10.         Return i
  11.     End Function
  12. End Class
Now, you have to instruct the VB.Net compiler that COM objects can use this component.
This is accomplished by setting the ComVisible attribute for the assembly (in the AssemblyInfo.vb file)
VB Code:
  1. <Assembly: ComVisible(True)>
  2. <Assembly: ClassInterface(ClassInterfaceType.None)>
You can, and should, also set the AssemblyDescription attribute to some value because this will appear in the Project Reference dialog box in VB 6.
VB Code:
  1. <Assembly: AssemblyDescription("Type in some description here")>
Best regards