2009-07-07 9 views
160

編集:私は結果をblog postとして書いています。C#コンパイラはどのようにCOMタイプを検出しますか?


C#コンパイラは、COMの種類をやや魔法のように扱います。例えば、この文は正常に見える...

Word.Application app = new Word.Application(); 

...あなたはApplicationインターフェイスであることを認識するまで。インターフェイス上でコンストラクタを呼び出すYoiks!これは実際にType.GetTypeFromCLSID()へのコールに変換され、もう1つはActivator.CreateInstanceへのコールに変換されます。

また、C#4で、あなたはrefのパラメータの非参照引数を使用することができ、コンパイラは結果だけを破棄、参照によって渡すためにローカル変数を追加します。

// FileName parameter is *really* a ref parameter 
app.ActiveDocument.SaveAs(FileName: "test.doc"); 

(うん、あります私はコンパイラの動作を調べようとしています。私は最初の部分を偽造することに失敗しています。

Dummy dummy = new Dummy(); 

をしかし:私は書くことができるようにしたいと思い

using System; 
using System.Runtime.InteropServices; 
using System.Runtime.CompilerServices; 

[ComImport, GuidAttribute("00-0000-0000-0000-000000000011")] 
public interface Dummy 
{ 
    void Foo(ref int x); 
} 

class Test 
{ 
    static void Main() 
    { 
     Dummy dummy = null; 
     dummy.Foo(10); 
    } 
} 

:私は問題なしとの第二の部分を行うことができます。明らかに、それは実行時に強打するだろうが、それは大丈夫です。私はただ実験しているだけです。

リンクされたCOM PIA(CompilerGeneratedおよびTypeIdentifier)用にコンパイラによって追加された他の属性は、トリックを実行していないようです...マジックソースは何ですか?

+0

あなたは私にこのようなもの(ほとんどのもの)を先取りしていますが、clairificationのためには、より正規化された構文の依存性注入機能が正しいと思います。 –

+11

オプションパラメータはいいですか? IMO、いいえ、彼らは素敵じゃない。 Microsoftは、C#にbloatを追加することで、Office COMインターフェイスの欠陥を修正しようとしている。 –

+0

良い質問(+1)。私はインターフェイス上でコンストラクタを呼び出すことについて同じことに気付きました。何が起きているかに精通していない開発者を本当に混乱させるので、コードでは恐ろしいように見えます。私はいつもそれが働くようにシーンの裏に何が起こっているのか疑問に思っていました。あなたの新しい本を買うように見えます;-) –

答えて

138

私はこれについて専門家ではありませんが、あなたが望むと思うものについては、最近、つまずきました:CoClass属性クラス。一つ以上の インターフェースの

[System.Runtime.InteropServices.CoClass(typeof(Test))] 
public interface Dummy { } 

コクラス用品コンクリート 実装(S)。 COMでは、このような具体的な の実装は、COM コンポーネントの開発をサポートする任意の プログラミング言語で記述することができます。など

デルファイ、 C++、Visual Basicの、あなたはインターフェイスSpVoice(本当に、あなたはSPVoiceClassをインスタンス化している)、 "インスタンス化" することができるしているmy answer to a similar question about the Microsoft Speech APIを参照してください。

[CoClass(typeof(SpVoiceClass))] 
public interface SpVoice : ISpeechVoice, _ISpeechVoiceEvents_Event { } 
+2

非常に面白いです - 後で試してみましょう。リンクされたPIAタイプにはCoClassがありません。たぶんそれはリンクプロセスと関係があります - 私は元のPIAを見ていきます... –

+64

Eric LippertとJon Skeetも答えたときに受け入れられた答えを書いて素晴らしいのです。 CoClassに言及するために。 – OregonGhost

60

あなたとマイケルの間で、あなたはほとんど一緒にまとめることができました。私はこれがどのように動作するのかと思います。 (私はコードを書きませんでしたので、少し誤っているかもしれませんが、これがどうなるかはかなり確信しています。)

