I am struggling trying to build a COM object in Visual Studio (2010) in VB.NET which can be called from a VBScript program run from the command line. I want the script to be able to do something like ...
Option Explicit
Dim trips
Dim results
Set trips = CreateObject("Hartley.Trips")
Set results = trips.selecttrips(57,now())
wscript.echo results.count
However whatever I do, this script fails with:
ActiveX component can't create object:'Hartley.Trips
The core of the COM object definition is ...
<ComClass(Trips.ClassId, Trips.InterfaceId, Trips.EventsId)> _
Public Class Trips
#Region "COM GUIDs"
' 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 = "75184b72-31e3-4d62-add6-438230d17bc3"
Public Const InterfaceId As String = "c020fef9-0425-4200-a2b4-77931c0a6011"
Public Const EventsId As String = "4cf93b6e-f554-491b-94bd-5b02c3c6c586"
#End Region
Private Const connStr As String = "redacted"
Private dbConnection As SqlClient.SqlConnection
Private connectionInitialised As Boolean = False
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Public Sub New()
MyBase.New()
End Sub
Public Class Trip
Private myTripID As Integer
Private myIsComplete As Boolean
Private myStart As DateTime
Private myEnd As DateTime
Private myHasStarted As Boolean
Public Sub New(ByVal iTripID As Integer, ByVal bIsComplete As Boolean, _
ByVal dStart As DateTime, ByVal dEnd As DateTime, _
ByVal bHasStarted As Boolean)
myTripID = iTripID
myIsComplete = bIsComplete
myStart = dStart
myEnd = dEnd
myHasStarted = bHasStarted
End Sub
Public ReadOnly Property TripID() As Integer
Get
Return myTripID
End Get
End Property
Public ReadOnly Property Iscomplete() As Boolean
Get
Return myIsComplete
End Get
End Property
Public ReadOnly Property StartDate() As DateTime
Get
Return myStart
End Get
End Property
Public ReadOnly Property EndDate() As DateTime
Get
Return myEnd
End Get
End Property
Public ReadOnly Property hasStarted() As Boolean
Get
Return myHasStarted
End Get
End Property
End Class
Public Class Results
Private mySelectID As Integer
Private myTripDay As Date
Private myIsDriver As Boolean
Private myTripArray As List(Of Trip)
Public Sub New(ByVal iSelectID As Integer, dTripDay As Date, _
bIsDriver As Boolean, iCount As Integer)
myTripArray = New List(Of Trip)
mySelectID = iSelectID
myTripDay = dTripDay
myIsDriver = bIsDriver
End Sub
Public ReadOnly Property numTrip() As Integer
Get
Return myTripArray.Count
End Get
End Property
Public ReadOnly Property SelectID() As Integer
Get
Return mySelectID
End Get
End Property
Public ReadOnly Property ReportDate() As Date
Get
Return myTripDay
End Get
End Property
Public ReadOnly Property isDriver() As Boolean
Get
Return myIsDriver
End Get
End Property
Public ReadOnly Property TripArray() As Array
Get
Return myTripArray.ToArray
End Get
End Property
Public Sub Add(aTrip As Trip)
myTripArray.Add(aTrip)
End Sub
End Class
Public Function SelectTrips(SelectID As Integer, TripDay As Date, _
Optional isDriver As Boolean = False) As Results
Dim myTrip As Trip
Dim myEndDate As DateTime
Dim cmd As SqlClient.SqlCommand
Dim rs As SqlClient.SqlDataReader
If Not connectionInitialised Then 'If this is first attempt
dbConnection = New SqlClient.SqlConnection(connStr)
dbConnection.Open()
connectionInitialised = True
End If
'Test Only
cmd = New SqlClient.SqlCommand("SELECT * FROM xxx", dbConnection)
rs = cmd.ExecuteReader
Dim myTrips As New Results(SelectID, TripDay, isDriver, rs.FieldCount - 1)
While rs.Read
If IsDBNull(rs("Completed")) Then
myEndDate = Now()
Else
myEndDate = rs("completed")
End If
myTrip = New Trip(rs("runID"), _
IsDBNull(rs("completed")), _
rs("runDate"), _
myEndDate, _
rs("started"))
myTrips.Add(myTrip)
End While
Return (MyTrips)
End Function
End Class
In Visual Studio, the project parameters specify this as sitting within a root namespace of "Hartley" and the assembly information has the "Make Assembly COM visible" checked. I have also generated a key and added that to the project.
When I "build the solution", I have to do so with Visual Studio running as Administrator because it wants to write to the registry. Looking at the registry, I can see that there are registry entries for "Hartley.Trips".
Searching around the Internet, there are plenty of instructions to do this - and I appear to have followed them all EXCEPT running the command line tools. What is confusing here is that Visual Studio 2010 appears to have run them for me - and given all the instructions that I can find apply to earlier versions of Visual Studio - it appears they didn't. I have tried running these programs manually from Visual Studio Command Line, but it didn't seem to change things.
So now I am stuck. It doesn't work, the script is very unforthcoming about why it can't create the object, and I don't know how to move forward. So I am looking to advice as to what I might be doing wrong, how I can find out more about what is not working ,etc.
Just as a postscript, I am wondering if the embedded class within a class is part of the problem and am now trying to build an assembly which separates the classes into separate top level class definitions each as their own COM object. The classes which currently have a New
function with parameters will have to have a New
function without them and some form of Friend
function to initialise them (I don't want the initialize function visible as the other classes are read only results).