封送ComVisible组件变量数组参数
本文关键字:数组 参数 变量 组件 ComVisible 封送 | 更新日期: 2023-09-27 18:15:42
我正在考虑将一些用VB6编写的遗留COM代码迁移到。net,但是这需要生成一个非常接近原始的typelib。
当早期绑定到其他VB6组件时,我遇到了一个传递参数数组的问题。在最初的VB6中,签名是这样的:
Public Function ExecSPReturnRS(ByVal strProcAs String, _
ParamArray varParams() As Variant) As Recordset
和生成的MIDL如下所示:
[id(0x60030009), vararg]
HRESULT ExecSPReturnRS([in] BSTR strProc,
[in, out] SAFEARRAY(VARIANT)* varParams,
[out, retval] _Recordset** );
对于c#,我不能确定正确的声明来生成相同的MIDL。我要么错过了vararg
声明,要么varParams参数被声明为SAFEARRAY(VARIANT)
而不是SAFEARRAY(VARIANT)*
。
所以如果在c#中我声明为:
Recordset ExecSPReturnRS(string storedProc, ref object[] arguments);
…我得到SAFEARRAY(VARIANT)*
,但没有vararg
。但是如果我声明为
Recordset ExecSPReturnRS(string storedProc, params object[] arguments);
…然后我得到vararg
,但SAFEARRAY没有被声明为引用。
我希望MarshalAsAttribute
可能是走的路,但到目前为止我能想到的最好的是:
Recordset ExecSPReturnRS(string storedProc,
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]
object[] arguments);
但这给了我相同的MIDL,如果我声明为params
没有MarshalAs。
本质上,我希望MIDL反映出我同时指定了ref
和params
,这在c#中是非法的。我错过的咒语是什么?
编辑:似乎有一些混乱的最终目标是什么。本质上,我们有一个由许多遗留的VB6组件组成的应用程序。为了消除遗留债务,我们需要能够一点一点地将VB组件转移到。net。当组件依赖于其他组件时,. net需要与现有的VB6和经典ASP兼容,理想情况下不需要修改代码。一些遗留组件将被完全重构,最终不再依赖于COM。许多VB6组件使用早期绑定。
就目前而言,当我在。net中使用param
声明来代替VB6 ParamArray时,针对该对象构建VB6组件会导致函数或被标记为受限的接口,或者该函数使用VB中不支持的自动化类型错误。如果我使用ref
代替,我得到构建错误类型不匹配:数组或用户定义的类型预期。
在VB6中对我正在查看的特定组件的调用看起来像这样:
Set rs = dbconn.ExecSPReturnRS("dbo.StoredProc", _
Array("@param1", value), _
Array("@param2", value))
我认为这个问题是一个类型问题,因为我的理解是VB将在构建时使用它来验证早期绑定时的调用。然而,我后来发现,如果我晚绑定所有东西,那么VB构建是成功的,调用似乎可以工作。然而,这将需要更改遗留VB6的源代码,并且除了在后期绑定时失去自动完成功能外,我预计还会失去参数的构建时验证。但这可能是我们最好的选择。
最后一点:目前这是研究/PoC,以找出什么是需要的,什么是不需要的。最终,这是而不是,目的是对所有对象进行逐行转换。有些对象需要公开COM接口,有些对象则不需要,还有一些对象将被重构或删除。然而,在某些地方,我们将需要维持一个向后兼容的COM兼容接口,至少在迁移进行的中短期内是这样。
使用类型库导入器(Tlbimp.exe)生成互操作程序集,然后使用Redgate Reflector或类似工具反编译生成的程序集。Reflector(至少)将生成用必需的互操作属性正确装饰的接口,并且代码可以复制并粘贴到您自己的源文件中。