封送 ComVisible 组件可变参数数组参数

Chr*_*s J 5 c# vb6 com-interop vb6-migration

我正在考虑将一些用 VB6 编写的遗留 COM 代码迁移到 .NET,但这需要生成一个与原始代码相当接近的类型库。

在早期绑定到其他 VB6 组件时,我遇到了传递参数数组的问题。在最初的 VB6 中,签名如下所示:

Public Function ExecSPReturnRS(ByVal strProcAs String, _
            ParamArray varParams() As Variant) As Recordset
Run Code Online (Sandbox Code Playgroud)

并生成如下所示的 MIDL:

[id(0x60030009), vararg]
HRESULT ExecSPReturnRS([in] BSTR strProc,
                       [in, out] SAFEARRAY(VARIANT)* varParams,
                       [out, retval] _Recordset** );
Run Code Online (Sandbox Code Playgroud)

使用 C#,我无法确定生成相同 MIDL 的正确声明。我要么缺少vararg声明,要么 varParams 参数被声明为而SAFEARRAY(VARIANT)不是SAFEARRAY(VARIANT)*.

因此,如果在 C# 中我声明为:

Recordset ExecSPReturnRS(string storedProc, ref object[] arguments);
Run Code Online (Sandbox Code Playgroud)

...我明白了SAFEARRAY(VARIANT)*,但没有vararg。但是如果我声明为

Recordset ExecSPReturnRS(string storedProc, params object[] arguments);
Run Code Online (Sandbox Code Playgroud)

...然后我得到了vararg但 SAFEARRAY 未声明为引用。

我希望这MarshalAsAttribute可能是可行的方法,但到目前为止我能想到的最好方法是:

Recordset ExecSPReturnRS(string storedProc, 
                         [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)]
                         object[] arguments);
Run Code Online (Sandbox Code Playgroud)

但这给了我相同的 MIDL,就好像我声明params没有元帅一样。

本质上,我希望 MIDL 反映出来,就好像我同时指定了refparams,这在 C# 下是非法的。我缺少什么咒语?


编辑:似乎对最终目标是什么有些困惑。本质上,我们的应用程序由许多旧版 VB6 组件组成。为了消除遗留债务,我们需要能够将 VB 组件一点一点地转移到 .NET。如果该组件依赖于其他组件,则 .NET 需要可与现有 VB6 和经典 ASP 一起使用,最好无需更改代码。一些遗留组件将被完全重构并且最终不再依赖于 COM。许多 VB6 组件都使用早期绑定。

就目前而言,当我使用param.NET 中的声明来代替 VB6 ParamArray 时,针对该对象构建 VB6 组件会导致函数或接口标记为受限,或者该函数使用 VB6 中不支持的自动化类型。 VB 中的Visual Basic错误。如果我改用ref它,则会收到构建错误“类型不匹配:需要数组或用户定义的类型”。

在 VB6 中对我正在查看的特定组件的调用类似于:

Set rs = dbconn.ExecSPReturnRS("dbo.StoredProc", _
    Array("@param1", value), _ 
    Array("@param2", value))
Run Code Online (Sandbox Code Playgroud)

我假设这个问题是 typelib 问题,因为我的理解是 VB 将在构建时使用它来验证早期绑定时的调用。然而我后来发现,如果我晚绑定所有内容,那么 VB 构建就会成功并且调用似乎可以工作。然而,这将需要更改旧版 VB6 的源代码,并且除了后期绑定时失去自动完成功能之外,我预计还会失去参数的构建时验证。但这可能是我们最好的选择。

最后一点:目前这是一项研究/PoC,旨在找出需要什么和不需要什么。最终,这并不是对所有对象进行逐行转换。某些对象需要公开 COM 接口,其他对象则不需要,还有一些对象将被重构或删除。然而,在某些地方,我们需要维持 COM 兼容接口以实现向后兼容性,至少在迁移过程中的中短期内如此。

R.J*_*ill 0

使用类型库导入器 (Tlbimp.exe) 生成互操作程序集,然后使用 Redgate Reflector 或类似工具反编译生成的程序集。Reflector(至少)将生成用其必需的互操作属性正确修饰的接口,并且可以将代码复制并粘贴到您自己的源文件中。