19

オブジェクトの配列 (COM インターフェイスを実装) を C# メソッドから COM4J 経由で 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(VARIANT)*代わりにマーシャリングSAFEARRAY(IUnknown*)*
    (これは同じ例外をスローします。)
  • MarshalAs属性の削除(tlbimpプロキシ メソッドの作成に失敗します)

COM4J が有効な Java 配列に変換できるように配列をマーシャリングする方法はありますか?

または、Java で配列を割り当てて、.NET メソッドで配列を設定できるようにする方法はありますか? (私はこれを試しましたが、.NET メソッドは配列のコピーを受け取り、Java コードはコピーに挿入されたオブジェクトを認識しません。これをオーバーライドする方法はあるのでしょうか?)


編集:これは関連している可能性があります:https ://stackoverflow.com/a/6340144/12048 - VBScriptから同様のことが可能であるようです

4

1 に答える 1

1

インターフェイスを InterfaceIsDual および/または InterfaceIsIDispatch として宣言しようとしましたか?

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

ほとんどの COM 相互運用ライブラリには、ディスパッチ インターフェイスが必要です。ただし、COM4J についてはわかりません。同じ目的を達成するために、インターフェイスではなく抽象基本 COM クラスを使用することもできますが、上記の変更でうまくいかない場合は驚くでしょう。

于 2012-12-20T20:20:56.227 に答える