在delphi 6中有一个错误,您可以在线找到一些参考资料,当您导入tlb时,事件调用中的参数顺序会被反转。它在导入的标题中反转一次,在TServerEventDIspatch.Invoke中反转一次。
您可以在此处找到有关它的更多信息: http://cc.embarcadero.com/Item/16496
在某种程度上与此问题有关,在TServerEventDispatch.Invoke中出现内存泄漏,其参数类型Var_Array的Variant(可能是其他的,但这是我能看到的更明显的一个)。调用代码将args复制到VarArray中以传递给事件处理程序,然后在调用之后将VarArray复制回args,相关代码粘贴在下面:
// Set our array to appropriate length
SetLength(VarArray, ParamCount);
// Copy over data
for I := Low(VarArray) to High(VarArray) do
VarArray[I] := OleVariant(TDispParams(Params).rgvarg^[I]);
// Invoke Server proxy class
if FServer <> nil then FServer.InvokeEvent(DispID, VarArray);
// Copy data back
for I := Low(VarArray) to High(VarArray) do
OleVariant(TDispParams(Params).rgvarg^[I]) := VarArray[I];
// Clean array
SetLength(VarArray, 0);
在我的案例中有一些明显的解决方法:如果我在VarArray参数的情况下跳过复制,它会修复泄漏。不改变功能,我认为我应该将数组中的数据而不是变量复制回params,但这可能会变得复杂,因为它可以容纳其他变体,在我看来需要递归完成。
由于OleServer的更改会产生连锁反应,我想确保我的更改严格正确。
任何人都可以了解为什么内存会泄露到这里?我似乎无法查询任何低于TServerEventDIspatch.Invoke的callstack(为什么会这样?)
我想在复制变量的过程中,将VarArray复制回参数列表,它添加了对数组的引用,因此不允许它像正常一样释放,但这只是一个粗略的猜测,我无法追踪支持它的代码。
也许对这一切有更好了解的人可以解释一下?
答案 0 :(得分:2)
有趣的是,我认为解决方案是我在问题中提供的链接,但是直到深入了解它之后我才明白这个含义。
要澄清一些事项:
似乎问题与不加选择地回写参数值有关。我正在处理的特定事件没有任何标记为var的参数,因此COM对象不期望更改调用参数以释放已分配的新内存。
大致COM对象分配了一个数组,调用该事件然后在事件发生后释放它自己的内存。然而,当Oleserver将数组参数复制回到COM对象甚至不知道的参数列表时,Oleserver会分配一些新内存,因为它没有通过引用传递任何内容,并且不期望更改其参数。那里必须有一些额外的编组魔法,我忽略了,如果有人知道细节,我肯定会好奇。
TVariantArg的vt字段有一个标志,指示它是通过值还是引用传递。据我所知,如果param被标记为通过引用传递,我们应该只复制值。
此外,可能有必要做的不仅仅是分配变量,如果这实际上是通过引用传递,虽然可以由编组处理,但仍然不确定这部分。
现在的解决方案是将代码更改为:
if ((TDispParams(Params).rgvarg^[I].vt and VT_BYREF) <> 0) then begin
OleVariant(TDispParams(Params).rgvarg^[I]) := VarArray[I];
end;