【问题标题】:Variable not defined on VBA about socketVBA 上未定义关于套接字的变量
【发布时间】:2020-04-11 05:37:42
【问题描述】:

我正在对 VBA 上的一个项目进行编辑,该项目使用 Socket 将信息发送到特定服务器上 Netbeans 上的程序。

代码不是我写的。我试图了解最初的程序员做了什么。

我有很多表单,还有一些通过该套接字发送信息。我正在尝试用另一种形式做同样的事情。

错误是

“变量未定义”。

在任何时候的所有项目中都有一个名为“Socket”的对象/变量的声明,但在最初运行连接的表单中,您可以使用它进行任何操作,例如Socket.CloseSocket.RemoteHost = "xxx.xxx.xxx.xxx"Socket.RemotePort = "xxxx"Socket.Connect 都没有问题。

我在开头有Option Explicit,但在其他表单上也有相同的选项。

我已经用 F8 查看了执行流程,看看是否声明了变量的方法或某些东西,但是,或者我缺少某些东西或没有定义。

【问题讨论】:

    标签: mysql sql vba sockets


    【解决方案1】:

    听起来您的 Socket 变量在表单的代码隐藏中声明为 Public 字段。

    表单是带有可视化设计器的类模块。作为类模块,当您使用一个类模块时,您就是在使用类的一个实例

    如果您在任何类模块(即任何ThisWorkbookSheet1UserForm1Class1 模块)中声明Public Socked As Object,那么是的,该对象是Public,但这并不成立它全局:公共字段属于它声明的类的实例

    这使得 Socket 标识符在表单的代码隐藏之外的任何地方使用时,实际上是一个未声明的变量 - 使用 Option Explicit 在编译时捕获这个错误的荣誉,否则很可能直到运行时才被注意到,其中未声明的 Socket 局部变量将是一些 Variant/Empty 值,并且某处某处可能不会喜欢它并且会提出了一些错误,可能与问题的实际根源相去甚远!

    您有多种选择。

    1。将Socket 设为实际的全局变量

    Socket 目前属于我称之为UserForm1 的东西。由于其他组件需要这条数据,您可以通过将声明移至 标准模块 (.bas) 来扩展其范围:

    'Module1.bas
    Option Explicit
    Public Socket As Object
    

    现在只需从 UserForm1 中删除声明,一切都应该“正常工作”。

    除了,它是一个全局变量:任何地方的每个人都可以随时覆盖这个对象引用。

    这并不理想。

    2。让其他代码使用它所在的Socket

    Socket 属于 UserForm1。根据您如何/是否实例化该表单,您可能可以将其视为全局状态,因为所有UserForm 模块都有一个VB_PredeclaredId 隐藏属性设置为True,这正是您能够做到的这样做:

    UserForm1.Show
    

    当你这样做时,UserForm1 对象实例由 VBA 在 . 取消引用运算符处创建,然后调用 Show 方法。 如果实例不自毁,那么当表单被隐藏卸载)后执行返回时,你就可以访问所有内容了Public关于它:

    Dim theSocket As Object
    Set theSocket = UserForm1.Socket
    

    现在这显然带有一个主要警告:您需要采取措施确保 VBA 不会重新生成一个全新的实例(使用全新的 Socket 引用,设置为 Nothing)当. 解引用运算符在该指令中运行。

    您可以通过处理QueryClose 事件并显式取消实例的销毁来做到这一点:

    Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
        If CloseMode = VbQueryClose.vbFormControlMenu Then
            Cancel = True
            Me.Hide
        End If
    End Sub
    

    如果你有一个OkButton 做这样的事情:

    Private Sub OkButton_Click()
        Unload Me
    End Sub
    

    或者更糟糕的是,像这样:

    Private Sub OkButton_Click()
        Unload UserForm1
    End Sub
    

    然后改成这样:

    Private sub OkButton_Click()
        Me.Hide
    End Sub
    

    这很关键:您必须 Hide 表单,而不是 Unload 它,并且您不能让它在执行返回之前被销毁 - 调用代码需要才能使用与用户交互的实例完全相同。

    3。自己控制

    UserForm1 是一个类,就像任何其他类一样。 New 自己解决而不是让 VBA 负责:采取与上述完全相同的预防措施,但现在假装没有默认实例

    Public Sub DoSomething()
        With New UserForm1
            .Show
    
            Dim theSocket As Object
            Set theSocket = .Socket
    
        End With
    End Sub
    

    请参阅我的UserForm1.Show 文章了解更多信息和详细信息。


    4。使用单独的Socket 对象

    如果表单的Socket 对象没有在该表单之外使用任何业务,那么其他代码也定义和设置Socket 来使用可能更有意义?

    变量的范围应该尽可能的小,尤其是当我们在查看共享资源时,比如一个套接字连接:如果不同的程序Set这个套接字指向不同的东西,那么唯一的目的就是该变量为Public 是为了避免在需要套接字的任何地方声明它的击键,这是滥用全局状态并且会在后端咬你,一天或一天​​。

    从实用的角度讲,表单无论如何都不知道如何连接套接字:应该有一个专门的模块来处理这个问题,每个需要与套接字通信的人都应该通过该模块。

    【讨论】:

    • 这非常非常有帮助!!但是,我找不到它在所有表单中声明对象的位置。我一直在到处寻找,但不知何故,声明必须是某些包或类似的包中固有的(这是我的结论)。我想我会在我正在处理的表格上声明它,就是这样。编辑:我正在考虑在表单类上声明私有。但是,如果我退出该表格并输入另一个表格:它会被重新申报吗?比如,如果我退出表格或其他什么,我应该取消声明它或其他什么? PS:你的回答很有帮助,非常感谢!
    • @GabrielÁlvarezMartínez-Conde Rubberduck 可以为您找到它(如果存在)。
    • 更新:我已经找到了问题,哎呀!这比我想象的要简单。问题出在表单的界面上,唯一要做的就是放置一个 WinSock 图标并用名称“Socket”调用它。这样,当表单执行时,它会创建 Socket 等。无论如何,非常感谢!
    猜你喜欢
    • 2019-02-20
    • 2018-11-14
    • 1970-01-01
    • 2023-02-14
    • 1970-01-01
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多