2

C# コードの一部を、COM を介してあらゆる種類の実装と対話させる必要があります。

この統合をユーザーが簡単に行えるようにするために、相互作用するインターフェイスを IDL に (関連する既存の DLL の一部として、ただしコクラスや実装は含めずに) 含め、Tlbimp を実行して型定義を作成することで C# コードに組み込みました。

C# を実装し、Windows レジストリ情報に基づいて COM オブジェクトを作成し、そのオブジェクトを必要なインターフェイスにキャストしました。

次に、別のプロジェクトでインターフェイスの C# 実装を作成し、登録しました。メイン プログラムはテスト COM オブジェクトを正しく作成しますが、インターフェイスへのキャストに失敗します (C# 'as' を使用すると null オブジェクトを取得し、明示的なキャストの InvalidCastException を取得します)。

インターフェイスがテストオブジェクトによって実装されていると識別されない理由を誰かが示唆できますか?

これは IDL のインターフェイス定義です (VS 2005 で C++ でコンパイル):

    [
    object,
    uuid(B60C546F-EE91-48a2-A352-CFC36E613CB7),
    dual,
    nonextensible,
    helpstring("IScriptGenerator Interface"),
    pointer_default(unique)
]
interface IScriptGenerator : IDispatch{

    [helpstring("Init the Script generator")] 
        HRESULT Init();
    [helpstring("General purpose error reporting")] 
        HRESULT GetLastError([out] BSTR *Error);
};

これは、Tlbimp によって C# 用に作成されたスタブです。

[TypeLibType(4288)]
[Guid("B60C546F-EE91-48A2-A352-CFC36E613CB7")]
  public interface IScriptGenerator
  {
    [DispId(1610743813)]
    void GetLastError(out string Error);
    [DispId(1610743808)]
    void Init();
  }

これはメインの C# コードの一部であり、その ProgID によって COM オブジェクトを作成し、それを IScriptGenerator インターフェイスにキャストします。

public ScriptGenerator(string GUID)
{
  Type comType = Type.GetTypeFromProgID(GUID);
  object comObj = null;
  if (comType != null)
  {
    try
    {
      comObj = Activator.CreateInstance(comType);
    }
    catch (Exception ex)
    {
      Debug.Fail("Cannot create the script generator COM object due to the following exception: " + ex, ex.Message + "\n" + ex.StackTrace);
      throw ex;
    }
  }
  else
    throw new ArgumentException("The GUID does not match a registetred COM object", "GUID");

  m_internalGenerator = comObj as IScriptGenerator;
  if (m_internalGenerator == null)
  {
    Debug.Fail("The script generator doesn't support the required interface - IScriptGenerator");
    throw new InvalidCastException("The script generator with the GUID " + GUID + " doesn't support the required interface - IScriptGenerator");
  }

}

これは C# コードの実装で、機能していることをテストします (実際には機能していません)。

  [Guid("EB46E31F-0961-4179-8A56-3895DDF2884E"),
  ProgId("ScriptGeneratorExample.ScriptGenerator"),
  ClassInterface(ClassInterfaceType.None),
  ComSourceInterfaces(typeof(SOAAPIOLELib.IScriptGeneratorCallback))]
  public class ScriptGenerator : IScriptGenerator
  {
   public void GetLastError(out string Error)
    {
      throw new NotImplementedException();
    }
    public void Init()
    {
      // nothing to do
    }
  }
4

2 に答える 2

2

繰り返しますが、提案に感謝します。

私は最終的に自分で問題を解決することができました。上記の提案を試しましたが、何の進展もありませんでした。次に、「テスト」コードの相互運用機能の名前空間を変更しました。Tlbimp を使用するときの引数の使用が異なるため、メイン コードの名前空間とは異なります。これで問題は解決しました。

理由についての私の推測は次のとおりです。.Net は COM オブジェクトを作成しますが、これが実際には .Net オブジェクトであることを検出すると、COM レイヤーをバイパスして直接通信します。その場合、queryInterface (インターフェイス GUID を使用) は使用されず、C# 名前空間が異なるため、インターフェイスは異なります。

これは、.Net コードとの統合をサポートするために、元の相互運用アセンブリを IDL とは別に公開する必要があることを意味します。

ありがとう、インバー

于 2008-11-11T23:52:51.700 に答える
0

インターフェイスでこれが必要だと思います

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
于 2008-11-11T22:14:12.977 に答える