本文介绍了在使用C#编写的COM服务器的Windows上,可以为早绑定和晚绑定代码返回SAFEARRAY吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题很长,所以我将用项目符号格式化以便于讨论

The question is quite long, so I'll format with bullet points for easier discussion


  1. 我正在编写C#COM服务器。

  2. COM服务器既可以在早期绑定模式下也可以在后期绑定模式下在Excel VBA中使用。

  3. 我的绊脚石是如何返回可在早期和晚期绑定模式下工作的实例化类的SAFEARRAY;我得到错误。

  4. (整天)我已经做了很多工作:


    • 我已经做了一些诊断并设置了调试器来说明我遇到的错误。

    • 我做了一些相当详尽的谷歌搜索。

    • 我发现了一些不太令人满意的解决方法。

    • 我现在真的很沮丧,正在寻找COM Interop专家来帮助我寻求一个好的解决方案。

  1. I'm writing a C# COM Server.
  2. the COM server is for use in Excel VBA both in early binding and late binding modes.
  3. My stumbling block is how to return a SAFEARRAY of instantiated classes that works both in early and late binding mode; I get errors.
  4. I have done plenty of work on this (all day):
    • I have done some diagnostics and setup the debugger to shed light on the errors I get.
    • I have done some fairly exhaustive googling.
    • I found some workarounds which are less than satisfactory.
    • I am now genuinely stumped and looking for a COM Interop expert to help me get to a good solution please.



设置项目类型和项目属性



To set up the project type and project properties


  1. 创建一个新的C#类库项目。

  2. 我将其命名为LateBoundSafeArraysProblem,也将源文件重命名为LateBoundSafeArraysProblem.cs。

  3. 在AssemblyInfo.cs中将第20行修改为ComVisible(true),因此可见性是通用的(仍然需要公共关键字)。

  4. 设置项目属性:


    • 设置构建选项,在项目属性->构建->输出中,选中注册COM互操作复选框。

    • 设置调试选项以启动Excel并加载excel工作簿客户端:


      • 在项目属性->调试->开始操作中,选择单选按钮开始外部问题并输入Microsoft Excel的路径,对我来说,该路径是 C:\Program Files\Microsoft Office 15\root\office15\excel.exe。

      • 在项目属性->调试->启动选项中,输入启用了客户端Excel宏的工作簿的名称,对我来说是C:bookTemp\LateBoundSafeArraysProblemClient.xlsm。 †

  1. Create a new C# Class library project.
  2. I named mine LateBoundSafeArraysProblem, also I renamed the source file to be LateBoundSafeArraysProblem.cs.
  3. In AssemblyInfo.cs amend line 20 to ComVisible(true) , so visibility is universal (still needs public keywords).
  4. Set the Project Properties:
    • Set the build options, in Project Properties->Build->Output I check the 'Register for COM interop' checkbox.
    • Set the debug options to launch Excel and load an excel workbook client:
      • In Project Properties->Debug->Start Action and select radio button 'Start external problem' and enter path to Microsoft Excel which for me is 'C:\Program Files\Microsoft Office 15\root\office15\excel.exe'.
      • In Project Properties->Debug->Start Options enter the name of a client Excel macro enabled workbook, which for me C:\Temp\LateBoundSafeArraysProblemClient.xlsm. †



创建COM服务器源代码



To create the COM server source code


  1. 样式选择和决策


    • I成为一名优秀的COM公民,并将接口定义与类定义分开。


      • 我在类上使用[ClassInterface(ClassInterfaceType.None)]和[ComDefaultInterface(typeof(< interface>)))属性来实现此目的清楚的划分。


  • 苹果是编组的简单国家船只数据返回给客户端,除了getter和setter之外,没有任何方法。

  • FruitCounter是一个工作器类,它具有方法enumerateApples(),该方法将返回Apple实例的SAFEARRAY。

因此,Apples接口和类的源代码为:

So the source code for the Apples interface and class are:

 code>,然后转储返回的VARIANT结构的内存,以查看VARTYPE是什么。对于早期绑定呼叫,它将返回 Variant ,其VARTYPE为 VT_ARRAY& VT_DISPATCH 。对于后期绑定呼叫,它将返回 VT_ARRAY& VT_UNKNOWN 。苹果应该已被定义为在tlb中实现 IDispatch ,但是由于某些原因,我无法理解,VBA难以处理 IUnknown 。解决方法是在C#端将返回类型更改为 object []  ... 

I did a bit of testing on this by marshaling the returned value in to a Variant, and then dumped the memory of the returned VARIANT structure to see what the VARTYPE was. For the early bound call, it was returning a Variant with a VARTYPE of VT_ARRAY & VT_DISPATCH. For the late bound call, it was returning a VARTYPE of VT_ARRAY & VT_UNKNOWN. Apples should already be defined as implementing IDispatch in the tlb, but for some reason that eludes me, VBA is having difficulty handling an array of IUnknown from the late bound call. The work-around is to change the return type to object[] on the C# side...

public object[] enumerateApples()
{
    List<object> applesList = new List<object>();

    //* Add some apples - well, one in fact for the time being
    Apples app = new Apples();
    app.variety = "Braeburn";
    app.quantity = 4;
    applesList.Add(app);

    // * finished adding apples want to convert to SAFEARRAY
    return applesList.ToArray();
}

...并将它们放入 Variant 在VBA上:

...and pull them into a Variant on the VBA side:

Sub TestEarlyBound()
    'Tools -> References to type library LateBoundSafeArraysProblem.tlb
    Dim fc As LateBoundSafeArraysProblem.FruitCounter
    Set fc = New LateBoundSafeArraysProblem.FruitCounter

    Dim apples As Variant
    apples = fc.enumerateApples()

    Debug.Print apples(0).variety   'prints "Braeburn"
End Sub

Sub TestFruitLateBound0()
    Dim fc As Object
    Set fc = CreateObject("LateBoundSafeArraysProblem.FruitCounter")

    Dim apples As Variant
    apples = fc.enumerateApples()

    Debug.Print apples(0).variety   'prints "Braeburn"
End Sub

这篇关于在使用C#编写的COM服务器的Windows上,可以为早绑定和晚绑定代码返回SAFEARRAY吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-22 20:43
查看更多