努力使用 Visual Studio 2010 创建 COM 对象,该对象可从命令行运行的 VBScript 中看到
我正在努力尝试在 VB.NET 中的 Visual Studio (2010) 中构建 COM 对象可以从命令行运行的 VBScript 程序调用。我希望脚本能够执行类似的操作...
Option Explicit
Dim trips
Dim results
Set trips = CreateObject("Hartley.Trips")
Set results = trips.selecttrips(57,now())
wscript.echo results.count
但是无论我做什么,该脚本都会失败:
ActiveX 组件无法创建对象:'Hartley.Trips
COM 对象定义的核心是...
<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
在 Visual Studio 中,项目参数将其指定为位于“Hartley”的根命名空间内,并且程序集信息具有“Make程序集 COM 可见”已选中。我还生成了一个密钥并将其添加到项目中。
当我“构建解决方案”时,我必须以管理员身份运行 Visual Studio 来执行此操作,因为它想要写入注册表。查看注册表,我可以看到有“Hartley.Trips”的注册表项。
在互联网上搜索,有很多说明可以做到这一点 - 除了运行命令行工具之外,我似乎已经遵循了所有说明。这里令人困惑的是,Visual Studio 2010 似乎已经为我运行了它们 - 并且考虑到我能找到的所有说明都适用于 Visual Studio 的早期版本 - 看来它们没有。我尝试从 Visual Studio 命令行手动运行这些程序,但它似乎没有改变任何事情。
所以现在我被困住了。它不起作用,脚本对于为什么无法创建对象非常不明确,我不知道如何继续前进。因此,我正在寻求建议,了解我可能做错了什么,如何找到更多有关不起作用的信息等。
作为后记,我想知道类中的嵌入类是否是问题的一部分,现在我正在尝试构建一个程序集,将这些类分成单独的顶级类定义,每个类定义作为它们自己的 COM 对象。当前具有带参数的 New
函数的类必须具有不带参数的 New
函数以及某种形式的 Friend
函数来初始化它们(我不希望初始化函数可见,因为其他类是只读结果)。
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).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
编写一些 VB.NET 代码来测试您的 COM 组件。 CLR 生成更好的错误消息。
在 64 位操作系统上你会遇到这样的问题。 IDE 仅为 32 位应用程序注册 COM 组件。您必须使用 32 位脚本解释器 (c:\windows\syswow64\wscript.exe) 或运行 64 位版本的 Regasm.exe,以通过 /codebase 选项注册 64 位应用程序的组件。
避免嵌套类,COM 没有相应的类。声明 COM 可见声明的最自然方法是使用 Interface 关键字。这正是您在 Results 类中所需要的。
Write some VB.NET code to test your COM component. The CLR generates much better error messages.
You will have trouble like this on a 64-bit operating system. The IDE only registers the COM component for 32-bit apps. You'll have to use the 32-bit script interpreter (c:\windows\syswow64\wscript.exe) or run the 64-bit version of Regasm.exe to register the component for 64-bit apps with the /codebase option.
Avoid nested classes, COM has no equivalent for that. The most natural way to declare a COM visible declaration is with the Interface keyword. Exactly what you need here for the Results class.