C# 通过COM4J从.NET方法返回接口数组

C# 通过COM4J从.NET方法返回接口数组,c#,java,com,com-interop,com4j,C#,Java,Com,Com Interop,Com4j,如何通过COM4J将对象数组(实现COM接口)从C#方法返回到Java方法 生成数组的示例C#类: using System; using System.Runtime.InteropServices; namespace Example { [ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface IAnimal { string

如何通过COM4J将对象数组(实现COM接口)从C#方法返回到Java方法

生成数组的示例C#类:

using System;
using System.Runtime.InteropServices;

namespace Example
{

    [ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IAnimal
    {
        string Speak();
    }

    [ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IFarm
    {
        [return:MarshalAs(UnmanagedType.SafeArray,
        SafeArraySubType=VarEnum.VT_UNKNOWN)]
        IAnimal[] GetAnimals();
    }

    [ComVisible(true), ClassInterface(ClassInterfaceType.None)]
    public class Farm : IFarm
    {
        public IAnimal[] GetAnimals()
        {
            return new IAnimal[] { new Cow(), new Pig() };
        }
    }

    internal class Cow: IAnimal
    {
        public string Speak()
        {
            return "Moo";
        }
    }

    internal class Pig: IAnimal
    {
        public string Speak()
        {
            return "Oink";
        }
    }
}
结果.tlb中的接口声明如下所示:

[
  odl,
  uuid(1FB5E376-E78D-3A2E-BEF3-F3C798FCF44C),
  version(1.0),
  oleautomation,
  custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "Example.IFarm")
]
interface IFarm : IUnknown
{
    HRESULT _stdcall GetAnimals([out, retval] SAFEARRAY(IUnknown*)* pRetVal);
};
Java客户端代码:

import com4j.*;

public class Example {
    public static void main(String[] args) {
        IFarm farm = ClassFactory.createFarm();
        Com4jObject[] animals = farm.getAnimals();

        for (Com4jObject o: animals) {
            IAnimal animal = o.queryInterface(IAnimal.class);

            if (animal != null) {
                animal.speak();
            }
        }
    }
}
这会编译,但我在运行时遇到此异常:

Exception in thread "main" com4j.ComException: 
    unexpected conversion type: 500 : .\invoke.cpp:470
        at com4j.Wrapper.invoke(Wrapper.java:185)
        at $Proxy5.getAnimals(Unknown Source)
        at MainClass.main(MainClass.java:7)
Caused by: com4j.ComException: unexpected conversion type: 500 : .\invoke.cpp:470
        at com4j.Native.invoke(Native Method)
        at com4j.StandardComMethod.invoke(StandardComMethod.java:35)
        at com4j.Wrapper$InvocationThunk.call(Wrapper.java:354)
        at com4j.Task.invoke(Task.java:55)
        at com4j.ComThread.run0(ComThread.java:157)
        at com4j.ComThread.run(ComThread.java:137)
我尝试过的其他事情:

  • 编组为
    SAFEARRAY(变体)*
    而不是
    SAFEARRAY(IUnknown*)*

    (这会引发相同的异常。)
  • 删除
    marshallas
    属性(
    tlbimp
    无法创建代理方法)
有没有一种方法可以封送数组,以便COM4J可以将其转换为有效的Java数组

或者,有没有一种方法可以在Java中分配数组并允许.NET方法填充它?(我试过了,但是.NET方法收到了数组的副本,Java代码从来没有看到插入副本的对象。也许有办法覆盖它?)



编辑:这可能是相关的:-VBScript中可能出现类似的情况

您是否尝试将您的接口声明为InterfaceIsDual和/或InterfaceIsIDispatch

[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAnimal
{
...

大多数COM互操作库都需要分派接口;但是,我对COM4J不太确定。您也可以使用抽象的基本COM类而不是接口来实现相同的目标,但如果上述更改不能让您启动并运行,我会感到惊讶。

COM4J使用IUnknown接口-不需要分派。我的问题只是数组(导出集合很好。)这是一个愚蠢的问题,但它是GetAnimal还是GetAnimal。错误表示无法解析getAnimal。@zam664两者都是正确的;COM4J在生成Java类时会去掉方法名的首字母大写。Pig和Cow既不是ComVisible,我也看不到它们的任何Java类。难道这就是缺少的东西吗?@JanHruby:它们不应该是
ComVisible
,也不应该是。它们实现了一个
ComVisible
接口,并由
ComVisible
方法返回,该方法足以使它们可访问。正如我在一篇关于答案的评论中所说的,如果我通过集合而不是数组导出相同的对象,它就会起作用。