使用从VBScript可见的Visual Studio 2010创建COM对象从命令行运行 [英] Struggling creating a COM object with Visual Studio 2010 which is visible from VBScript run from the command line
问题描述
我在尝试在Visual Studio(2010)中创建一个COM对象,在 VB.NET ,它可以从命令行运行的 VBScript 程序中调用。我希望脚本能够做像... ...
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组件无法创建对象:'Hartley.Trips
ActiveX component can't create object:'Hartley.Trips
COM对象的核心定义是...
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
在Visual Studio中,项目参数将此指定为位于Hartley的根命名空间内,并且装配体信息具有使装配COM可见选中。我也生成了一个键,并添加到项目。
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.
当我构建解决方案,我必须这样做Visual Studio以管理员身份运行,因为它想写入注册表。查看注册表,我可以看到Hartley.Trips有注册表项。
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".
在互联网上搜索,有很多说明,我似乎已经跟着他们所有EXCEPT运行命令行工具。这里令人困惑的是,Visual Studio 2010似乎已经为我运行它们 - 并且给出了我可以找到的所有说明适用于早期版本的Visual Studio - 它似乎没有。我试图从Visual Studio命令行手动运行这些程序,但它似乎没有改变的事情。
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.
正如一个后记,我我想知道一个类中的嵌入式类是否是问题的一部分,我现在正在尝试构建一个集合,将类分离成独立的顶级类定义,每个作为自己的COM对象。当前具有带参数的 New
函数的类必须有一个 New
函数, code> Friend 函数来初始化它们(我不想让初始化函数可见,因为其他类都是只读结果)。
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).
推荐答案
编写一些VB.NET代码来测试你的COM组件。 CLR生成更好的错误消息。
Write some VB.NET code to test your COM component. The CLR generates much better error messages.
在64位操作系统上,你会遇到这样的问题。 IDE仅注册32位应用程序的COM组件。您将必须使用32位脚本解释器(c:\windows\syswow64\wscript.exe)或运行64位版本的Regasm.exe来注册组件的64位应用程序与/ codebase选项。
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.
避免嵌套类,COM没有等价的。声明COM可见声明的最自然方式是使用接口关键字。这里是你需要的结果类。
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.
这篇关于使用从VBScript可见的Visual Studio 2010创建COM对象从命令行运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!