为什么在我调用COM服务器时Dim as new和Dim/Set在VBA中表现不同?
我已被从VBA称为进程外-COM服务器(C++)。为什么在我调用COM服务器时Dim as new和Dim/Set在VBA中表现不同?
因为当我把它称为多次(至少两个在同一子倍),我只能利用Dim xx As New xxx
称之为原因不明。
当我尝试使用Dim xxx As xxx
然后Set xx = new xxx
调用它时,我的com服务器产生违例读取异常,VBA返回错误代码800706BE
。
下面的代码不工作(伪代码 - 我删除了不相关的部分)。注意'Main'子调用'aux'函数,Sub和'aux'函数调用我的COM服务器(两个不同的类)。
Function aux() As Double()
Dim com As 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 New COMServer.classe1
Dim Returns() As Double
Returns = aux ' call Function aux
Resultat = com1.Method1(Returns) 'actual call to the COM Server
End Sub
以下不工作:
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
有人能解释我为什么我的代码只在第一种情况下工作?
还要注意的是,如果我只在子调用服务器次(无调用AUX),那么这两种方法(灰暗新的和点心/套)的工作。
编辑
我注意到,在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
唯一的区别是,我把我的服务器之前调用它(而不是将其初始化之前调用我的“辅助”功能)。 是否是有意义的人?
Dim
陈述不是可执行文件。声明是Set
。
当你做Dim foo As New 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走出它的方式,以确保总有该指针有效的对象引用,不管是什么。对象变量As New
的每个成员调用都是有效的:VBA将创建成员调用前的新实例,如果参考指向Nothing
- 这是我前面提到的开销,并且与LS_dev's answer相抵触。自动实例化的对象变量不是“仅在第一个成员调用时实例化的” - 它们在需要成为时实例化为。
答案很可能在您的C++代码中,而不是在客户端VBA代码中。 东西是错误的,你如何清理东西,有松散的末端某处 - 使用As New
绕过一个马虎的COM服务器并不打动我作为一个好主意(As New
应该避免,作为一个问题事实上,对于上面描述的直觉行为)。
问题可能是在调用顺序。从我的经验,申报的对象与As New
仅在第一个成员调用实例,而Set ... = New
实例化OB立即开始。
这样说,在第一种情况下classe2
是在classe1
之前创建的,只有当您拨打com1.Method1
时才创建。
在第二种情况下,classe1
创建于Set
之前,classe2
之前。
考虑到这一点,它会以某种方式关联您的COM代码,如果在classe2
之前创建了classe1
,则会创建内存违规。
感谢这个想法,我正在调查它,但事先两个班应该是独立的。 – Malick
谢谢,请参阅我的编辑,重新安排我的服务器的初始化后,异常消失,但我不明白为什么。 – Malick
我不认为你的问题完全可以在没有C++代码的情况下回答。两个初始化对应于两个“新的”声明;为什么它停止不是VBA的错,但可能是COM服务器中的一个错误。 –
你说得对,问题来自我的C++代码,我在ATL类中初始化了一些第三部分运行时,而不是在主CAtlExeModuleT模块中。现在,这对两种情况都适用,感谢您指出我正确的方向和解释。 – Malick