Как вернуть массив объектов (реализацию COM-интерфейса) из метода С# в метод Java через COM4J?
Пример класса С#, который генерирует массив:
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(VARIANT)*
вместоSAFEARRAY(IUnknown*)*
(это вызывает то же исключение.) - Удаление атрибута
MarshalAs
(tlbimp
не удается создать прокси-метод)
Есть ли способ маршалировать массив, чтобы COM4J мог преобразовать его в допустимый массив Java?
В качестве альтернативы существует способ выделения массива в Java и использование метода .NET для его заполнения? (Я пробовал это, но метод .NET получает копию массива, а код Java никогда не видит объекты, вставленные в копию. Может быть, есть способ переопределить это?)
Изменить. Это может быть связано: qaru.site/info/273916/... - похожее похожее на VBScript