トップ «前の日記(2011-06-22) 最新 次の日記(2011-06-28)» 編集

日々の破片

Subscribe with livedoor Reader
著作一覧

2011-06-23

_ 今更ながらCOMインターロップ

ちょっとした、でもC++とかで書くのは面倒だしVBはあり得ないようなプログラムをC#で書いたのは良いが、それをVB6から使いたいという要望を受ける。

そういうときこそのCOM Interopですよ、とやったこたないけど(逆は普通にあるが)、やってみた。

ら、そこらで見つかる情報(MSDN含む)が、嘘ばかりでどえらく苦労したのでメモしておく。

もしかしたら、公開当時は嘘ではなく、.NET Framework 3.5以降で嘘になったのかも知れないけど。

まず、最初に、TypeLibIdは、最初からassemblyInfo.csに含まれている(vs2010の場合)。したがって何も考えなくとも良い(追記:はというのは調べているのにその上を見ていない罠。ツッコミ欄参照)。

次に、public classはデフォルトでは、TypeLibに移出されない。ここが「相互運用のための .NET 型の要件」がおかしいところだ。

パブリック型のメンバーも、COM から参照できるようにする場合には、パブリックである必要があります。 アセンブリ、パブリック型、またはパブリック型のパブリック メンバーの参照可能範囲を制限するには、ComVisibleAttribute を適用します。 既定では、すべてのパブリック型およびメンバーが参照可能です。

コミュニティコンテンツだから修正できるのだが、問題はこの記述が正で、実装がバグの可能性があることなのだ(ので、修正しない)。原文もvisibleなのがdefaultとなっている。

結局、上記のページを信じれば、特に何もしなくても(public 無引数コンストラクタがあり、型互換のpublicメソッドなどが定義されているpublicクラスであれば)、Tlbexpを実行すればそれだけでCOMクライアントから呼べるように読める。

が、それは間違いで、明示的にComVisibleAttribute(true)を設定しなければならない。以下のように(interfaceを定義するのは自然の理)。

[Guid("000000-D7D0-4087-B7C2-B060B994BC57")] // IID
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
public interface FooBar
{
    [ComVisible(true)]
    string Hello(string whoareyou);
}
 
[Guid("000000-D7D0-4087-B7C2-B060B994BC59")] // CLSID
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class FooBarImpl : FooBar
{
    public string Hello(string whoareyou)
    {
         if (string.IsNullOrEmpty(whoareyou)) 
             throw new InteropException("who are you ?", 0x80004003);
         return "hello " + whoareyou;
    }
}
class InteropException : Expcetion
{
    internal InteropException(string msg, uint hr)
        : base(msg)
    {
        HResult = checked((int)hr);  // HResultはuintにしとけよな(ぷんぷん)
    }
}

ComVisible(true)しないと、空のtlbが生成されるだけだ。

ちょっと、一部うろ覚えの箇所あり。

本日のツッコミ(全11件) [ツッコミを入れる]
_ yfakariya (2011-06-24 01:48)

AssemblyInfo.cs に [assembly:ComVisible(false)] が残っているというオチがあったりは……(手元でコメントアウトしたところ、tlb に入りました)

_ arton (2011-06-24 01:53)

え、そんなところに……(なるほど。明日確認してみますが、ありそうな話ですね。ありがとうございます)

_ arton (2011-06-24 01:56)

いや、でも仮にそうだとしても(そうだと思うけど、COM相互作用のページ全体に及んで、そんなこと一言も書いてないんだから、やはりおかしいよね。VS20?の既定のプロジェクトではAssemblyInfo.csで無効化していますとか、書いておくべきじゃん:というわけで、確認したら書いておくかも)

_ arton (2011-06-24 02:15)

コミュニティコンテンツに書き込んだが、行末が$0に置き換わるのはなぜだろう? (面倒だから放置)

_ yfakariya (2011-06-24 02:17)

確かに何か一言書いてあるべきですよね。

_ ishisaka (2011-06-24 11:46)

VSのプロジェクトのプロパティ→アセンブリ情報でアセンブルをCOM参照可能にするにチェックが無いだけだったりして。。。まあ後細かく調製したいときとか、COMカテゴリ使おうなんてなるとやっぱり属性は書かなくっちゃ行けない。というかお手軽サンプル以外はみたいな話かもです。あと、TelbExpだけでいけました?Regasm無しで。。。

_ なかむら(う) (2011-06-24 12:10)

チェックがないだけだったりして、に+1。<br>いやまあ、それがAssemblyInfo.csの件の1行になるんですけどね。<br>プロジェクトのプロパティの方がMS的な推奨本道だと思います。

_ arton (2011-06-24 12:50)

あれを設定するとregasmが動いて権限違反でビルドが失敗するから当然オフです。いずれにしてもVB6<br>環境は別だから開発環境に登録されても意味ないし。(AssemblyInfoの属性に反映されるのかなと思ったけど、そういうこともなかった)

_ arton (2011-06-24 13:05)

うさんのツッコミだとAssemblyInfoに反映されるとなってるけど保存しても変わらないけどなぁ。ビルド成功すると保存されるのかな? でもそれだと意味ないなぁ。

_ arai (2011-07-02 13:27)

えーっと、この話はAssemblyInfoでComVisible属性がfalseに設定されているために起きることだったのでは、なかったですかね。<br>アセンブリのComVisible属性がfalseになっていますから、公開するものを明示的にtrueに設定する必要があっただけかと思います。

_ arton (2011-07-02 17:44)

そうです、どうもありがとうございます。で、それとプロジェクトのプロパティの連動ってどうなっているのかなというのと、Vista以降(Serverでは当然だけど)のユーザー権限でHKCRには書けないのが絡んで来てややこしいということです。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|

ジェズイットを見習え