当我调用COM服务器时,为什么Dim as New和Dim / Set在VBA中表现不同?

时间:2017-08-25 13:12:43

标签: vba com

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

由于一个未知的原因,当我多次调用它时(在同一个sub中至少两次),我只能使用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

有人可以解释一下为什么我的代码仅适用于第一种情况吗?

另请注意,如果我只在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'函数之前初始化它)。 对某人有意义吗

2 个答案:

答案 0 :(得分:3)

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的对象变量的每个成员调用都是有效的:如果引用指向Nothing,VBA将在进行成员调用之前创建一个新实例 - 这是我之前提到的开销,与LS_dev's answer相矛盾。自动实例化的对象变量不是“仅在第一次成员调用时实例化” - 只要需要,它们就会被实例化

答案可能在您的C ++代码中,而不是在客户端VBA代码中。 某些东西错误的你是如何清理的,有一些松散的目的某处 - 使用As New来解决一个草率的COM服务器不会让我感到害怕一个好主意(事实上,As New通常应该避免上述不直观的行为。

答案 1 :(得分:1)

问题可能是按顺序呼叫。根据我的经验,使用As New声明的对象仅在第一个成员调用中实例化,而Set ... = New立即实例化对象。

这样说,第一种情况classe2是在classe1之前创建的,com1.Method1仅在您致电classe1时创建。

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

考虑到这一点,如果在classe2之前创建#include <stdlib.h> #include <stdio.h> #include <malloc.h> short int max_short(void) { short int i = 1, j = 0, k = 0; while (i>k) { k = i; if (((short int)(2 * i))>(short int)0) i *= 2; else { j = i; while ((short int)(i + j) <= (short int)0) j /= 2; i += j; } } return i; } int main() { printf("%d", max_short()); while (1); } ,它会以某种方式创建内存冲突。