場合:あなたは「新しい」インターフェイスタイプをINGの、そして

  • されているインタフェースの種類が知られているコクラスを持ち、かつ
    • あなたはこのために、「ノーPIA」機能を使用しています
    次いで

    コード(IPIAINTERFACE)Activator.CreateInstance(COCLASSTYPE OF Type.GetTypeFromClsid(GUID))として生成されるインタフェース

  • 場合:

    • あなたは「新しい」インターフェイスタイプをINGの、そして
    • されているインタフェースの種類が知られているコクラスを持っている、とあなたは、このインターフェイス
    • のために「ノーPIA」機能を使用していない

    「新しいCOCLASSTYPE()」と同じようにコードが生成されます。

    Jonさん、このようなことについて質問がある場合は、私をバグしてもSamさんに直接お問い合わせください。 FYI、Samはこの機能の専門家です。

    35

    これはマイケルの答えにちょっとした肉体を付けることです(彼が望むのであればそれを追加することができます。この場合は削除します)。

    [ComImport, TypeLibType(...), Guid("..."), DefaultMember("Name")] 
    public interface _Application 
    { 
        ... 
    } 
    
    [ComImport, Guid("..."), CoClass(typeof(ApplicationClass))] 
    public interface Application : _Application 
    { 
    } 
    
    [ComImport, ClassInterface(...), ComSourceInterfaces("..."), Guid("..."), 
    TypeLibType((short) 2), DefaultMember("Name")] 
    public class ApplicationClass : _Application, Application 
    { 
    } 
    

    エリックリペットはanother answerに語る理由のための2つのインターフェイスがあります。Word.ApplicationのためのオリジナルPIAを見ると

    は、(イベントを無視して)関係する3つのタイプがあります。あなたが言ったように、CoClassは、クラスそのものとApplicationインターフェイスの属性の両方の観点からです。

    C#4でPIAリンクを使用した場合、の一部は結果のバイナリに埋め込まれますが、すべてではありません。 がちょうどApplicationのインスタンスを作成するアプリケーションは、これらのタイプで終わる:

    [ComImport, TypeIdentifier, Guid("..."), CompilerGenerated] 
    public interface _Application 
    
    [ComImport, Guid("..."), CompilerGenerated, TypeIdentifier] 
    public interface Application : _Application 
    

    ませんApplicationClass - それは実行時にリアル COMタイプから動的にロードされると思われるので。

    もう1つ興味深いのは、リンクされたバージョンとリンクされていないバージョンの間のコードの違いです。で、それはそう

    Application application = (Application) 
        Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("..."))); 
    

    として、それが終わるバージョンをリンクし、一方、

    Application application = new ApplicationClass(); 
    

    :あなたが行に参照バージョンで

    Word.Application application = new Word.Application(); 
    

    を逆コンパイルした場合には、として終わります"実際の" PIAのように見えるCoClass属性が必要ですが、リンクされたバージョンはないので、ではないCoClassコンパイラが実際に参照できる。動的に行う必要があります。私はこの情報を使って偽のCOMインターフェイスに試してみて、私はマイケルの答えに確認のビットを追加する...

    26

    それをリンクするためのコンパイラを得ることができるかどうか表示される場合があります

    コードは以下はコンパイルし、実行:

    public class Program 
    { 
        public class Foo : IFoo 
        { 
        } 
    
        [Guid("00000000-0000-0000-0000-000000000000")] 
        [CoClass(typeof(Foo))] 
        [ComImport] 
        public interface IFoo 
        { 
        } 
    
        static void Main(string[] args) 
        { 
         IFoo foo = new IFoo(); 
        } 
    } 
    

    それを動作させるためにあなたはComImportAttributeGuidAttributeの両方が必要です。

    また、new IFoo()の上にマウスを置いたときの情報に注意してください。Intellisenseは情報を正しくピックアップします。Nice!

    +0

    ありがとう、私は試していたが、私は** ComImport **の属性が不足していたが、私は私がソースコードに行くとき私はF12を使用して作業していた** CoClass **と** Guid **、 –

    関連する問題