为什么在调用COM服务器时,VBA中的Dim as New和Dim/Set的行为不同?

为什么在调用COM服务器时,VBA中的Dim as New和Dim/Set的行为不同?,vba,com,Vba,Com,我制作了一个从VBA调用的进程外COM服务器(C++) 由于未知原因,当我多次调用它(在同一个子系统中至少调用两次)时,我只能使用Dim xx作为新的xxx调用它 当我尝试使用Dim xxx As xxx调用它,然后Set xx=new xxx时,我的com服务器会引发一个违规读取异常,VBA返回错误代码800706BE 以下代码确实有效(伪代码-我删除了不相关的部分)。请注意,“Main”子函数调用“aux”函数,而“sub”和“aux”函数都调用我的COM服务器(两个不同的类) 以下不起作用

我制作了一个从VBA调用的进程外COM服务器(C++)

由于未知原因,当我多次调用它(在同一个子系统中至少调用两次)时,我只能使用
Dim xx作为新的xxx调用它

当我尝试使用
Dim xxx As xxx
调用它,然后
Set xx=new xxx
时,我的com服务器会引发一个违规读取异常,VBA返回错误代码
800706BE

以下代码确实有效(伪代码-我删除了不相关的部分)。请注意,“Main”子函数调用“aux”函数,而“sub”和“aux”函数都调用我的COM服务器(两个不同的类)

以下不起作用:

 Function aux() As Double()

        Dim com As COMServer.classe2
        Set com  = New COMServer.classe2

        Dim Returns() As Double
        Returns = com.Method2 'actual call to the COM Server
        aux = Returns
End Function

Sub Main()
     Dim Resultat() As Double

     Dim com1 As  COMServer.classe1
     Set com1  = New COMServer.classe1

     Dim Returns() As Double
     Returns = aux ' call Function aux
     Resultat = com1.Method1(Returns)   'a violation reading (c++) Exception is thrown here
End Sub
有人能解释一下为什么我的代码只在第一种情况下有效吗

还要注意的是,如果我在sub中只调用服务器一次(不调用aux),那么这两种方法(Dim as New和Dim/Set)都可以工作


编辑

我注意到在案例1中(有效的案例):我的服务器连续两次自动启动和停止(见Windows任务管理器)

而在第二种情况下(有缺陷的情况):我的服务器只启动一次,没有停止并引发错误

现在,我刚刚以以下方式修改了第二个案例,例外情况消失了:

Sub Main()
     Dim Resultat() As Double

     Dim Returns() As Double
     Returns = aux ' call Function aux

     Dim com1 As  COMServer.classe1
     Set com1  = New COMServer.classe1
     Resultat = com1.Method1(Returns)   'no more Exception 
End Sub
唯一的区别是我在调用它之前设置了服务器(而不是在调用“aux”函数之前初始化它)。
这对某人有意义吗?

问题可能在调用顺序中。根据我的经验,使用
声明为新的对象仅在第一次成员调用中实例化,而
Set…=New
立即实例化对象

如上所述,在第一种情况下,
classe2
是在
classe1
之前创建的,它仅在调用
com1.Method1
时创建

在第二种情况下,在
classe2
之前的
Set
中创建
classe1


考虑到这一点,如果
classe1
classe2
之前创建
classe1
,问题可能是在调用顺序中。根据我的经验,用
声明为新的对象只会在第一次成员调用中实例化,而
Set…=New
实例化对象马上

如上所述,在第一种情况下,
classe2
是在
classe1
之前创建的,它仅在调用
com1.Method1
时创建

在第二种情况下,在
classe2
之前的
Set
中创建
classe1


考虑到这一点,如果
classe1
是在
classe2
之前创建的
Dim
语句不可执行。
Set
语句不可执行,则COM代码会以某种方式创建内存冲突

当您将foo设置为新的Bar时,您正在创建一个自动实例化的对象变量,这会在VBA运行时产生一点开销(对它的每次调用都会验证是否存在有效的对象引用)

这就是自动实例化对象的作用方式:

Dim foo As New Collection
Set foo = Nothing
foo.Add 42 'runtime error 91? nope.
Debug.Print foo.Count ' prints 1
Set foo = Nothing
Debug.Print foo.Count ' runtime error 91? nope. prints 0
因此,
As New
使VBA不遗余力地确保该指针始终有一个有效的对象引用,无论发生什么。对声明为
的对象变量的每个成员调用都是有效的:如果引用指向
Nothing
,VBA将在进行成员调用之前创建一个新实例-这就是我的开销自动实例化的对象变量并不是“仅在第一次成员调用时实例化”——它们在需要时被实例化


<> >答案可能在C++代码中,而不是在客户端VBA代码中。有些东西是错误的,你是如何清理的,有些地方有松散的地方——使用<代码>作为新的< /代码>来绕过松散的COM服务器并不把我当成一个好主意。(
作为新的
通常应该避免,事实上,对于上面描述的非直观行为)。

Dim
语句是不可执行的。
Set
语句是可执行的

当您将foo设置为新的Bar时,您正在创建一个自动实例化的对象变量,这会在VBA运行时产生一点开销(对它的每次调用都会验证是否存在有效的对象引用)

这就是自动实例化对象的作用方式:

Dim foo As New Collection
Set foo = Nothing
foo.Add 42 'runtime error 91? nope.
Debug.Print foo.Count ' prints 1
Set foo = Nothing
Debug.Print foo.Count ' runtime error 91? nope. prints 0
因此,
As New
使VBA不遗余力地确保该指针始终有一个有效的对象引用,无论发生什么。对声明为
的对象变量的每个成员调用都是有效的:如果引用指向
Nothing
,VBA将在进行成员调用之前创建一个新实例-这就是我的开销自动实例化的对象变量并不是“仅在第一次成员调用时实例化”——它们在需要时被实例化


<> >答案可能在C++代码中,而不是在客户端VBA代码中。有些东西是错误的,你是如何清理的,有些地方有松散的地方——使用<代码>作为新的< /代码>来绕过松散的COM服务器并不把我当成一个好主意。(
作为新的
通常应该避免,事实上,对于上面描述的非直观行为).

谢谢这个想法,我正在调查,但两个类之前应该是独立的。谢谢这个想法,我正在调查,但两个类之前应该是独立的。谢谢,请查看我的编辑,在我重新安排服务器初始化后,异常消失,但我不明白为什么。我不认为你的问题这两个初始化对应于C++代码,作为新的< /Cord>声明;为什么它停止不是VBA的错误,而是COM服务器中的一个错误。您是对的,问题来自C++代码,我在我的A中初始化了第三个部分运行时。