为什么在调用COM服务器时,VBA中的Dim as New和Dim/Set的行为不同?
我制作了一个从VBA调用的进程外COM服务器(C++) 由于未知原因,当我多次调用它(在同一个子系统中至少调用两次)时,我只能使用为什么在调用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服务器(两个不同的类) 以下不起作用
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中初始化了第三个部分运行时。