简体   繁体   English

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

[英]Return array of interface from a .NET method via COM4J

How can I return an array of objects (implementing a COM interface) from a C# method to a Java method via COM4J? 如何通过COM4J从C#方法返回一个对象数组(实现COM接口)到Java方法?

Example C# class that generates an array: 示例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";
        }
    }
}

The interface declaration in the resulting .tlb looks like this: 生成的.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 client code: 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();
            }
        }
    }
}

This compiles but I get this exception at runtime: 这编译但我在运行时得到这个异常:

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)

Other things I have tried: 我试过的其他事情:

  • Marshalling as a SAFEARRAY(VARIANT)* instead of SAFEARRAY(IUnknown*)* 编组为SAFEARRAY(VARIANT)*而不是SAFEARRAY(IUnknown*)*
    (this throws the same exception.) (这引发了同样的异常。)
  • Removing the MarshalAs attribute ( tlbimp fails to create the proxy method) 删除MarshalAs属性( tlbimp无法创建代理方法)

Is there a way to marshal the array so that COM4J can convert it to a valid Java array? 有没有办法编组数组,以便COM4J可以将其转换为有效的Java数组?

Alternatively is there a way to allocate an array in Java and allow the .NET method to populate it? 或者有没有办法在Java中分配一个数组并允许.NET方法填充它? (I tried this but the .NET method receives a copy of the array and the Java code never sees the objects inserted into the copy. Maybe there's a way to override this?) (我试过这个,但.NET方法接收到数组的副本,Java代码永远不会看到插入到副本中的对象。也许有办法覆盖它?)


Edit : This may be related: https://stackoverflow.com/a/6340144/12048 - something similar appears to be possible from VBScript 编辑 :这可能是相关的: https//stackoverflow.com/a/6340144/12048 - 类似的东西似乎可以从VBScript

Have you tried declaring your interfaces as InterfaceIsDual and/or InterfaceIsIDispatch? 您是否尝试将接口声明为InterfaceIsDual和/或InterfaceIsIDispatch?

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

Most COM interop libraries require a dispatch interface; 大多数COM互操作库需要一个调度接口; however, I'm not sure about COM4J. 但是,我不确定COM4J。 You could also use an abstract base COM class rather than an interface to achieve the same goal, but I'd be surprised if the above change doesn't get you up and running. 您也可以使用抽象基类COM类而不是接口来实现相同的目标,但如果上述更改无法启动并运行,我会感到惊讶。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM