简体   繁体   English

VBA-使用.NET类库

[英]VBA - Using .NET class library

We have a custom class library that has been built from the ground up that performs a variety of functions that are required for the business model in place. 我们有一个自定义类库,该类库是从头开始构建的,可以执行适当的业务模型所需的各种功能。 We also use VBA to automate some data insertion from standard Microsoft packages and from SolidWorks. 我们还使用VBA自动从标准Microsoft软件包和SolidWorks中插入一些数据。

To date we have basically re-written the code in the VBA application macro's, but now are moving to include the class library into the VBA references. 迄今为止,我们基本上已经在VBA应用程序宏中重新编写了代码,但是现在正在将类库包含到VBA引用中。 We've registered the class library for COM interop, and made sure that it is COM visible. 我们已经为COM互操作注册了类库,并确保它对COM可见。 The file is referencable, we have added the <ClassInterface(ClassInterfaceType.AutoDual)> _ tag above each of the Public Classes, so that intellisense 'works'. 该文件是可引用的,我们在每个Public <ClassInterface(ClassInterfaceType.AutoDual)> _上方添加了<ClassInterface(ClassInterfaceType.AutoDual)> _标记,以便智能操作。

With that said, the problem now arises - when we reference the class library, for this instance let's call it Test_Object , it is picked up and seems to work just fine. 话虽如此,现在出现了问题-当我们引用类库时,对于该实例,我们将其Test_Object ,它将被拾取并且似乎可以正常工作。 So we go ahead and try a small sample to make sure it's using the public functions and returning expected values: 因此,我们继续尝试一个小示例,以确保它正在使用公共函数并返回期望值:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Dim test As New Test_Object.Formatting
    Dim t As String
    t = test.extractNumber("abc12g3y45")
    Target.Value = t
End Sub

This works as expected, returning 12345 in the selected cell/s. 这将按预期方式工作,在选定的单元中返回12345。

However, when I try a different class, following the exact same procedure, I get an error ( Object variable or With block variable not set ). 但是,当我尝试另一个类时,按照完全相同的步骤进行操作,则会收到错误消息( Object variable or With block variable not set )。 Code is as follows: 代码如下:

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Dim test As New Test_Object.SQLCalls
    Dim t As String
    t = test.SQLNumber("SELECT TOP 1 ID from testdb.dbo.TESTTABLE") 'where the string literal in the parentheses is a parameter that is passed.
    Target.Value = t
End Sub

This fails on the t = test.SQLNumber line. 这在t = test.SQLNumber行上失败。 It also fails on another function within that SQLCalls class, a function that returns the date in SQL format (so it is not anything to do with the connection to the database). 它还在该SQLCalls类中的另一个函数上失败,该函数以SQL格式返回日期(因此,与数据库连接无关)。

Can anyone assist in what could be causing this error? 任何人都可以协助导致此错误的原因吗? I've googled for hours to no avail, and am willing to try whatever it takes to get this working. 我已经搜索了几个小时无济于事,并且愿意尝试一切以使其正常工作。

Cheers. 干杯。

EDIT: (added in the .SQLNumber() method) 编辑:(在.SQLNumber()方法中添加)

Function SQLNumber(query As String) As Double
    Dim tno As Double
        Try
            Using SQLConnection As SqlConnection = New SqlConnection(Connection_String_Current)
                SQLConnection.Open()
                SQLCommand = New SqlCommand(query, SQLConnection)
                tno = SQLCommand.ExecuteScalar
            End Using
        Catch ex As System.Exception
            MsgBox(ex.Message)
        End Try
    Return tno
End Function

For comparison, the extractNumber() method: 为了进行比较, extractNumber()方法:

Function extractNumber(extstr As String) As Double
    Dim i As Integer = 1
    Dim tempstr As String
    Dim extno As String = ""
    Do Until i > Len(extstr)
        tempstr = Mid(extstr, i, 1)
        If tempstr = "0" Or tempstr = "1" Or tempstr = "2" Or tempstr = "3" Or tempstr = "4" Or tempstr = "5" Or tempstr = "6" Or tempstr = "7" Or tempstr = "8" Or tempstr = "9" Or tempstr = "." Then
            extno = extno & tempstr
        End If
        i = i + 1
    Loop
    If IsNumeric(extno) Then
        Return CDbl(extno)
    Else
        Return 0
    End If
End Function

With the help of vba4all, we managed to delve down right to the issue. 在vba4all的帮助下,我们设法深入研究了该问题。

When I tried to create a new instance of an object using Dim x as new Test_Object.SQLCalls , I was completely oblivious to the fact that I had not re-entered this crucial line: <ClassInterface(ClassInterfaceType.None)> _ . 当我尝试使用Dim x as new Test_Object.SQLCalls创建对象的新实例时,我完全忘记了我没有重新输入以下关键行这一事实: <ClassInterface(ClassInterfaceType.None)> _

Prior to doing this, I had this in my object explorer which has both the ISQLCalls and SQLCalls in the Classes section 在执行此操作之前,我将其放在对象浏览器中,该浏览器的“类”部分中同时包含ISQLCalls和SQLCalls 在此处输入图片说明

But wait, ISQLCalls isn't a class, it's an interface! 但是,等等,ISQLCalls不是一个类,而是一个接口!

By entering the <ClassInterface(ClassInterfaceType.None)> _ back in the SQLCalls class, the object explorer looked a bit better: 通过在SQLCalls类中输入<ClassInterface(ClassInterfaceType.None)> _ ,对象浏览器看起来会更好一些:

在此处输入图片说明

And low and behold, I could now create a new instance of the class, and the methods were exposed. 瞧瞧,我现在可以创建该类的新实例,并公开这些方法。

tldr: I needed to explicitly declare the interface and use <InterfaceType(ComInterfaceType.InterfaceIsDual)> on the interface and <ClassInterface(ClassInterfaceType.None)> on the class. tldr:我需要显式声明接口,并在接口上使用<InterfaceType(ComInterfaceType.InterfaceIsDual)> ,并在类中使用<ClassInterface(ClassInterfaceType.None)>

Many thanks to vba4all, who selflessly devoted their time to assist in this issue. 非常感谢vba4all,他花了无私的时间来协助解决此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM