【问题标题】:Excel interop macro out/ref parametersExcel 互操作宏输出/引用参数
【发布时间】:2017-03-27 21:27:13
【问题描述】:

我继承了一个 VB6 应用程序,该应用程序可以启动 Excel、打开工作簿并按时间间隔运行宏。该宏通过其参数返回值。在我尝试使用互操作将其转换为 C# 时,我可以成功运行宏,但不会返回这些参数值。

下面的代码中是否缺少某些内容/不正确,或者根本不支持?

VBA 宏:

Sub Foo(bar As Long)
    bar = 5
End Sub

C#代码:

void CallFoo()
{
    // Declared as an object to avoid losing the value in auto-boxing
    // The result is the same if declared as int
    Object bar = 0;

    m_application.Run(m_fooCommand, a);

    Console.WriteLine(a); // a is always 0
}

这个(大致)等效的 VB6 代码可以很好地获取返回值。

Dim bar as Long
bar = 0
xlApp.Run "Test.xlsm!Foo", bar
MsgBox bar // prints 5

【问题讨论】:

  • Excel.Application.Run 甚至没有在 VBA 中分配 ByRef。您确定 VB6 代码正在做您认为它正在做的事情吗?
  • 如果 a 被 ByRef 传递,那么在 C# 中它将是 ref a
  • 如果Run 参数不是ByRef,那么VB6 代码不可能按照您描述的方式工作。 没有魔法。此时你的问题不看VB6代码就无法回答。
  • 另外,VB6默认ByRef,是C#方法签名没有声明ref
  • 是的,它可以返回单个值。我想我应该在示例中更清楚地说明,重点是它实际上可以返回多个最初由多个参数返回的值。

标签: c# excel vba vb6


【解决方案1】:

据我所知,不,您不能以这种方式通过参数将值从 VBA 返回到 C#。下一个最好的方法是在 .NET 中简单地创建一个类型,使其 COM 可见,重新填充它,然后在 VBA 脚本中引用它。

所以,为了完整性...

返回类型:

[ComVisible(true)]
[Guid("097B5B52-C73B-4BD0-A540-802D0BC7C49F")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IFooResult
{
    int Value { get; set; }
}

[ComVisible(true)]
[Guid("76B6BCBD-6F4D-4457-8A85-CDC48F4A7613")]
[ClassInterface(ClassInterfaceType.None)]
public class FooResult : IFooResult
{
    [DispId(1)]
    public byte[] Buffer { get; set; }
}

生成强名称(regasm 需要)

sn -k FooLib.snk

注册程序集

regasm FooLib.dll /tlb:FooLib.tlb /codebase

然后只需在 VBA 项目中引用该库即可。它现在可以作为参数传递并填充到宏中,也可以在宏中创建并从宏中返回(我相信这需要在 .NET 端进行清理,Marshal.ReleaseComObject())。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多