我已经制作了一个从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'函数之前初始化它)。 对某人有意义吗?
答案 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);
}
,它会以某种方式创建内存冲突。