returns remarks net c# java com com-interop com4j

c# - remarks - Devuelva la matriz de la interfaz desde un método.NET a través de COM4J



remarks c# documentation (1)

¿Cómo puedo devolver una matriz de objetos (implementar una interfaz COM) de un método C # a un método Java a través de COM4J?

Ejemplo de clase C # que genera una matriz:

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"; } } }

La declaración de la interfaz en el .tlb resultante se ve así:

[ 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); };

Código de cliente 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(); } } } }

Esto compila pero obtengo esta excepción en tiempo de ejecución:

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)

Otras cosas que he probado:

  • Se SAFEARRAY(VARIANT)* como SAFEARRAY(VARIANT)* lugar de SAFEARRAY(IUnknown*)*
    (Esto lanza la misma excepción.)
  • Eliminando el atributo MarshalAs ( tlbimp falla al crear el método proxy)

¿Hay alguna manera de calcular la matriz para que COM4J pueda convertirla en una matriz Java válida?

Alternativamente, ¿hay una manera de asignar una matriz en Java y permitir que el método .NET lo complete? (Intenté esto, pero el método .NET recibe una copia de la matriz y el código Java nunca ve los objetos insertados en la copia. ¿Tal vez haya una manera de anular esto?)

Edición : Esto puede estar relacionado con: https://stackoverflow.com/a/6340144/12048 - parece ser posible algo similar desde VBScript


¿Ha intentado declarar sus interfaces como InterfaceIsDual y / o InterfaceIsIDispatch?

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

La mayoría de las bibliotecas de interoperabilidad COM requieren una interfaz de envío; Sin embargo, no estoy seguro acerca de COM4J. También puede utilizar una clase COM base abstracta en lugar de una interfaz para lograr el mismo objetivo, pero me sorprendería si el cambio anterior no lo pone en marcha.