0

COM タイプ ライブラリ (ComLib)、C# ツール クラスライブラリ (ComTools)、および COM タイプ ライブラリのテストベッドとして使用されるメイン C# プロジェクト (ComMaster) で構成される ac# プロジェクトがあります。

下部のコードを参照してください。

ComMaster から COM オブジェクトを呼び出すと (com オブジェクトとしてではなく、「通常の」C# オブジェクトとして)、すべて正常に動作します。ComLib から ComTools への呼び出しが機能し、ComTools は ComLib にある TypeConverter を見つけます。DoIt 関数は、次のような素敵なメッセージ ボックスをポップアップ表示します。

Original: Hello
Converted: Hello

を使用して com lib を公開しRegAsm ComLib.dll /codebase /tlb:ComLib.tlbます。

私の問題は次のとおりです。 たとえば、Excel-Vba から COM オブジェクトを呼び出すと、regasm で生成された typelib に参照を設定し、次のコードを作成します。

Sub TestComLib()
    Dim c As New ComLib.ComLib
    c.DoIt "My Test String"
End Sub

というランタイム エラーが表示されます"InvalidCastException: 'System.String' can't be converted into 'ComLib.MyClass'"。明らかに、これは(T)(object)aStringTypConverter が文字列を MyClass に変換できない場合に呼び出される ComTools.ToolFunc の厄介なものから来ています。

さて、私の質問は次 のとおりです。ComTools で ComLib への参照を設定せずに、MyClass にアタッチされた TypeConverter を ComTools アセンブリに渡すにはどうすればよいですか (編集: これにより循環参照が発生します!)。

同じように見える次の問題を見つけました (ただし、回答はありません): TypeConverter from VB6

編集:型コンバーターを宣言する MyClass の属性をより明示的にしようとしました: [System.ComponentModel.TypeConverter("ComLib.MyClassConverter, ComLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")]。しかし、それは役に立ちません:-(


編集:解決策

Simon Mourier のおかげで、ComLib クラスに次のコードを追加しました。

static ComLib()
{//static constructor, gets called before anything in here gets executed
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
        if (args.Name == Assembly.GetAssembly(typeof(ComLib)).FullName)
            return Assembly.GetAssembly(typeof(ComLib));
        return null;
    };
}


サンプル コード:
ComLib (インターフェイスを明示的に公開する C# クラス ライブラリとして作成されたプロジェクト):

namespace ComLib
{
    [ComVisible(true), Guid("abcdef00-23aa-46d0-8ba8-c7548fa4d820")]//faked GUID
    [InterfaceType(ComInterfaceType.InterfaceIsDual)]
    public interface IComLib
    {
        void DoIt(string aMsg);
    }

    [ComVisible(true), Guid("abcdef01-23aa-46d0-8ba8-c7548fa4d820")]//faked GUID
    [ProgId("ComLib.ComLib")]
    [ClassInterface(ClassInterfaceType.None)]
    public class ComLib : IComLib
    {
        public void DoIt(string aMsg)
        { 
            try {
                MyClass c = new MyClass();
                //call tool func in ComTools
                c = ComTools.ComTools.ToolFunc<MyClass>(aMsg);
                MessageBox.Show("Original: " + aMsg + "\n" + c.Text);
            }
            catch (Exception e) {
                MessageBox.Show("Error: " + e.ToString());
            }
        }
    }

    [System.ComponentModel.TypeConverter(typeof(MyClassConverter))]
    public class MyClass
    {//dummy class wrapping a string
        public string Text {get; set; }
    }

    public class MyClassConverter : System.ComponentModel.TypeConverter
    {//converter for MyClass allowing conversions from string
        public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, Type sourceType)
        { return sourceType == typeof(string); }

        public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            var s = value as string;
            if (s != null)
                return new MyClass() {Text = "Converted: " + s};
            return base.ConvertFrom(context, culture, value);
        }
    }
}

ComLib プロジェクトは、次のコードを含むComToolsプロジェクトを参照します。

namespace ComTools
{
    public class ComTools
    {
        public static T ToolFunc<T>(string aString)
        {//create an object of the given T type converting it from goiven string value
            System.ComponentModel.TypeConverter typeConverter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
            if (typeConverter.CanConvertFrom(typeof(string)))
            {//called from com, the correct type converter is not found
                return (T) typeConverter.ConvertFrom(aString);//convert using the typeconverter found
            }
            else
            {//last resort: try a cast
               // ******* this throws an error when called from COM,
               // ******* because the correct type converter is not found
               return (T)(object)aString;//will not let me cast directly to T
            }
        }
    }
}

ComMaster プロジェクトはComLibプロジェクトのみを参照し、次のコードを含みます。

static void Main()
    {
        ComLib.ComLib lib = new ComLib.ComLib();//create an instance of the lib
        lib.DoIt("Hello");//call the exposed function
    }
4

1 に答える 1