我正在考虑将用VB6编写的一些遗留COM代码迁移到.NET,但是这需要生成一个与原始版本非常接近的类型库。
当早期绑定到其他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,好像我在没有MarshalAs的情况下声明为params
。
从本质上讲,我希望MIDL反映出我同时指定了ref
和params
,这在C#下是非法的。我错过了什么咒语?
<小时/> 编辑:似乎最终目标是什么令人困惑。本质上,我们有一个由许多传统VB6组件组成的应用程序。为了消除遗留债务,我们需要能够将VB组件逐位移动到.NET。在该组件依赖于其他组件的情况下,.NET需要与现有的VB6和经典ASP一起使用,理想情况下不需要更改代码。一些遗留组件将被完全重构,最终没有COM依赖。许多VB6组件都使用早期绑定。
目前,当我使用.NET中的param
声明代替VB6 ParamArray时,针对该对象构建VB6组件会导致函数或接口标记为受限制,或者该函数使用VB中的Visual Basic 错误中不支持的自动化类型。如果我使用ref
代替,我会收到构建错误类型不匹配:数组或用户定义的预期类型。
在VB6中调用我正在查看的特定组件:
Set rs = dbconn.ExecSPReturnRS("dbo.StoredProc", _
Array("@param1", value), _
Array("@param2", value))
我认为这个问题是一个类型库问题,因为我的理解是VB将在构建时使用它来在早期绑定时验证调用。但是我已经发现,如果我迟到绑定所有内容,那么VB构建成功并且调用似乎有效。然而,这将需要遗留VB6的源代码更改,而不是在后期绑定时丢失自动完成,我预计我也会失去参数的构建时验证。但它可能是我们最好的选择。
最后一点说明:目前这是研究/ PoC,以找出需要什么和不需要什么。最终,不旨在成为所有对象的逐行转换。某些对象需要公开COM接口,其他对象则不需要,其他对象将被重构或删除。但是,为了向后兼容,我们需要维持COM兼容接口,至少在短期到中期的同时进行迁移。
答案 0 :(得分:0)
使用类型库导入器(Tlbimp.exe)生成互操作程序集,然后使用Redgate Reflector或类似工具反编译生成的程序集。 Reflector(至少)将生成正确地装饰有必要互操作属性的接口,并且可以将代码复制并粘贴到您自己的源文件中。