为什么在我调用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应该避免,作为一个问题事实上,对于上面描述的直觉行为)。

+0

谢谢,请参阅我的编辑,重新安排我的服务器的初始化后,异常消失,但我不明白为什么。 – Malick

+1

我不认为你的问题完全可以在没有C++代码的情况下回答。两个初始化对应于两个“新的”声明;为什么它停止不是VBA的错,但可能是COM服务器中的一个错误。 –

+1

你说得对,问题来自我的C++代码,我在ATL类中初始化了一些第三部分运行时,而不是在主CAtlExeModuleT模块中。现在,这对两种情况都适用,感谢您指出我正确的方向和解释。 – Malick

问题可能是在调用顺序。从我的经验,申报的对象与As New仅在第一个成员调用实例,而Set ... = New实例化OB立即开始。

这样说,在第一种情况下classe2是在classe1之前创建的,只有当您拨打com1.Method1时才创建。

在第二种情况下,classe1创建于Set之前,classe2之前。

考虑到这一点,它会以某种方式关联您的COM代码,如果在classe2之前创建了classe1,则会创建内存违规。

+0

感谢这个想法,我正在调查它,但事先两个班应该是独立的。 – Malick