夕暮ログ

C#やJavascript、最近はAndroidなんかも好きなtinqのブログ。「夕暮れログ」

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ShellClass shell = new ShellClass();がコンパイルエラーになるので調べてみた

追記有 2013/3/16

C#でCOMのShell系の機能をを利用するさいにMicrosoft Shell Controls And AutomationをCOM参照に追加し、
ShellClass shell = new ShelClass();

のようにしてShellClassのインスタンスを作っていろいろとやるサンプルをよく見かけます。
また、自分もXP/VisualStudio2008でそうやっていました。
しかし、Windows7/VisualStudio2010に乗り換えたところ、ビルドが通らなくなりました。
XPの仮想マシンでVS2010を入れてみたところ、やはりビルドが通らなかったのでVisual Studio2010からかわったのかなーとおもいます。

たとえばこんなエラーです。
エラー 1 相互運用型 'Shell32.ShellClass' を埋め込むことができません。代わりに適用可能なインターフェイスを使用してください。
エラー 2 型 'Shell32.ShellClass' のコンストラクターが定義されていません。
エラー 3 相互運用型 'Shell32.ShellClass' を埋め込むことができません。代わりに適用可能なインターフェイスを使用してください。

エラー一覧


自分はCOMに詳しくなくてこまりながらいろいろやっていたところ、どうやらShellというのが全く同じように使えるようです。
Shell shell = new Shell();

これでめでたしです。
しかし、VisualStudio2008とは違うコードになっており、本当にほかのOSで動くか不安だったので、もうすこし調べてみました。 右クリックから定義へ移動してみると、ShellClassはこのShellを継承しているクラスでした。
Shellの定義も見てみると、

[Guid("866738B9-6CF2-4DE8-8767-F794EBE74F4E")]
[CoClass(typeof(ShellClass))]
public interface Shell : IShellDispatch5
{
}

となっていて、Shellはインターフェースになっていることがわかります。インターフェースの先頭はIを付けるというマナーが守れていませんね。
・・・ではなく、インターフェースなのにnewでインスタンス化しています。
インターフェースは抽象的なものであり、それを実装したクラスしかインスタンス化できない、というのが常識のはずです。
ではなぜでこんなことになっているのでしょうか?怪しいのは属性です。
Guidは違いそうなので、怪しいのはCoClass属性。しかも、ShellClassを指定してます。

ということで、さらに調べてみました。

まずMSDNですが説明する気はあまりない模様です。自分で使うもんじゃないよ。と書いてあります。
CoClassAttribute クラス
ということで、Google先生へ。
やっぱりありました!先人のみなさま、ありがとうございますm(__)m
コクラス - まめしば雑記
COM クライアント実装の道程 for TaskScheduler その4 [はてなブックマークで表示 - ぬるり。
What does the C# CoClass attribute do? - stackoverflow

どうやら、「具体的な実装はCOMにされています。」ということを表しており、実際にコンパイルするとCOMのインスタンスを作成するコードに置き換えられるようです。
普通に書くとながったらしくなるコクラスのインスタンス化処理を手短に書く、ということらしいです。
(こういうのをシンタックスシュガーといえばいいのかな?)


インターフェースなのにIから始まっていないのにも、普通のインターフェースとは異なる使い方をするからだと思います。きっと。

ということで、ILSpyで逆コンパイルしてみました。

private void Form1_Load(object sender, EventArgs e)
{
Shell shell = new Shell();
}

private void Form1_Load(object sender, EventArgs e)
{
Shell arg_19_0 = (Shell)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("13709620-C279-11CE-A49E-444553540000")));
}

最適化でまるごと消えるかと思いましたが、のこってました。
もちろんローカル変数名などは変わってしまっていますが、Actiavator.CreateInstanceでGUIDをもとにインスタンスを作成するようになっています。
これなら安心して使うことができそうです。

追記(2013/3/6)


コメントでそのままのコードで使う方法を教えていただきました。ありがとうございます!!
そのままコピペさせていただきます。

(1)C#の右側に縦書きになっている、ソリューションエクスプローラーの文字を押し続ける。
(2)ソリューションエクスプローラーの画面が現れるので、参照設定の中身を表示します。
(3)Shell32を右ボタンで押すと、メニューが現れ「プロパティー」選択します。
(4)プロパティー画面が現れますので、「相互運用機能型の埋め込み」が、Trueになっていると思います、
  これをFalseにしてください。


ここをFalseに。

どうやら、VisualStudio2010/.NET Framework4.0からCOMに必要なデータを完全にexe内に埋め込むことが可能になったようです。この「相互運用機能型の埋め込み」をFalseにすると、以前のようにInterop.Shell32.dllというファイルが同じフォルダに作成されるようになります。
埋め込みがTrueの場合はチュートリアル: Microsoft Office アセンブリからの型情報の埋め込み (C# および Visual Basic)によりますと、異なるバージョンでも対応が可能になるとか。
これが有効で元のコードが使えなくなる理由はよくわからないです・・・
関連記事

コメント

ここをクリックしてコメントを投稿

非公開コメント

トラックバック

http://tinqwill.blog59.fc2.com/tb.php/83-f4f37086

« next  ホーム  prev »

プロフィール

tinq tinq(もしくはTinqWill)

Sky  For   Every 改装予定

プログラミングお勉強中の高校生。月一くらいは更新したい

最新記事

カテゴリ

月別アーカイブ

検索フォーム

最新コメント

リンク

最新トラックバック

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。